Compare commits

...

530 Commits

Author SHA1 Message Date
1c4a33eb78 Bump version to 3.0.0.2
Update NEWS
2011-04-06 18:46:49 -04:00
b7513097ea extensionSystem: add missing import
https://bugzilla.gnome.org/show_bug.cgi?id=646333
2011-04-06 18:45:00 -04:00
a35677a9bf Updated Finnish translation. 2011-04-06 12:56:06 +03:00
89de3a81c6 Bump version to 3.0.0.1
Update NEWS
2011-04-05 16:09:51 -04:00
b9828bf5de StScrollbar: clean up properly when unmapped during scroll
If we're unmapped (or destroyed) during a scroll, we want to clean
up the changes we've made to Clutter's event handling, remove our
signal handler, and emit ::scroll-stop.

https://bugzilla.gnome.org/show_bug.cgi?id=646825
2011-04-05 12:10:13 -04:00
d6c3868a7c Bump version to 3.0.0 2011-04-04 17:29:04 -04:00
a73f02ac23 Add NEWS file with 3.0 contributors 2011-04-04 17:23:58 -04:00
7e9594456b Require and build against Mutter 3.0 2011-04-04 17:21:16 -04:00
d25418ba04 popup-sub-menu: Adjust scrollbar style
Slightly adjust the style, so that scrollbars in submenus look
slightly less disconnected from the scrolled content.

https://bugzilla.gnome.org/show_bug.cgi?id=646001
2011-04-04 15:54:26 -04:00
a7df1a3d77 popup-menu: Tweak submenu style
Tone down the background color and use an inset shadow to give the
subsection some depth.

Expander menu item is always highlighted when open.

https://bugzilla.gnome.org/show_bug.cgi?id=646001
2011-04-04 15:53:12 -04:00
50951d15ea popupMenu: make submenus scrollable if needed
Right now, the network menu will overflow the screen if More...
is selected with many access points. As a short-term workaround
for this, add a scrollbar for submenus of panel dropdown menus
if they would cause the toplevel menu to overflow the screen.

- Put the actors in a PopupSubMenu in a StScrollView so we get
  a scrollbar if the allocated space is smaller than the height
  of the menu. Expand animation is turned off in the scrolled case
  to avoid weirdness.
- When we pop up a panel menu, set a max-height style property
  on the panel menu to limit it to the height of the screen.
- Hack event handling while the scrollbar is dragged to make
  the scrollbar work properly.

https://bugzilla.gnome.org/show_bug.cgi?id=646001
2011-04-04 15:46:46 -04:00
30076884ae Updated Latvian translation. 2011-04-04 19:57:01 +03:00
1eff22a90b Updated Japanese translation 2011-04-04 23:17:08 +09:00
41bdbc203d Updated Traditional Chinese translation(Hong Kong and Taiwan) 2011-04-04 22:08:33 +08:00
7932585656 network: fix alignment of secure vs insecure wireless icons
Since the icon area is end-aligned, the signal strength icon for
insecure networks was ending up aligned with the lock icon for secure
networks. Fix that by always including a _secureIcon, but having it be
blank for the insecure networks.

https://bugzilla.gnome.org/show_bug.cgi?id=646121
2011-04-04 09:30:53 -04:00
68bf4e7b70 Updated Japanese translation 2011-04-04 22:28:24 +09:00
92f09a60f6 Add shell_get_file_contents_utf8_sync(), use it instead of gio temporarily
Adding correct annotations to Gio.File.load_contents revealed that gjs
doesn't actually support array+length combinations.  For 3.0 this would
be invasive to fix, so add a method to ShellGlobal which does what
we need.

https://bugzilla.gnome.org/show_bug.cgi?id=646333
2011-04-04 09:08:33 -04:00
d19f2bb6d2 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2011-04-04 20:55:10 +08:00
b06dce5bf8 Updated Japanese translation 2011-04-04 21:31:01 +09:00
82e2ab89c5 Fix expand animation for submenus
Figuring out the size of an unmapped actor is not completely
reliable because styles aren't fully assigned until an actor
is mapped. So show the submenu before computing the size we
want to tween to.

https://bugzilla.gnome.org/show_bug.cgi?id=645949
2011-04-04 08:23:37 -04:00
db198b183c New Bengali translation 2011-04-04 16:37:51 +06:00
90bab650e2 Update Czech translation 2011-04-04 04:19:53 +02:00
fa1cc556f9 Updated Dutch translation by Wouter Bolsterlee 2011-04-04 01:12:51 +02:00
69b23b0e48 [l10n]Fixes on Catalan translation 2011-04-03 23:19:44 +02:00
af69945e5b end-session-dialog: Show default icon if user icon is unset
If the user has not configured a user icon, the logout dialog will
display an empty rectangle. Show a default picture instead.

https://bugzilla.gnome.org/show_bug.cgi?id=646032
2011-04-03 22:48:37 +02:00
f36f7644c8 [l10n] Updated German translation, umlauts fixed 2011-04-03 21:08:58 +02:00
20f1457d15 NetworkStatus: ignore invalid and unsupported connection types
Some connection types (like wimax) are not supported by the menu, and
should be ignored instead of throwing exceptions. Also, NetworkManager
had a bug that sent connections with invalid settings. This should not
happen, but in case it does, we will not blow up, but just log a warning
and continue silently.

https://bugzilla.gnome.org/show_bug.cgi?id=646355
2011-04-03 14:24:58 +02:00
38bcd52065 NetworkMenu: keep the connection list visible when connecting...
When a device is connecting, we can continue showing available
connections and access points, as well as the active one with the dot.
(Hiding was a remnant of when the device status was on a different
menu item than the title)

https://bugzilla.gnome.org/show_bug.cgi?id=646381
2011-04-03 14:22:27 +02:00
38219fec99 Updated Italian translation 2011-04-03 10:35:14 +02:00
6c3300bc2f network: fix logic bug in checking whether to activate or deactive
A cosmetic change recommended in review of the patch to fix the
VPN Connections switch ended up introducing a logic error that
made the switch not work properly. Fix.

https://bugzilla.gnome.org/show_bug.cgi?id=646380
2011-04-02 21:58:45 -04:00
d1a110d4ca NetworkMenu: fix VPN connection state
It was always reporting true, even if disconnected. At the same time,
add a signal that is emitted when state changes and update the UI
accordingly.
In the future (with another libnm-glib API break) we should use the
NMVPNConnection object to track the connection state, so that we can
show if we're connecting or we need authentication.

https://bugzilla.gnome.org/show_bug.cgi?id=646380
2011-04-02 20:40:12 +02:00
5b61485143 NetworkMenu: fix parameters to _findConnection
NMDevice._findConnection expects an uuid as parameter, but
checkConnection was passing a NMConnection object. This caused
exists to be always false, thus the connection was added again every
time the 'updated' signal was emitted.

https://bugzilla.gnome.org/show_bug.cgi?id=645702
2011-04-02 20:35:46 +02:00
6b95a357eb gnome-shell.css: fix multiple calendar layout issues
Specifying absolute pixel widths for fields breaks under both font
scaling and translation.

Change all px lengths in the calendar to corresponding pt values, to
fix the layout under larger/smaller font sizes.

Change all "width" specifications to "min-width", for languages with
longer translations. This completely breaks the layout if any field
exceeds the min-width of its column, but that is preferable to
ellipsizing. Needs to be redone using St.Table or the like for 3.0.1.

Also add padding to the right of the calendar popup to match the
padding on the left, since the lack of it becomes more obvious in
layouts where the actual width exceeds the minimum width.

https://bugzilla.gnome.org/show_bug.cgi?id=645693
2011-04-02 07:31:55 -04:00
60bdc726ce Updated Korean translation 2011-04-02 19:58:17 +09:00
429f809b71 search-display: Fix getDragActorSource()/getDragActor()
The 'icon' property in search results' meta info has been replaced
by a 'createIcon' property, adjust to this change.

https://bugzilla.gnome.org/show_bug.cgi?id=645990
2011-04-02 11:13:45 +02:00
9396d736f2 notificationDaemon: only ignore 'chat' and 'presence' notifications from Empathy (#645932) 2011-04-02 00:05:10 +02:00
cc9b812466 Updated Lithuanian translation. 2011-04-01 22:30:15 +02:00
5b0f2dc0cf [jhbuild] Clutter moved to git.gnome.org
Use this new git repository.
2011-04-01 17:21:52 +02:00
7ffea1606d [jhbuild] Build libxklavier 5.1 from tarball
We had to get it from CVS waiting for 5.1 to be released,
but now we can use the same tarball as the GNOME moduleset.

Stop installing CVS since libxklavier was the only module using it.

https://bugzilla.gnome.org/show_bug.cgi?id=646416
2011-04-01 15:38:30 +02:00
342bc1e72d [jhbuild] glib-networking depends on gsettings-desktop-schemas
This missing dependency is only noticeable when you remove the
whole $prefix and build everything from scratch, since schemas
are already present in existing installs.

https://bugzilla.gnome.org/show_bug.cgi?id=646416
2011-04-01 15:38:30 +02:00
0127eb5892 Updated Gujarati Translations 2011-04-01 17:23:55 +05:30
39023269d6 Updated Hungarian translation 2011-04-01 13:44:58 +02:00
35e3cd97fe hindi updated 2011-04-01 14:52:29 +05:30
a63a171ec3 Updated Norwegian bokmål translation 2011-04-01 09:45:14 +02:00
7f1763f32f Updated Basque language 2011-04-01 09:43:36 +02:00
2d6326815c Added Basque language 2011-04-01 09:27:53 +02:00
ee4c8cca8c Updated Tamil translation 2011-04-01 12:17:10 +05:30
2104e0f411 build: Add gconf dependency to libgweather 2011-03-31 20:04:33 +02:00
84e69f57ea Updated Serbian translation 2011-03-31 11:07:58 +02:00
aba43125f3 [l10n] Updated Estonian translation 2011-03-31 09:37:56 +03:00
de5fc58fcb Updated Danish translation 2011-03-30 22:40:47 +02:00
4831dde3fb Updated translation for Afrikaans (af) 2011-03-30 19:10:32 +02:00
b5cbfc5e7a Updated British English translation 2011-03-30 14:56:02 +01:00
1124d164ec Updated Japanese translation. 2011-03-30 21:49:55 +09:00
9d9391bd95 Updated Portuguese translation 2011-03-29 23:53:24 +01:00
0121d74b92 Update translation for Afrikaans (af) 2011-03-29 23:41:13 +02:00
f81af32963 Update Simplified Chinese translation. 2011-03-30 00:38:46 +08:00
8f5198821e Bump version to 2.91.93 2011-03-28 23:19:36 -04:00
96c2b5ef32 MessageTray: don't forward click on sources with notifications
When a source has an associated tray icon, we would forward all clicks
to the X11 window, meaning that the summary notification could not
be opened. Instead, restore normal event flow for clicks, when the
source has notifications in the queue.

https://bugzilla.gnome.org/show_bug.cgi?id=645753
2011-03-28 23:05:56 -04:00
c5eb324cf0 Fix problem with app menu showing when leaving overview
Since the opacity of the application menu is controlled by
it's _targetIsCurrent flag, we need to respect that when entering
and leaving the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=645734
2011-03-28 23:05:55 -04:00
f117d9bfd3 telepathyClient: give a separate style to TpLogger messages
Sometimes, log messages are hard to differentiate from normal,
unread recent messages, so give a separate style to messages
retrieved from the TelepathyLogger service.

https://bugzilla.gnome.org/show_bug.cgi?id=645609
2011-03-28 23:05:55 -04:00
b470736246 telepathyClient: Do a better job with old chat timestamps
If we have a date that's not within the last week, it's really
confusing to display it as "Sent at 9:23 on Tuesday". Steal
some strings from calendar.js for displaying older dates to
avoid a string-freeze break.

https://bugzilla.gnome.org/show_bug.cgi?id=645609
2011-03-28 23:05:55 -04:00
b2a2a00cd8 telepathyClient: insert a timestamp between log messages and pending messages
This will give a visual break, giving a bit of clarity when a message
is received from a new contact.

https://bugzilla.gnome.org/show_bug.cgi?id=645609
2011-03-28 23:05:55 -04:00
659130856c Hide summary box pointer without animating if it is empty
This ensures that we don't show a small black blob fading away
when the user clicks on the notification and it is removed.

Set HIDING state right away in _hideSummaryBoxPointer() so that
it is only called once. Update this._pointerInTray when the tray
is unlocked, so that we are not dependent on escapeTray() being
triggered by 'done-displaying-content' signal.

https://bugzilla.gnome.org/show_bug.cgi?id=645697
2011-03-28 22:40:38 -04:00
9a21008177 Make sure notification has all the content when it is expanded
Use Meta.later_add() with BEFORE_REDRAW rather than Mainloop.idle_add()
to add the banner body so that the notification body is reliably added
after the first frame is drawn. This is important for notifications that
are expanded right away, such as the summary notifications that
were not shown as banners because the user was in the Busy mode or was
interacting with the summary. Otherwise, these notifications were sometimes
shown with an ellipsized banner and were only getting full content when
they were done animating.

Only add expanded content and signal the change once. Previously, we
used to signal the change numerous times and processing this signal was
holding up processing other things, such as the user moving the mouse
away from the notification so that the notification collapses.

https://bugzilla.gnome.org/show_bug.cgi?id=645719
2011-03-28 22:40:17 -04:00
8f58bc5b19 [l10n]Updated Catalan translation 2011-03-29 00:29:34 +02:00
3a0220a875 Updated Danish translation 2011-03-28 23:40:46 +02:00
9f438d0ec6 Panel: sync primary hotcorner hover with Activities button
Since the hotcorner is a reactive actor, and it is over the Activities
button, hovering on it results in a leave-event for the button.
This is not noticeable when opening the overview, as the button is
correctly prelighted, but it is when closing, if you keep the mouse
near the hot corner, as the button is kept in normal state, despite
the mouse being over it.

https://bugzilla.gnome.org/show_bug.cgi?id=645751
2011-03-28 22:15:04 +02:00
22c22e0d7a boxPointer: Use the anchor point to fix problems with allocations
Instead of setting the x/y position of the box pointer, which results
in a long change of workarounds for limitations of the Clutter
layout system, set the anchor point instead, which takes the
positioning out of the layout system.

The position is computed as a combination of the position computed
from the allocation and the box pointer's size, and an offset that
we tween when animating showing and hiding the box pointer.

https://bugzilla.gnome.org/show_bug.cgi?id=645744
2011-03-28 15:27:10 -04:00
bc48bd5f4a boxPointer: use shell_util_get_transformed_allocation()
Using ClutterActor.get_transformed_size() can produce bugs if we
happen to position the box pointer when the source actor has a
relayout queued. Use our newly added reliable utility function
instead.

https://bugzilla.gnome.org/show_bug.cgi?id=645744
2011-03-28 15:27:10 -04:00
905c4bb4a5 Add shell_util_get_transformed_allocation()
Add a function that gets the current allocation of an actor
transformed into stage coordinates. This avoids a misfeature of
clutter_actor_get_transformed_size() where when a size request is
queued (even if it won't eventually change the size), the returned
value is the transformed size request rather than the last allocation.

https://bugzilla.gnome.org/show_bug.cgi?id=645744
2011-03-28 15:27:10 -04:00
94bfaf6896 Updated Polish translation 2011-03-28 20:22:07 +02:00
25b743b03c message-tray: Fix dismissing notifications
Commit 31b12635d1 fixed links in notifications again, but blocked
clicks on normal labels getting through to the notification. Fix
this, so that both links and dismissing notifications work again.

https://bugzilla.gnome.org/show_bug.cgi?id=645839
2011-03-28 19:46:11 +02:00
8da4e6ce5e Updated Indonesian translation 2011-03-28 23:16:23 +07:00
cedd297ba6 hindi added and translated and lingua upodated 2011-03-28 14:18:59 +05:30
b6e0c5e0ea Added mr to LINGUAS
Added Marathi Translations
2011-03-28 10:56:54 +05:30
bf3f7d0dc4 Update Simplified Chinese translation. 2011-03-28 12:53:51 +08:00
7b42a84422 Updated Latvian translation. 2011-03-28 01:10:16 +03:00
8b7c065706 Updated Brazilian Portuguese translation. 2011-03-27 17:45:38 -04:00
c6a4b3d9b0 Updated French translation 2011-03-27 20:46:53 +02:00
0ef32f2b8d Updated Galician translations 2011-03-27 20:33:17 +02:00
f7fdcb7bf1 Added UG translation 2011-03-27 19:56:53 +02:00
848d36ff39 Uploaded Ukranian 2011-03-27 18:27:33 +03:00
07ce3e7cdf [l10n] Updated German translation 2011-03-27 16:42:46 +02:00
cfec145ae2 Use the description for GNOME shell instead of Mutter 2011-03-27 15:55:37 +02:00
641d7a4ea4 polkit: Add translator comment
Add a translator comment for the "Sorry, that didn't work. Please try
again." string, as suggested by several people; this should help
translators what "that" refers to.
2011-03-27 10:41:54 +05:30
da0650fda6 Updated Bulgarian translation 2011-03-27 08:03:48 +03:00
6724133927 update tranlation for Punjabi by A S Alam 2011-03-27 10:03:13 +05:30
c0ded8ef5f Updated Russian translation 2011-03-26 23:41:48 +03:00
7382de51dc Updated Dutch translation by Wouter Bolsterlee 2011-03-26 20:43:15 +01:00
96a1121e6b Update Simplified Chinese translation. 2011-03-27 03:39:01 +08:00
323bbb0692 Updated Slovenian translation 2011-03-26 20:31:54 +01:00
59e235623a Updated Arabic translation 2011-03-26 17:30:39 +02:00
40dc85d975 Add description to DOAP file 2011-03-26 13:24:44 +01:00
6006a42cbb Update Simplified Chinese translation. 2011-03-26 19:08:04 +08:00
c2e0278bd9 Updated Vietnamese translation 2011-03-26 13:58:45 +07:00
c1ba920c86 BluetoothStatus: depend more on libgnome-bluetooth-applet
Ensure that a dependency is generated even when using --as-needed,
by adding a fake function that calls into the library.

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

Was accidentally removed, as part of the switch to building
a gnome-shell binary, reapplying the original patch. - Owen

https://bugzilla.gnome.org/show_bug.cgi?id=645596
2011-03-25 21:39:22 -04:00
7b997e9374 statusIconDispatcher: fix trailing comma
Fix a trailing comma in object initializer introduced in
the last patch.
2011-03-25 21:24:42 -04:00
dfb97c1ed7 statusIconDispatcher: add ibus-ui-gtk to standard implementations
As a stop-gap measure until we have a native input method tray icon,
add ibus-ui-gtk to STANDARD_TRAY_ICON_IMPLEMENTATIONS so that the IBus
status icon shows up in the status area rather than in the message
tray. The message tray location doesn't work for the function of
showing the current input method when switching between windows or
changing input methods.

https://bugzilla.gnome.org/show_bug.cgi?id=641531
2011-03-25 21:20:36 -04:00
fc49fb2f4f Improve checks for XFixes pointer barriers
Instead of checking on version (which doesn't work when protocol
and libraries are out of sync), just check for the functions we
need.

https://bugzilla.gnome.org/show_bug.cgi?id=645630
2011-03-25 21:13:57 -04:00
63078fba5b NetworkStatus: Adapt to nm_client_activate_connection api change
It now takes a connection directly instead of the object path associated
with a connection.
2011-03-25 20:38:55 -04:00
b0176546c2 NetworkStatus: fix vpn indicator
It looks like a part of the code wasn't updated to reflect
a variable name change.
2011-03-25 20:37:29 -04:00
a234ba91a4 Updated Hebrew translation. 2011-03-26 00:56:07 +02:00
526d11809f network: add security icons to WEP/WPA wireless networks
https://bugzilla.gnome.org/show_bug.cgi?id=645647
2011-03-25 18:55:40 -04:00
3bbdecc6b3 popupMenu: round spacing to an integer
StThemeNode.get_length() doesn't necessarily return an integer pixel
value, and our code produces non-integer positions in that case. So
round the spacing.

https://bugzilla.gnome.org/show_bug.cgi?id=645647
2011-03-25 18:55:40 -04:00
00fc4a2eb7 gnome-shell.css: fix padding/alignment of menu toggle switches
We do not support scaling background-images, so setting the
toggle-switch size to anything other than the natural size of the
image just results in it getting padding, which makes it look
improperly aligned.

https://bugzilla.gnome.org/show_bug.cgi?id=645647
2011-03-25 18:55:06 -04:00
924b31233b popupMenu: fix relayout after submenu open/close
Because of the GtkSizeGroup-like trickiness we're doing with
PopupMenuItems, we need to force Clutter to discard its cached size
requests for them any time the menu itself changes size.

https://bugzilla.gnome.org/show_bug.cgi?id=645647
2011-03-25 18:55:06 -04:00
475161f716 boxpointer: reposition after a size change
If the BoxPointer changes size (eg, when opening the "More" section of
the network menu), reposition it to make sure it's still aligned
correctly and still completely on-screen.

This is not the right fix for this problem (and causes the menu to be
drawn in the wrong position for one frame). The right fix would
involve a ClutterConstraint, but that would be more invasive, and can
happen post-3.0.0.

https://bugzilla.gnome.org/show_bug.cgi?id=645647
2011-03-25 18:55:06 -04:00
31b12635d1 messageTray: fix clicking on links again
The change to make Notification an StButton (06d2c0af, bug 642978)
broke links, because the link actor would ignore the
button-press-event, allowing the notification actor to receive it and
get a pointer grab, and so the link actor would never see the
button-release-event. Fix that by accepting and discarding the
button-press-event.

https://bugzilla.gnome.org/show_bug.cgi?id=645613
2011-03-25 18:49:27 -04:00
d2de0865bf telepathyClient: fix duplicate copy of first message in a chat
The chat-history-fill-in code had logic to avoid appending two
messages when a message appeared in both the log and the pending
messages. But it wasn't working because of an incorrect object field
name.

Additionally, the code was previously keeping the copy of the message
from the log, and suppressing the copy from pending. But that meant
that once the previous bug was fixed, it would think it had only shown
old messages, and so it would create a source but not notify it. So
fix it to suppress the log message and show the pending message.

https://bugzilla.gnome.org/show_bug.cgi?id=645612
2011-03-25 18:47:01 -04:00
9b4dbd0e83 Updated Swedish translation 2011-03-25 22:15:24 +01:00
4577cd7497 Updated Spanish translation 2011-03-25 21:36:39 +01:00
4ebf07c725 NetworkStatus: hide the only connection for wired devices
For wired devices (actually, ethernet devices), hide the connection
list when there is only one connection (either automatic or stored).
The device can be operated with the associated switch.
2011-03-25 20:58:37 +01:00
da852a94bd NetworkStatus: show "firmware missing" when firmware is not available
Since device state Unavailable is generic and has substates, instead
of using an hack for carrier, introduce some code that checks both
for carrier and firmware-missing when in that device state, and updates
the UI accordingly.
2011-03-25 20:58:37 +01:00
9b51ff7241 Updated Spanish translation 2011-03-25 19:11:59 +01:00
aa0137e7ce Use /org/gnome as starting path for schemas 2011-03-25 12:53:03 -04:00
3889ae7627 Updated Brazilian Portuguese translation 2011-03-25 11:54:56 -03:00
c97a8602a1 ShellAppSystem: Only search gnomecc.menu for preferences
settings.menu was removed in gnome-menus commit
b68bcd27f44ce2c494f6e3cd9695890b9c02af04; gnomecc.menu is the intended
replacement.

(On Red Hat Linux derived systems, settings.menu continues to exist)

https://bugzilla.gnome.org/show_bug.cgi?id=645063
2011-03-25 10:35:38 -04:00
affc9f9058 Updated Korean translation 2011-03-25 21:57:01 +09:00
1582819259 update tranlation for Punjabi by A S Alam 2011-03-25 08:17:30 +05:30
05e8ae33dc Uploaded Ukranian 2011-03-25 00:19:36 +02:00
219d5fb66b Updated Swedish translation 2011-03-24 23:04:46 +01:00
92ff57c0ea Updated Swedish translation 2011-03-24 23:04:46 +01:00
5233429b6f Updated Italian translation 2011-03-24 22:58:22 +01:00
475cf7179e Add gettext macro to message to enable translation. 2011-03-25 02:16:10 +08:00
f608c65962 Updated Vietnamese translation 2011-03-25 00:31:36 +07:00
6cf0a35b4c po/vi.po: import from damned lies 2011-03-25 00:21:48 +07:00
bac006ebc1 Updated French translation 2011-03-24 13:56:49 +01:00
be5f74e37f Updated French Translation
Contributed by :
Cyril Arnaud, Frédéric Peters, Bruno Brouard
2011-03-24 13:54:58 +01:00
5c29bff23d Updated Galician translations 2011-03-24 09:51:53 +01:00
68968d2b40 Update Simplified Chinese translation. 2011-03-24 16:09:59 +08:00
038f4e8bde Updated Norwegian bokmål translation 2011-03-24 09:03:20 +01:00
f8874fec0f Add file to POTFILES.in 2011-03-24 09:03:19 +01:00
ee6693e6e3 Don't translate empty string 2011-03-24 09:03:19 +01:00
bfba97647e Mark strings for translation in the right way 2011-03-24 09:03:19 +01:00
82d5194afe Updated Swedish translation 2011-03-24 08:04:06 +01:00
bf449b9f61 Updated Italian translation 2011-03-24 01:13:58 +01:00
9530048867 NotificationDaemon: fix typo in dealing with TrayIcon
Source was failing to determine if it was a tray icon, destroying
itself when the associated application was closed.

https://bugzilla.gnome.org/show_bug.cgi?id=645625
2011-03-23 22:58:28 +01:00
090d54516e main: Allow replacement of org.gnome.Shell name
This was an oversight in the previous commit; if we don't
do this, then we just can't --replace.

https://bugzilla.gnome.org/show_bug.cgi?id=645593
2011-03-23 17:23:47 -04:00
c91b716a63 main: Use --replace semantics for org.gnome.Shell DBus name
Previously (because I suck) we were ignoring the return value of
RequestName, and so we'd totally ignore the fact that we failed
to acquire the DBus name.

Make this consistent by using meta_get_replace_current_wm() and
if we're in --replace, actually replace immediately.

https://bugzilla.gnome.org/show_bug.cgi?id=645593
2011-03-23 16:13:51 -04:00
80cdb0dc4e Updated Spanish translation 2011-03-23 20:36:13 +01:00
aaa6b54673 Updated Spanish translation 2011-03-23 18:49:19 +01:00
a3b61ec8c8 Complete Simplified Chinese translation. 2011-03-23 23:58:48 +08:00
6c41d6b66a Updated Bengali India Translation 2011-03-23 20:58:20 +05:30
1838ab1412 Uploaded Ukranian 2011-03-23 16:10:44 +02:00
72e8d38586 Update Simplified Chinese translation. 2011-03-23 21:39:20 +08:00
9259e2221d Added Bengali India file, translation to start 2011-03-23 12:36:36 +05:30
42ea979b06 Added Bengali India to the list of languages 2011-03-23 12:35:13 +05:30
46824adb97 Added Bengali India file, translation to start 2011-03-23 12:35:00 +05:30
3758f4952e Bump version to 2.91.92 2011-03-22 18:52:39 -04:00
8fdbbe78f4 MessageTray: keep notification focused through update()
If a notification was updated while one of its widgets was focused,
it would lose the grab when that widget was destroyed. Fix that by
moving the focus to a safe place before destroying the old widgets.

https://bugzilla.gnome.org/show_bug.cgi?id=643687
2011-03-22 18:20:33 -04:00
5a86b0f9e3 MessageTray: never show summary and a new notification at the same time
We want to minimize focus stealing from the user. If a non-urgent notification
comes in while the user is interacting with the tray, we add it to the tray
and only show it after the user is done interacting with the tray. If an
urgent notification comes in while the user is interacting with the tray,
we hide the tray and show the urgent notification.

https://bugzilla.gnome.org/show_bug.cgi?id=636838
2011-03-22 18:18:11 -04:00
604722b775 MessageTray: use single scrollbar for summary notification stacks
We want to allow the user to scroll through all notifications from
source by using a single scrollbar. We suppress the individual
scrollbars inside the notifications.

As one exception, we keep the original scrollbar for chat notifications
because it has a distinct look, ending above the text entry box.

https://bugzilla.gnome.org/show_bug.cgi?id=611611
2011-03-22 18:18:11 -04:00
812812d817 MessageTray: show multiple notifications per source
Add an ability to show multple notifications per source, so that
the user doesn't miss seeing any notifications.

https://bugzilla.gnome.org/show_bug.cgi?id=611611
2011-03-22 18:18:11 -04:00
f07fe0a8e7 Updated Slovenian translation 2011-03-22 22:05:03 +01:00
1d7cef5bfe workspace-thumbnails: Add a subtle border to indicator
As windows' content tends to use mostly light colors/white, the
thumbnail indicator is hard to spot for workspaces with maximized
windows on it. To improve its visibility in these cases, add a
subtle dark border in addition to the white outline.
2011-03-22 21:38:56 +01:00
34b12e6a6a Updated Galician translations 2011-03-22 21:18:27 +01:00
eb6ba563bd Updated Spanish translation 2011-03-22 20:58:02 +01:00
281b2e9b0e St: Fix blur radius computation to correspond to current CSS draft
The next draft of the CSS Backgrounds and Borders module will actually
define when the blur radius means. Fix our code to use that definition
(2 * standard deviation) rather than using the 1.9 * that we extracted
from what Mozilla was doing.

https://bugzilla.gnome.org/show_bug.cgi?id=632506
2011-03-22 15:53:49 -04:00
5437629e89 Updated Spanish translation 2011-03-22 20:33:20 +01:00
e1df2f8ff5 Updated Arabic translation 2011-03-22 20:59:20 +02:00
12fad6f05f Fix ripple animation for RTL locales
The animation was invisible because it was going out of screen, also
add a mirrored version of the image to the theme.

https://bugzilla.gnome.org/show_bug.cgi?id=584662
2011-03-22 19:35:21 +01:00
4208078750 st-texture-cache: Fix stretched images
Some functions in StTextureCache enforce square ClutterTextures,
even in cases where the underlying CoglTexture has a different
width:height ratio.
Add padding in those cases to keep the resulting image from being
stretched.

https://bugzilla.gnome.org/show_bug.cgi?id=643866
2011-03-22 19:35:21 +01:00
dba02f8f08 endSessionDialog: make shutdown dialog work like latest mock ups
This commit adds a restart button to the shutdown dialog and changes
the terminology from Shut Down to Power Off.  This brings things in
line with the latest mockups here:

http://live.gnome.org/GnomeShell/Design/Whiteboards/SystemStopRestart

https://bugzilla.gnome.org/show_bug.cgi?id=641375
2011-03-22 14:22:55 -04:00
35e410fe96 endSessionDialog: clean up appearance
This commit lines up the app list with the description,
adds spacing between controls of the dialog, and increases
the wrap width of the text.

https://bugzilla.gnome.org/show_bug.cgi?id=641375
2011-03-22 14:22:55 -04:00
7dcd2313d8 endSessionDialog: hide app list when there are no apps
We don't want its padding to show up when it shouldn't
be visible.

https://bugzilla.gnome.org/show_bug.cgi?id=641375
2011-03-22 14:22:55 -04:00
40750f2dc6 Updated Russian translation 2011-03-22 21:18:55 +03:00
85c007431b endSessionDialog: emit Closed signal when dialog disappears
The session manager needs to keep its internal state for the
dialog in sync with ours.

https://bugzilla.gnome.org/show_bug.cgi?id=645485
2011-03-22 14:15:00 -04:00
cbd187369e PopupMenu: invert the menu when in RTL locales
Change the way menu items allocate their contents to take text
direction into account, so they're fully reversed in RTL locales,
and St.Align.START / END are respected.

https://bugzilla.gnome.org/show_bug.cgi?id=645524
2011-03-22 18:26:18 +01:00
d20d89a0b9 endSessionDialog: prelight inhibiting app items
This commit makes it more obvious that apps in the end session
dialog inhibitors list are clickable.  It does this by rendering
the text for the apps in a low intensity white under normal
conditions, but a high intesnity white on hover.

https://bugzilla.gnome.org/show_bug.cgi?id=645491
2011-03-22 13:04:41 -04:00
80eb37ef60 Constrain tooltips to monitors
Use st_tooltip_set_constrain_func() to set a function that constrains
tooltips to be on the same monitor as the original tip area.

https://bugzilla.gnome.org/show_bug.cgi?id=645547
2011-03-22 12:38:26 -04:00
d19cdc206b StTooltip: Add the ability to set a hook to constrain the tooltip
If, for example, the stage is divided into multiple monitors, we
might want to constrain tooltips so they don't cross monitor boundaries.
Add a function to set a per-stage callback to constrain tooltips.

https://bugzilla.gnome.org/show_bug.cgi?id=645547
2011-03-22 12:38:26 -04:00
02078255ea appDisplay: show hover and tooltip while the menu is up
While we have menu for an app icon open, we want to show the prelight
for the item instead of removing the prelight when the user mouses
away from the item and into the menu, and if there's a tooltip
(like for the dash), we want to show the tooltip immediately when
the menu is popped up.

https://bugzilla.gnome.org/show_bug.cgi?id=642871
2011-03-22 12:38:25 -04:00
bea2d40f79 popupMenu: Add the ability to block sending events to the source actor
It can be useful to avoid sending enter/leave events to the source actor
of a menu: this would be the case when the source actor isn't a menu item
that should participate in menu navigation but rather is some object
(like an app icon) that we want to indicate corresponds to the menu.

https://bugzilla.gnome.org/show_bug.cgi?id=642871
2011-03-22 12:38:25 -04:00
a5d3259cfe StTooltip: use a timeout like GtkTooltip
Instead of showing tooltips immediately on hover, wait until a timeout
after the last motion (timeout is given by the gtk-tooltip-timeout
GtkSetting.)

https://bugzilla.gnome.org/show_bug.cgi?id=642871
2011-03-22 12:38:25 -04:00
4a93ce703e dash: Show tooltips on hover
As dash items no longer show application names, display names as
tooltips on hover.

https://bugzilla.gnome.org/show_bug.cgi?id=642871
2011-03-22 12:37:14 -04:00
661ea906d9 css: Adjust tooltip style
Update the tooltip style to match current mockups.

https://bugzilla.gnome.org/show_bug.cgi?id=642871
2011-03-22 12:37:14 -04:00
b382b4cb94 build: Bump vala to 0.11.7 to fix dep. on dconf 2011-03-22 11:07:00 -05:00
087e86fb32 StTooltip: fix various warnings and use Clutter API correctly
Use ClutterContainer functions for adding the tooltip instead of
calling clutter_actor_set_parent behind the stage's back, and do
it inside st_widget_show_tooltip (which is a normal method) instead
of overriding st_tooltip_show, which is a vfunc and it is called
internally by Clutter, therefore it is limited in what it can safely
do.
Also, instead of positioning the tooltip with clutter_actor_set_position,
modify the anchor point when the associated widget moves, so that
only a redraw is queued.

https://bugzilla.gnome.org/show_bug.cgi?id=635100
2011-03-22 16:13:38 +01:00
afffa76c17 Make St aware of the UI group.
Inside the Shell, all the UI (including chrome, the overview, and
the actual windows) is not a child of the stage but of a special
ClutterGroup, which is cloned inside the magnifier.
Add function for setting this special actor so that actors added by
St are visible in the magnifier. Nothing yet uses this, but the
tooltip will soon.

https://bugzilla.gnome.org/show_bug.cgi?id=635100
2011-03-22 16:09:23 +01:00
69ca18f36b Updated Arabic translation 2011-03-22 15:04:15 +02:00
f84c62f0be Fix overview sizing when exiting via thumbnails
We need to update WorkspacesView._ZoomOut before calling
_updateWorkspacesGeometry() in show(), as otherwise the old
value is kept. This was a problem if we previously left the
overview zoomed out.
2011-03-22 12:50:14 +01:00
90c554ad42 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2011-03-22 19:43:17 +08:00
e2cb6cc4da st-texture-cache: Request large thumbnails
As of commit 34ce17c4b3, search results use large icons, or thumbnails
when available. To keep the amount of upscaling for the latter as small
as possible, request a large thumbnail size.

https://bugzilla.gnome.org/show_bug.cgi?id=645493
2011-03-22 11:42:07 +01:00
02da366cc2 [l10n] Updated Estonian translation 2011-03-22 10:25:46 +02:00
54e3a54489 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
2011-03-21 22:42:25 -04:00
8798ec653d NotificationDaemon: don't notify for resident notifications when application is focused
The applications have to have a way of keeping resident notifications
updated without unnecessarily notifying the user with the information
the user is already seeing in the application window.

https://bugzilla.gnome.org/show_bug.cgi?id=630847
2011-03-21 21:58:29 -04:00
d1ffd3cf35 MessageTray: style summary sources
Make summary sources look more clickable and highlight them when selected.
Highlighting the fully expanded summary source when selected matches the
highlighting in the top bar items and teaches the user that any part of the
expanded summary source can be clicked.

Based on the initial patches by Florian Müllner and Jonathan Strander.

https://bugzilla.gnome.org/show_bug.cgi?id=644788
2011-03-21 21:50:27 -04:00
133b854f1b modalDialog: constrain container to the size of the stage
The lightbox will be sized to the size of its parent container,
so we need to make the parent container reliably the size of the
stage, instead of letting it be auto-sized to the size of its contents.

https://bugzilla.gnome.org/show_bug.cgi?id=644889
2011-03-21 21:18:37 -04:00
33125e78c8 Alt-F2: Avoid running programs multiple times
Returning true from the event handler seems to avoid getting
duplicate return events; these duplicate events likely are
getting generated by IBus.

https://bugzilla.gnome.org/show_bug.cgi?id=644509
2011-03-21 20:50:08 -04:00
4118bf1a5e Updated Italian translation 2011-03-22 01:36:58 +01:00
8282db456b Use the new meta_window_move_to_monitor function
https://bugzilla.gnome.org/show_bug.cgi?id=645032
2011-03-22 00:58:56 +01:00
7b5eacf671 Updated Galician translations 2011-03-22 00:53:01 +01:00
12bd374477 searchDisplay: don't create useless SearchResult's
average constructing time for 1 SearchResult is 3 ms.
It give > 400 result on query like 'a' (on my machine).
https://bugzilla.gnome.org/show_bug.cgi?id=645313
2011-03-22 02:50:32 +03:00
9ef4cc0ab9 iconGrid: remove unused variable in _computeLayout
https://bugzilla.gnome.org/show_bug.cgi?id=645313
2011-03-22 02:50:25 +03:00
528fc9bc47 XDND: Allow workspace switching using the thumbnails
Currently activating a window on a different workspace requires very
long drag distances, which is very inconvenient to use.

Fix that by allowing switching workspaces using the thumbnails which is
consistent with window and launcher dnd and much easier to use.

https://bugzilla.gnome.org/show_bug.cgi?id=643945
2011-03-22 00:05:17 +01:00
c58b8498b3 st: Add more error checking to shadow-related code
The additional error checks should catch quite some warnings (e.g.
when trying to create a shadow for a 0-width actor).
2011-03-21 23:25:42 +01:00
c81c564941 overview: Don't pick for every overlay
Don't do an individual hover fixup for every window overlay, instead
just use the new global.sync_hover() to fix up hovers once we have
finished showing the overview.

Based on a patch from Adel Gadllah <adel.gadllah@gmail.com>

https://bugzilla.gnome.org/show_bug.cgi?id=638613
2011-03-21 17:45:51 -04:00
b16de0e374 Fix workspaces accumulating on each restart.
Main._nWorkspacesChanged was racing with Main._checkWorkspaces.
If _checkWorkspaces won the race, _workspaces was uninitialized.
Because of this, _checkWorkspaces only noticed workspaces
with windows on them, leading it to believe the last workspace wasn't
empty, and added a new, empty workspace.

https://bugzilla.gnome.org/show_bug.cgi?id=645343
2011-03-21 17:45:00 -04:00
d38f41a459 dnd: If needed, destroy _dragActor in _cancelDrag
In the case where the original actor is destroyed, we don't
show a snap back animation, so we need to destroy drag actor
as we would do in _onAnimationComplete.

https://bugzilla.gnome.org/show_bug.cgi?id=640781
2011-03-21 17:39:42 -04:00
30346884fe Update terminology from "panel" to "top bar" when Ctrl+Alt+Tab is pressed.
This is the term recommended for use by the Documentation Team.
2011-03-21 17:17:27 -04:00
1518dc9b60 Add pointer barriers to panel and message tray
If you have XFixes 5 (and corresponding xserver support) then we
add barriers on the panel and in the message tray corner so that
its easy to reach the corners even when there are monitors to the
sides of the primary monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=622655
2011-03-21 21:03:19 +01:00
fd3f2289c3 gnome-shell.desktop: Set autorestart flag
This is the last ditch 3.0 plan for error handling.
See https://bugzilla.gnome.org/show_bug.cgi?id=645251

https://bugzilla.gnome.org/show_bug.cgi?id=645451
2011-03-21 15:57:49 -04:00
22bfd4f7c3 notificationDaemon: handle trayicon clicks in the overview
If the user clicks a trayicon in the overview, drop out of the
overview before passing the click on to the icon. (We have to actually
wait for the overview animation to complete, in case the icon wants to
get a pointer grab, which it would not be able to do with the overview
active.)

https://bugzilla.gnome.org/show_bug.cgi?id=641853
2011-03-21 14:58:10 -04:00
2782011ce8 shell-global: try to resync the pointer state after grabs
If the pointer moves on or off the stage while another process has a
grab, we will lose track of it. One example of this is that if you use
a popup menu from a message tray trayicon, the tray will stay up after
the menu goes away, because the shell never saw the pointer leave it.

Add a new method shell_global_sync_pointer() that causes clutter to
recheck what actor is under the pointer and generate leave/enter
events if appropriate.

Of course, we can't actually tell for sure when another process has a
grab, so we need a heuristic of when to call this. Currently we call
it from Chrome._windowsRestacked(), which is not really the right
thing at all, but does fix the menu-from-trayicon case...

https://bugzilla.gnome.org/show_bug.cgi?id=630842
2011-03-21 14:56:53 -04:00
7f17fcfafc messageTray: forward clicks on trayicon SummaryItems to the icon
If the user clicks on the title of a trayicon's SummaryItem, forward
that click to the trayicon. Also adjust
gnome_shell_plugin_xevent_filter() so that if the trayicon takes a
grab as a result of this, we don't hide the message tray.

https://bugzilla.gnome.org/show_bug.cgi?id=630842
2011-03-21 14:56:53 -04:00
a40daa3c22 runDialog: popModal before running the command
If you run a command from Alt+F2 that tries to get a server grab (eg,
xmag), it will fail if it starts up before the run dialog is finished
hiding.

Additionally, the run dialog currently stays focused while it is
fading out, potentially stealing keystrokes (or causing the user to
accidentally launch two copies of a program).

Change ModalDialog.close() to call popModal() immediately

Add a ModalDialog.popModal method, and call that before running the
RunDialog command. If the command succeeds, close the dialog as
before. If it fails, call ModalDialog.pushModal() to put things back
to normal before displaying the error.

https://bugzilla.gnome.org/show_bug.cgi?id=644857
2011-03-21 14:26:08 -04:00
1e366aa56e altTab: popModal before fading out
This lets the user start typing in the newly-selected window right
away, without any characters possibly getting eaten during the
animation.

https://bugzilla.gnome.org/show_bug.cgi?id=644857
2011-03-21 14:26:08 -04:00
bad8dbc2d2 modalDialog: grab focus immediately, not after fade-in
If the user types Alt+F2 and then immediately starts typing, some keys
can get lost. Fix that by grabbing focus sooner.

https://bugzilla.gnome.org/show_bug.cgi?id=644857
2011-03-21 14:26:08 -04:00
d0dd37fe94 appDisplay: use get_allocation_box() in _ensureIconVisible
When right-clicking on an AppWellIcon, the icon will become focused,
which (presumably via style-changed) invalidates its current
allocation, causing "icon.y" to return 0 until it has been
reallocated, messing up our idea of where in the AppDisplay the icon
is. Work around this by calling get_allocation_box() instead.

https://bugzilla.gnome.org/show_bug.cgi?id=645162
2011-03-21 14:26:07 -04:00
b2df3fcd1d Always show the workspace thumbnails if there is a monitor to the right
If there is a monitor to the right it is very easy to overshot the
expanding thumbnails and enter the next monitor. So, in that case
we just always show it.

https://bugzilla.gnome.org/show_bug.cgi?id=641877
2011-03-21 18:48:57 +01:00
96f89ce4ae message-tray: allocate the entire size to the icon
Specify x-fill and y-fill true for the bin that contains the status
icon so the status icon will always be sized to our specified icon
size (24x24). This prevents pathological behavior for legacy status
icons embedded in the tray where an initial allocation at 1x1 before
they had content would "stick", and the icon would permanently
end up 1x1.

https://bugzilla.gnome.org/show_bug.cgi?id=634820
2011-03-21 11:17:29 -04:00
e886a3d891 StButton: fix handling of Space/Enter -> click
StButton was mistakenly considering any Space/Enter KEY_RELEASE to be
a click, when in fact it should only count as a click if it also got
the corresponding KEY_PRESS as well. This meant that when typing in a
chat notification, any Space/Enter keypress would dismiss the
notification, since the StEntry would take the PRESS event but ignore
the RELEASE, allowing it to propagate to the notification itself,
which would treat it as a click.

https://bugzilla.gnome.org/show_bug.cgi?id=645243
2011-03-21 10:18:46 -04:00
0eaf141ae4 user-status: Honor lockdown settings
Right now, the user status menu always contains actions to logout
and lock the screen, and the user switching action only depends on
the technical availability of the functionality.
All those items should honor the lockdown settings defined in
org.gnome.desktop.lockdown.

https://bugzilla.gnome.org/show_bug.cgi?id=645335
2011-03-21 15:02:10 +01:00
291ef07cf3 run-dialog: Honor lockdown settings
org.gnome.desktop.lockdown has a setting to prevent the use of the
Alt-F2 run dialog. Honor this setting.

https://bugzilla.gnome.org/show_bug.cgi?id=645335
2011-03-21 15:00:32 +01:00
b9066ac997 Updated Lithuanian translation. 2011-03-21 14:26:19 +01:00
206f4604a4 gnome-shell: fix restart after rebuild
Alt+F2 restart was failing after a rebuild when running from the
source tree because it would try to restart
".libs/lt-gnome-shell-real", which didn't exist yet. Fix this by using
"libtool --mode=execute" at build time to regenerate that file.

https://bugzilla.gnome.org/show_bug.cgi?id=645390
2011-03-21 09:20:23 -04:00
adbc1d97a0 StThemeNode: support border-image: none
Treat border-image: none as a valid specification that overwrites any
previously specified border image.

https://bugzilla.gnome.org/show_bug.cgi?id=644788
2011-03-21 09:16:32 -04:00
70ae700461 Only add hot corner for primary and "top left" monitors
To avoid having hot corners that accidentally trigger when e.g. trying
to hit the panel on the primary monitor we add hot corners only to
monitors that are "naturally" top left (top right for RTL).

For instance, we'd like a hot corner here:

corner -> +-------------
          |            |
+---------+            |
|=========|            |
|         |            |
|         |            |
|         |            |
+---------+------------+

But not here:

          unexpected hot corner
          ↓
+---------+-------+
|=========|       |
|         |       |
|         +-------+
+---------+

https://bugzilla.gnome.org/show_bug.cgi?id=645116
2011-03-21 10:32:30 +01:00
b81ad3ed39 Updated Portuguese translation 2011-03-20 23:52:36 +00:00
77cdb17cee ShellAppSystem: dynamically generate known_vendor_prefixes
It create prefix based on desktop file's id and desktop file's path and vendor_prefix.
https://bugzilla.gnome.org/show_bug.cgi?id=620464
2011-03-20 23:39:38 +03:00
d4e329b76d Updated Galician translations 2011-03-20 18:54:54 +01:00
fb24585dd8 Don't use italic for status items in menus
https://bugzilla.gnome.org/show_bug.cgi?id=645276
2011-03-20 12:23:58 -04:00
bd5efd5968 Added Latvian translation. 2011-03-20 15:35:24 +02:00
650f35c1f3 Util: use the right function name when reporting errors.
It's Main.notifyError, not Main.notifyProblem.

https://bugzilla.gnome.org/show_bug.cgi?id=645248
2011-03-19 19:57:08 +01:00
14e65168c9 Updated Polish translation 2011-03-19 16:19:43 +01:00
f00c47c21a Updated Indonesian translation 2011-03-19 22:12:28 +07:00
547d105b2e Updated Korean translation 2011-03-19 23:23:32 +09:00
de671103ca Updated Serbian translation 2011-03-19 12:37:28 +01:00
2c48efa3fd dash: Handle cancelled drags
If a drag was cancelled, do animations like size changes or zooming
out the remove target in parallel with the snapback animation.

https://bugzilla.gnome.org/show_bug.cgi?id=644324
2011-03-19 11:16:10 +01:00
7f35b2dc43 workspaces-view: Zoom out early on canceled item drags
Start the zoom at the same time as the snapback animation, as it's
already done for window snapbacks.

https://bugzilla.gnome.org/show_bug.cgi?id=644324
2011-03-19 11:16:10 +01:00
6ae914da2f overview: Handle drag-cancelled signal for items
Allow handling the drag-cancelled signal for non-window items, just
like the handling for windows instroduced in commit a80e88e33.

https://bugzilla.gnome.org/show_bug.cgi?id=644324
2011-03-19 11:16:10 +01:00
06ea78af1b view-selector: Don't fade in the initially selected tab
The fade effect when switching tabs should only be applied when
switching from a previously selected tab, not when selecting the
initial one - otherwise, the window previews are faded in the first
time the overview is shown.

https://bugzilla.gnome.org/show_bug.cgi?id=644389
2011-03-19 11:16:09 +01:00
2ea12a7699 Updated Hungarian translation 2011-03-19 02:47:36 +01:00
8ab25de6c6 Fix user visible typo: s/estabilished/established/
The affected translations are also modified to not cause any
inconvenience for translators.
2011-03-19 01:16:16 +01:00
e0424a7017 Updated Dutch translation by Wouter Bolsterlee 2011-03-19 01:14:43 +01:00
f259162d64 workspacesView: Fix graphical glitches with windows appearing for a split-second
When we were knocking off workspace height to fix the ratio problems, we
weren't adding spacing in between workspaces, so they smooshed up against
each other whenever we took height off, causing them to be visible.
2011-03-18 23:21:43 +01:00
6bb5cdeb2f Updated Spanish translation 2011-03-18 20:01:08 +01:00
384c30b6fd Updated Slovenian translation 2011-03-18 18:45:54 +01:00
67a75d4439 Update Simplified Chinese translation. 2011-03-18 18:34:54 +08:00
0d963df7b3 status: use Shell.AppSystem to launch settings panels
Different methos are being used to launch the control-center panels of each
status icon. Standarize on Shell.AppSystem.
This also fixes the network icon using a non-existant Util.spawnDesktop()
method.

Bug #645091
2011-03-17 23:26:14 -05:00
99efde5673 Switch Clutter module to http git checkout
It apparently is unlikely that anongit access will be restored
to clutter-project.org. We'll update the moduleset again when
alternate hosting is found.
2011-03-17 23:03:18 -04:00
c8ff699c4b Updated Romanian translation 2011-03-18 00:20:27 +01:00
0718a888d0 Updated Romanian translation 2011-03-18 00:18:56 +01:00
b7be4df603 panel: Hide spinner when switching apps
Commit fcfd17e was overzealous when simplifying the previous spinner
animation, as a result the spinner now stays around when switching
to another application while the animation is ongoing.
2011-03-17 22:06:34 +01:00
8bece0b49e Updated Arabic translation 2011-03-17 22:55:07 +02:00
47d6edc3c8 Updated Spanish translation 2011-03-17 20:20:09 +01:00
26bb56396d Updated Spanish translation 2011-03-17 20:06:18 +01:00
dd99ed73a9 Fallback to using a generic when requested image isn't found
Use a type specific generic image when the requested icon
can't be loaded instead of using an empty texture.

https://bugzilla.gnome.org/show_bug.cgi?id=644668
2011-03-17 14:02:04 -04:00
36ce460a39 Uploaded Ukranian 2011-03-17 18:59:08 +02:00
e92c845dfd Updated Italian translation 2011-03-17 16:03:27 +01:00
492263c2e9 Link against libmutter.
https://bugzilla.gnome.org/show_bug.cgi?id=644565
2011-03-17 15:26:51 +01:00
0c99f66547 Handle workspaces going empty due to windows changing monitors
If a workspace becomes empty due to a window changing to/from the
primary monitor, but not changing its original workspace then we
were not noticing this. This can happen for instance if you drag
a thumbnail window to a non-primary window.

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-17 14:13:55 +01:00
df440496ee Constrain zoomed overview windows to the current monitor
Additionally, the constraint to not overlap the panel should only happen
on the primary monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-17 14:13:55 +01:00
09f2028d6a overview: hidden workspace thumbnails should not stick out on other monitor
We clip the entire WorkspacesDisplay to its allocation to avoid things
like the WorkspaceThumbnails sticking out of the primary monitor into
another monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-17 14:13:55 +01:00
05736ba0a1 Always reserve space in all workspaces on a drag
We used to do this only on automatic workspace switch, but that
doesn't work for the multiple monitors case where we want to reserve
space on the extra monitors.

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-17 14:13:55 +01:00
e5f05bc9d8 Add workspaces on non-primary monitors
We create a Workspace with a null metaWorkspace for each
non-primary monitor, showing the windows on these monitors.
These are saved in WorkspaceView.extraWorkspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-17 14:13:55 +01:00
cdd1209b55 Only show windows from the primary monitor on the overview workspace
This means a bunch of windows will not be visible at all in the overview.
Those will be added back with per-screen workspaces on the non-primary
monitors.

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-17 14:13:55 +01:00
0e6458a630 Only show windows from the primary monitor in the workspace thumbnails
Also, if windows are dropped on the thumbnail, move them to the primary
monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-17 14:13:55 +01:00
a1a068a377 Only show the primary monitor region in the workspace thumbnails
Make the thumbnail the size of the primary monitor and only show
the windows from that area.

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-17 14:13:55 +01:00
2c5657e8a9 Enable the workspaces_only_on_primary feature of mutter
https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-17 14:13:55 +01:00
87fbd715a3 Updated Norwegian bokmål translation 2011-03-17 09:44:09 +01:00
fc8cba9598 Updated Hebrew translation. 2011-03-17 00:38:02 +02:00
147725bf7a gnome-shell.modules: Add a gtk3 dep for libgweather 2011-03-16 18:01:40 -04:00
06d2c0af35 messageTray: dismiss notifications on click, not button-release-event
Notification was connecting to button-release-event to decide when to
be dismissed, which caused problems with widgets inside the
notification that reacted to button-press-event but not
button-release-event. Fix this by wrapping the Notification's table in
an StButton and connecting to 'click'.

https://bugzilla.gnome.org/show_bug.cgi?id=642978
2011-03-16 15:55:37 -04:00
708f1a97dd Move the font color CSS rule from .workspaces-view to .window-caption
This is needed once we start seeing window captions outside the
workspaces view (for other monitors).

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-16 20:33:25 +01:00
d8bd9f5a66 Add and export shell_global_get_primary_monitor_index
https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-16 20:33:25 +01:00
079953c3ee Switch to using the mutter primary monitor APIs
https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-16 20:30:58 +01:00
fea8b6da2f Remove broken ShellAppSystem API and all consumers
In commit 9bd22dc0, I introduced an API to load an arbitrary
.desktop file, not necessarily from the menu path.  It turns
out this function was broken because it created ShellApp instances
that were *different* from ones that were cached normally.

As far as I can tell, we didn't initially use it.  Then later
Util.spawnDesktop was created which used this function.

Remove this broken function and all callers; if we're loading
.desktop files from *outside* the menu path, we can look at
readding.

This patch also kills off Util.spawnDesktop in favor of callers
talking to ShellAppSystem directly, now that the latter reports
errors.

https://bugzilla.gnome.org/show_bug.cgi?id=644402
2011-03-16 15:07:22 -04:00
4bf1df0894 ShellApp: Report error when we fail to run an app
https://bugzilla.gnome.org/show_bug.cgi?id=644402
2011-03-16 15:07:22 -04:00
b4f16c4df8 Add shell_global_report_error()
Move the "system notification error" handling out of
util.js, and add it to ShellGlobal so we can start
calling it from across the codebase better (including
C).

https://bugzilla.gnome.org/show_bug.cgi?id=644402
2011-03-16 15:07:21 -04:00
61282737c5 Updated Galician translations 2011-03-16 19:56:26 +01:00
d8c2290099 Prelight panel items on hover
In order to give feedback when the user hovers
over items on the panel, we should prelight them.

https://bugzilla.gnome.org/show_bug.cgi?id=609576
2011-03-16 19:52:54 +01:00
830ab599df Updated Spanish translation 2011-03-16 19:30:11 +01:00
0de5c5e8a3 Updated Hungarian translation 2011-03-16 19:01:40 +01:00
c6170ed751 windowManager: fix up accounting of dimmed windows
Simplify the accounting of which windows we should dim by checking
the current state of windows rather than trying to track changes,
and by keeping a list of dimmed windows rather than a list of windows
with a dimmed parent. Remove windows from the list of dimmed windows
when they are destroyed.

This should fix problems where destroyed windows could end up in
the list of dimmed windows.

https://bugzilla.gnome.org/show_bug.cgi?id=644167
2011-03-16 12:31:06 -04:00
2ea762cfc9 Updated Italian transaltion 2011-03-16 17:04:19 +01:00
2646741297 Updated Arabic translation 2011-03-16 17:46:23 +02:00
f5df5faf71 Update Simplified Chinese translation. 2011-03-16 23:28:57 +08:00
cab9a580e8 gnome-shell-jhbuild: Adjust GI_TYPELIB_PATH for NM inclusion
When jhbuilding, we use a jhbuilt gobject-introspection, so the
default typelib path is the jhbuild prefix, not /usr. So if we are
using NetworkManager from packages, we need to adjust GI_TYPELIB_PATH
to include it.

https://bugzilla.gnome.org/show_bug.cgi?id=621707
2011-03-16 11:04:33 -04:00
c8ac3fd4f5 Status area: add NetworkManager indicator
Adds an implementation of nm-applet in javascript. Uses the new
introspection from NetworkManager, and temporarily requires
nm-applet to be running for the secret service.
Features a renewed interface, with each device controllable through
a switch, which if toggled off disconnects, and if toggled on
connects to the most recently used valid connection. More esoteric
features like creation of ad-hoc networks have been moved to the
control center panel.

https://bugzilla.gnome.org/show_bug.cgi?id=621707
2011-03-16 15:59:34 +01:00
7f67c34b39 Bluetooth: fix updating the device list
Inside the inner loop, use the inner iterator, not that of the outer
loop. At the same time, refactor the code to rely less on private
properties appended to foreign objects.

https://bugzilla.gnome.org/show_bug.cgi?id=644858
2011-03-16 15:29:37 +01:00
e27293edbc messageTray: fix summary area wobbling
Due to accumulation of rounding errors, the left edge of the summary area
could wobble by a few pixels during animations. Fix that.

https://bugzilla.gnome.org/show_bug.cgi?id=636930
2011-03-16 09:47:07 -04:00
8d57c5052c Updated Arabic translation 2011-03-16 14:53:53 +02:00
1314559833 polkit: drop gdmuser naming workaround
The polkit authentication dialog contains logic for
falling back to dispalying a user's username if that
user has no real name.

This logic is no longer needed because gdmuser does it
internally now.

https://bugzilla.gnome.org/show_bug.cgi?id=644765
2011-03-15 15:50:26 -04:00
735397aa89 gdm: fix empty real name check
gdm_user_get_real_name() checks for an empty real
name and automatically falls back to username if
real name is NULL.  It doesn't automatically fall
back to username if real name is empty, however.

This commit makes it fall back for both cases.

https://bugzilla.gnome.org/show_bug.cgi?id=644765
2011-03-15 15:49:15 -04:00
c0d0c792e1 StContainer: Account for floating-point imprecision when sorting actors
When we compare the boxes for two actors, they may appear to overlap
by a small amount because of floating-point imprecision. Allow for
up to 0.1 pixel overlap when determining what children are in the
focus direction from the currently focused actor.

https://bugzilla.gnome.org/show_bug.cgi?id=644134
2011-03-15 15:41:07 -04:00
43020b20b7 ShellWindowTracker: don't create ShellApps for non-interesting windows
If a process does not have any "interesting" windows, then it can't be
considered a running app. (Previously we were calling
get_app_for_window() before ruling out non-interesting windows, which
ended up calling _shell_app_new_for_window(), which would add the
window to the ShellApp directly, bypassing the is_interesting check.)

https://bugzilla.gnome.org/show_bug.cgi?id=642221
2011-03-15 15:37:08 -04:00
0a3d80b86e accessibility: remove Screen Reader and Screen Keyboard entries
These are not 100% ready for 3.0 (though they are still available from
the control panel).

https://bugzilla.gnome.org/show_bug.cgi?id=639762
2011-03-15 15:36:09 -04:00
a9505d0426 workspaceView: Make sure to scale the workspace proportionally
Commit 0207f1f29b landed a new
way of zooming, but was causing all sorts of window positioning
weirdness because the positions were supposed to be working against
a proportional workspace.

https://bugzilla.gnome.org/show_bug.cgi?id=644542
2011-03-15 13:28:38 -04:00
4d804c2a29 telepathyClient: remove alias-change messages, to unbreak string freeze
https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-15 13:12:15 -04:00
e8eec2d357 Use points for font sizes
Do a basic job of converting font sizes from pixels to points, so they
will scale will the global GNOME scale factor. Some other sizes that are
clearly related to the font sizes are changed to ems, but no comprehensive
attempt is made to get rid of px units.

https://bugzilla.gnome.org/show_bug.cgi?id=636868
2011-03-15 12:01:40 -04:00
971e3f679f Updated Slovenian translation 2011-03-15 16:13:05 +01:00
7c90f078e7 Updated Slovenian translation 2011-03-15 16:09:30 +01:00
5957bd1abb Updated Galician translations 2011-03-15 15:26:21 +01:00
b16380e7e5 Updated Galician translations 2011-03-15 15:26:21 +01:00
b72a32c70d Updated Hungarian translation 2011-03-15 14:44:00 +01:00
90f15b3c5a dateMenu: open calendar specifically when opening evolution
https://bugzilla.gnome.org/show_bug.cgi?id=641504
2011-03-15 09:13:09 -04:00
44bbf26cb2 gnome-shell.modules: add --disable-Werror to telepathy-logger
It does not currently build error-free with gcc 4.6.
2011-03-15 08:41:02 -04:00
fcfd17e973 app-menu: Simplify startup animation
During application startup, we used to display a rotating spinner
which also moved from left to right, revealing the application title.
The result looks rather busy, so remove the horizontal movement.

https://bugzilla.gnome.org/show_bug.cgi?id=640782
2011-03-15 13:27:44 +01:00
73853cf147 .gitignore: add gnome-shell-perf-helper 2011-03-15 08:27:04 -04:00
ddbc263da2 [l10n] Updated Estonian translation 2011-03-15 13:42:27 +02:00
982d8a0dc0 build: Fix TelepathyLogger version requirement
We are supposed to require the 0.2 gir file not 1.0.
2011-03-15 00:15:26 +01:00
5a269db9d5 telepathyClient: Add messages from TelepathyLogger
This allows users to see chat history from other contacts with
the inline message tray replies.

https://bugzilla.gnome.org/show_bug.cgi?id=643377
2011-03-14 18:49:31 -04:00
525da01a62 shell-global: Add wrappers for TelepathyLogger
gjs can't support more than one callback in the same function,
so work around this with yet another shell-global wrapper.

https://bugzilla.gnome.org/show_bug.cgi?id=643377
2011-03-14 18:49:31 -04:00
12df10b2d0 Require a recent TelepathyLogger
We require a TelepathyLogger version with gobject-introspection support.

https://bugzilla.gnome.org/show_bug.cgi?id=643377
2011-03-14 18:48:18 -04:00
e6aee5d7ea telepathyClient: Add support for the ACTION message type
This message type is usually supported by the '/me' command
in IRC and IM clients.

https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-14 18:48:18 -04:00
6ff69da0de telepathyClient: Add support for aliases on the self-contact
Upgrade the connection's self contact to allow aliases, so that we
don't show the internal telepathy identifier anywhere user-visible.

https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-14 18:48:18 -04:00
ebcb87c163 shell-global: Add shell_get_self_contact_features
This is another workaround for the lack of gjs supporting array
arguments, this time wrapping tp_connection_upgrade_contacts to
add new features to the connection's self contact.

https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-14 18:48:18 -04:00
79d9df9bb1 telepathyClient: Add history navigation to entry
This adds a non-saving history to each notification entry,
like runDialog and lookingGlass.

https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-14 18:42:55 -04:00
8c40c2086a telepathyClient: Add alias change notifiers
Update the Source title when an contact's alias changes, and
also also add a minor meta message like the current timestamps.

Updating the alias of a 'presenced' contact will overwrite the
current title, and it will also not update the summary item title
right now due to limitations of the message tray.

https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-14 18:42:55 -04:00
f4a000cb59 telepathyClient: Re-open existing chat sources on Shell restart
This allows users to continue a chat they were having after
the shell is restarted.

https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-14 18:42:55 -04:00
4029202635 messageTray: Add Source.pushNotification method
This allows clients to make minor adjustments to their notification
content without triggering a new popup.

https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-14 18:42:55 -04:00
29d473f2fa XDND: Fix dragMonitor leak in WorkspacesDisplay
WorkspacesDisplay removes its dragMonitor in _dragEnd, but
this was never called in when a xdnd drag ended causing
dragMonitors to stack up and handling events multiple times.

Fix that by making sure that _dragEnd is called when xdnd ends.

https://bugzilla.gnome.org/show_bug.cgi?id=644642
2011-03-14 22:03:33 +01:00
7ad89dc46b Work around Spidermonkey problem with Unicode date formats
Monkey-patch Date.prototype.toLocaleFormat() with a version that uses
g_date_time_format() since the Spidermonkey built-in can't handle
format strings with Unicode characters.

https://bugzilla.gnome.org/show_bug.cgi?id=643350
2011-03-14 15:33:44 -04:00
4b2d6f8a99 clock: update every second
If we don't update every second, we may show the wrong time for up to
a minute on 1. resume; or 2. when changing the time; or 3. when
changing the timezone. This is both annoying and and leads to people
thinking that the tool for changing the time / timezone is broken.

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

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-03-14 14:36:24 -04:00
9b55de1c6b polkit: Make dialogs look more like the mockups
The mockups are here

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

Detailed changes

 - Don't use an icon for root
 - For root, show Administrator in red
 - Nuke icons for info and error messages
 - Make error messages yellow
 - Use 10pt size for error and message labels, not 12px
 - Don't make the dialog change size when (single-line) error/info
   messages appear
 - Spacing fixes
 - Show "Sorry, that didn't work. Please try again" if authentication fails
 - Don't cancel the PolkitAgentSession if the session has already completed

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

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-03-14 15:18:03 -03:00
8b45211a8f gnome-shell.modules: patch libcanberra to not use gtk_quit_add()
Add patch from the main GNOME 3 moduleset to make libcanberra
work properly with GTK+ 3.
2011-03-14 13:55:49 -04:00
f079501cff placeDisplay: Remove network places
It hasn't existed in nautilus for a while now, and we don't
have places at all.

https://bugzilla.gnome.org/show_bug.cgi?id=644402
2011-03-14 10:37:19 -04:00
e375e1789b popupMenu: don't include hidden items in the width computation
https://bugzilla.gnome.org/show_bug.cgi?id=621707
2011-03-14 09:28:06 -04:00
30d2cfdf56 Updated Korean translation 2011-03-14 10:40:23 +09:00
44d61e6857 Remove use of G_CONST_RETURN macro.
This is going to be deprecated.

https://bugzilla.gnome.org/show_bug.cgi?id=644632
2011-03-13 22:03:47 +01:00
3466829766 popupMenu: Restyle the slider to use a color for the 'active' area
In the mockups the slider does not have an uniform color but uses
one color (shade of blue) to indicate the current value and one
to indicate "the rest" (shade of grey).

So adjust the slider to look like that to be closer to the look
in the mockups and thus to the design.

https://bugzilla.gnome.org/show_bug.cgi?id=644600
2011-03-13 19:33:03 +01:00
d3703516d9 Fix handling of clutter_init() failures
clutter_init() fails under normal circumstances like
being unable to open a display connection, so it shouldn't
be handled with g_error() producing a core dump.

Clutter consistently produces an error message when
clutter_init() fails, so we don't need to print out any
error message.

https://bugzilla.gnome.org/show_bug.cgi?id=643910
2011-03-13 14:29:47 -04:00
bdebaa986b Silence -Werror for other clutter_init callers 2011-03-13 14:16:54 -04:00
c2d400846b test-theme: Pacify -Werror for clutter_init 2011-03-13 14:11:33 -04:00
034e147910 l10n: Updated Greek translation 2011-03-13 19:14:24 +02:00
25015c9c3a BluetoothStatus: don't pass NaNs to native functions
GJS complains when a NaN is passed in place of an integer, and
parseInt returns that from non numeric string. Pass a sentinel
that cancels the operation in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=642978
2011-03-13 17:05:33 +01:00
43cf60f563 StScrollViewFade: Fix GLSL shader to work on r300 hardware
The number instructions in a shader is limited to 64 on r300 hardware,
the fade shader in StScrollViewFade was ending up using 97 instructions
which is way over the limit.

So refactor the shader to use less instructions by precomputing as many
values as possible outside of the conditionals. The resulting shader
ends up using 34 instructions which is well within the hardware limits.

https://bugzilla.gnome.org/show_bug.cgi?id=644589
2011-03-13 16:29:18 +01:00
057348763b StTextureCache: generate icon names in the right order
GThemedIcon expects the first name to be the most specific, and
will thus prefer it to later ones. We thus need to order the names
from the longer to the shorter.

https://bugzilla.gnome.org/show_bug.cgi?id=621707
2011-03-13 14:46:42 +01:00
7230452e23 Updated Romanian translation 2011-03-13 01:31:36 +01:00
438317c1e9 Updated Romanian translation 2011-03-13 01:31:02 +01:00
cfe719c962 Updated Romanian translation 2011-03-13 01:25:15 +01:00
44e2d88628 Updated Romanian translation 2011-03-13 01:19:11 +01:00
6e50e77709 Updated Romanian translation 2011-03-13 00:32:01 +01:00
02ed28d68d Updated Dutch translation by Wouter Bolsterlee 2011-03-12 23:53:15 +01:00
73274e201b Status Menu: use Gnome Session DBus for shutdown and logout
Around 2.91.90, gnome-session-save was renamed to gnome-session-quit.
This commit restores compatibility with the older gnome-session, for
those testing under GNOME 2.32 or below, by calling the DBus methods
directly.

https://bugzilla.gnome.org/show_bug.cgi?id=644591
2011-03-12 21:37:39 +01:00
f6fc88cc2d perf: Add metrics for switching to the applications view
Measure how long it takes to switch from the workspaces view to the
windows view the first time and the second time.

https://bugzilla.gnome.org/show_bug.cgi?id=644266
2011-03-11 19:25:40 -05:00
d16acc43d9 viewSelector: allow programmatically switching to tabs
Add the idea of an 'id' for a tab, and add a public switchTab method
so you can switch to 'applications' or 'windows'. This will be useful
for performance tests that test tab switching performance.

https://bugzilla.gnome.org/show_bug.cgi?id=644266
2011-03-11 19:25:40 -05:00
239aa7b8d5 perf: Add metrics for different window configurations
Add metrics:
 overviewFps5Windows
 overviewFps10Windows
 overviewFps5Maximzed
 overviewFps10Maximized
 overviewFps5Alpha
 overviewFps10Alpha

To have more numbers to show how performance varies with different
numbers of windows and different types of windows (maximized,
with an alpha channel.)

https://bugzilla.gnome.org/show_bug.cgi?id=644265
2011-03-11 19:25:40 -05:00
44a1bc5396 scripting.js: small cleanups
- Fix missing trailing semicolons
- Catch when something results in metrics not being to avoid
  hard-to-debug JSON parse errors.

https://bugzilla.gnome.org/show_bug.cgi?id=644265
2011-03-11 19:21:07 -05:00
821583acae Use gnome-shell-perf-helper to control windows during perf tests
* Run gnome-shell-perf-helper during performance tests
* Use MUTTER_WM_CLASS_FILTER to omit all other windows
* Add new Scripting methods: createTestWindow,
  waitTestWindows, destroyTestWindows
* Create a single 640x480 test window for testing overview
  animation performance.

https://bugzilla.gnome.org/show_bug.cgi?id=644265
2011-03-11 19:21:07 -05:00
c6a2814881 gnome-shell-perf-helper: add server for creating test windows
Add a small D-Bus server program that the performance tests can
use to create well-specificed sets of windows.

https://bugzilla.gnome.org/show_bug.cgi?id=644265
2011-03-11 19:21:07 -05:00
1954a02352 gnome-shell-jhbuild: Fix race condition when launching DConf manually
We need to connect to the NameOwnerChanged signal before we execute the
DConf binary. Refactor things so that we connect to the signal when
we first get the bus object. Split the code for waiting for a D-Bus
name into a wait_for_dbus_name() function for latter reuse.

https://bugzilla.gnome.org/show_bug.cgi?id=644265
2011-03-11 19:21:06 -05:00
8a28022a6b Don't show the overview unless removing the workspace
Don't enter the overview at startup, or when we we remove the
last window on the first workspace, but only when we remove a
workspace and there are windows on the other workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=644541
2011-03-11 19:21:06 -05:00
43a243b24a CSS: Remove a left-over from an earlier relayout iteration 2011-03-11 21:29:23 +01:00
7c937c8704 gvc: Fix missing introspection
It's all Bastien's fault
2011-03-11 17:50:49 +00:00
bdd1f82777 volume: Use constants from GVC
Instead of defining our own.

https://bugzilla.gnome.org/show_bug.cgi?id=644511
2011-03-11 16:29:59 +00:00
cbb8876815 gvc: Fix introspection building 2011-03-11 16:29:40 +00:00
f8cdaaae30 gvc: Update from gnome-control-center
https://bugzilla.gnome.org/show_bug.cgi?id=644511
2011-03-11 16:29:40 +00:00
74314bacd7 Remove DYNAMIC_MOZJS_HACK bits
Not used anymore now that gnome-shell is a real ELF binary with an
rpath.
2011-03-11 10:30:33 -05:00
04473f607b gnome-shell-jhbuild: exit 1 if gnome-shell-real failed
We need to be propagating the failure exit code so that
gnome-session knows something went wrong.
2011-03-11 10:30:33 -05:00
88958270cb New translation for Afrikaans (af) 2011-03-11 12:39:00 +02:00
856f7ecee9 Updated Italian translation 2011-03-11 01:57:01 +01:00
9f5584a157 Uploaded Ukranian 2011-03-10 20:20:27 +02:00
eda8a94d5b Updated Spanish translation 2011-03-10 19:14:39 +01:00
5956b13588 Updated Hebrew translation. 2011-03-10 18:45:10 +02:00
162d029c81 statusMenu: Lock screen before suspending
We need to lock the screen before suspending the system
to prevent unauthorized access to the system / account.

https://bugzilla.gnome.org/show_bug.cgi?id=643357
2011-03-09 21:59:50 +01:00
7f3920dbb7 statusMenu: Use the screensaver's dbus interface directly
Use the dbus interface instead of calling gnome-screensaver-command.

https://bugzilla.gnome.org/show_bug.cgi?id=643357
2011-03-09 21:59:26 +01:00
6d07c3a1df Updated Polish translation 2011-03-09 21:48:39 +01:00
a0a83428cf telepathyClient: Pin the scrollbar to the bottom
When new messages come in we want to scroll down so that the user
sees the incoming messages. The current implementation does not work
because it relies on a synchronous allocation hack which does not work
for unmapped notifications.

Fix that by connecting to adjustment::changed and scroll whenever the
adjustment changes which equals "new messages", "new timestamp" or
"presense change", but don't interference with the user's scroll actions
i.e when the user scrolls back to read something don't scroll to the bottom.

https://bugzilla.gnome.org/show_bug.cgi?id=614977
2011-03-09 19:38:17 +01:00
dc2cae07b2 notification: Remove scrollTo hack
Remove the hack from Notification.scrollTo because it is unreliable,
the caller should make sure to call scrollTo when it will actually
have the desired effect.

https://bugzilla.gnome.org/show_bug.cgi?id=614977
2011-03-09 19:38:16 +01:00
f8b44cd30e Updated Spanish translation 2011-03-09 19:38:10 +01:00
c3eca3d754 Updated Spanish translation 2011-03-09 19:37:05 +01:00
1ea005f6a6 Updated Slovenian translation 2011-03-09 17:40:12 +01:00
16a675b7ce Bail early from check over all permutations
If we're already doing worse than the best so far there is
no need to continue checking this particular permutation.

https://bugzilla.gnome.org/show_bug.cgi?id=609258
2011-03-09 10:45:21 +01:00
df2f939f3a Start the workspace zoom out immediately on dnd cancel.
This means the snap-back animation happens at the same time as the zoom,
which looks much better.

https://bugzilla.gnome.org/show_bug.cgi?id=643786
2011-03-09 10:36:09 +01:00
5743224817 Don't rearrange dragged window when repositioning windows
If we're dragging a window around and we need to reposition the windows,
due to e.g. the sliding in of the thumbnails or some other reason, then we
need to consider the original position of the dragged window, rather than
the currend drag position. Otherwise we will unnecessarily rearrange the
other windows for instance on snap-back if you moved the dragged window
past some other window.

https://bugzilla.gnome.org/show_bug.cgi?id=643786
2011-03-09 10:36:09 +01:00
a80e88e33e dnd: Add a drag-cancelled signal
This lets us start the workspace zoom out animation right when the
snapback starts, rather than waiting for the snapback to finish.

https://bugzilla.gnome.org/show_bug.cgi?id=643786
2011-03-09 10:36:09 +01:00
0207f1f29b Restructure the way we handle positioning zooming in Workspace
We currently show the workspace in the overview in a rectangle
with the same aspect ratio as the screen. Originally this was
probably done since it showed the desktop, but we don't do this
anymore, and the positioning of the windows in the overview is
strictly a grid, so its not in any way related to monitor geometry.
Additionally, in the multihead case the screen aspect ratio is
very different from the overview monitor geometry, so a lot of
space is lost.

So, instead we just fill the entire inner rectangle of the overview
with the workspace. However, the way the zoom into and out of the
workspace right now is by scaling the workspace so that it covers
the entire monitor. This cannot really work anymore when the workspace
is a different aspect ratio. Furthermore the coordinates of the
window clone actors are of two very different types in the "original
window" case and the "window in a slot case". One is screen relative,
the other is workspace relative. This makes it very hard to compute
the cost of window motion distance in computeWindowMotion.

In order to handle this we change the way workspace actor positioning
and scaling work. All workspace window clone actors are stored in
true screen coordingates, both the original window positions and the
in-a-slot ones. Global scaling of the workspace is never done, we
just reposition everything in both the initial zoom and when the
controls appear from the side.

There is one issue in the initial and final animations, which is that
the clip region we normally have for the workspacesView will limit the
animation of the clones to/from the original positions, so we disable
the clip region during these animations.

https://bugzilla.gnome.org/show_bug.cgi?id=643786
2011-03-09 10:36:02 +01:00
72120bb87f dnd: Avoid division by zero, etc for zero-size actors
When rescaling due to a possible parent actor resize avoid problems
if the parent width is zero.

https://bugzilla.gnome.org/show_bug.cgi?id=643786
2011-03-09 10:27:36 +01:00
7eaca86bf1 updated kn translations 2011-03-09 09:39:58 +05:30
db5f72c868 Updated Arabic translation 2011-03-09 01:12:50 +02:00
69d6ae4141 panel: prevent blink of current app indicator
If new current app is null, show animation of disappearing old.
https://bugzilla.gnome.org/show_bug.cgi?id=615099
2011-03-09 01:53:32 +03:00
edabafc0fc gnome-shell.modules: update the git repository for telepathy-glib
Telepathy repositories moved to freedesktop.org:
http://lists.freedesktop.org/archives/telepathy/2011-February/005291.html

https://bugzilla.gnome.org/show_bug.cgi?id=644239
2011-03-08 16:14:20 -05:00
e9f2aa6010 Updated British English translation 2011-03-08 19:53:18 +00:00
e054dd7813 autoWorkspaces: Merge empty workspaces with the always empty one
When closing a workspace due to the last window on that workspace
closing, switch to the overview and show the always empty workspace
rather then just going to the adjacent workspace.

Based on a patch from Adel Gadllah <adel.gadllah@gmail.com>.

https://bugzilla.gnome.org/show_bug.cgi?id=642188
2011-03-08 19:46:51 +01:00
76d788a186 windowManager: Add mechanism to block animations
Add an API to allow blocking animations in situations where
they aren't desireable.

https://bugzilla.gnome.org/show_bug.cgi?id=642188
2011-03-08 19:46:46 +01:00
3944df1bd2 altTab: fix incorrect positioning with multiple monitors
Calculate the position of the alt-tab popup correctly when primary.x != 0.
This was accidentally broken by 614176b269
https://bugzilla.gnome.org/show_bug.cgi?id=644206
2011-03-08 20:21:07 +03:00
49f6280645 src: add more stuff to gnome_shell_real_LDADD
to work with libtools that are more strict about not allowing
transitive dependencies
2011-03-08 11:47:14 -05:00
84eb66d5aa StContainer: simplify focus navigation
When navigating from a non-immediate descendant of a container, we
were attempting to use clutter_actor_get_transformed_position() to get
the exact position of that actor relative to the container, but this
did not really make sense, since we would be using the position of
the intermediate container when navigating back.

https://bugzilla.gnome.org/show_bug.cgi?id=644134
2011-03-08 09:36:55 -05:00
026fc531ba StTextureCache: never return fullcolor icons for ST_ICON_SYMBOLIC
g_themed_icon_new_with_default_fallbacks() does not do what we want
with symbolic icons; if the user's icon theme is not "gnome", then it
will end up preferring a non-symbolic icon from the higher-level theme
over a symbolic icon from gnome-icon-theme-symbolic.

If the shell requests a symbolic icon, and there is only a
non-symbolic icon available, that should be considered a programmer
error, just like requesting a non-existent icon name. So change the
code to only look up "-symbolic" names when drawing an
ST_ICON_SYMBOLIC icon.

https://bugzilla.gnome.org/show_bug.cgi?id=644142
2011-03-08 09:36:55 -05:00
8d14df0ced Updated Norwegian bokmål translation 2011-03-08 15:29:51 +01:00
f27547dcff l10n: Updated Greek translation for gnome-shell 2011-03-08 15:00:59 +02:00
6f15d1c4c4 Bump version to 2.91.91 2011-03-08 00:41:38 -05:00
46ffff8438 Add missing files to CLEANFILES 2011-03-08 00:41:38 -05:00
8dcd08f47e Fix srcdir != builddir issues
* calendar-server subdirectory of build directory needs to
  be created.
* Generate shell-enum-types.c/.h in build directory rather than
  in the possibly-read-only source directory.
2011-03-08 00:41:38 -05:00
2515d5ad6c POTFILES.in: add main.c 2011-03-08 00:41:38 -05:00
e6b1853908 Require Mutter 2.91.91 2011-03-07 23:59:00 -05:00
e2b26c4014 update Punjabi Translation by A S Alam 2011-03-08 08:27:29 +05:30
d4b7a3478e build: Fix LDADD for gnome-shell-real
Use the libtooled shared object, and the dependency on it.
2011-03-08 00:51:27 +00:00
e187961d72 src: update for mutter include reorganization
https://bugzilla.gnome.org/show_bug.cgi?id=641724
2011-03-07 18:33:33 -05:00
ae96b0c971 Use libmutter-wm, and build a real gnome-shell binary
Build gnome-shell as a binary linked against libmutter-wm, instead of
a module to be loaded by libmutter-wm. Move the majority of
initialization-type stuff from gnome_shell_plugin_start() into main().

We still build libgnome-shell as a shared library, so that the linker
doesn't discard all the methods that are never called from C.

https://bugzilla.gnome.org/show_bug.cgi?id=641724
2011-03-07 18:33:33 -05:00
c4dad3d2c1 MessageTray: remove source if associated application exits
We don't want sources that are no longer associated with a running
application to stick around in the message tray.

https://bugzilla.gnome.org/show_bug.cgi?id=642659
2011-03-07 17:37:31 -05:00
36287fc33b Fix hover state after DND
During a drag-and-drop, our pointer grab keeps enter/leave events from
being delivered. That means that after the DND ends, whatever actor is
under the pointer won't have received the enter event it should have,
and any state or hover effect dependent on that won't work right.
By paying attention to the actors we leave and enter we can figure out
what widgets we need to call st_widget_sync_hover() on after the drag.

https://bugzilla.gnome.org/show_bug.cgi?id=640974
2011-03-07 16:53:56 -05:00
edd5a5f185 appView: Highlight category names on hover
This is consistent with the viewselector's tab and indicates to the
user that the item is actually clickable.
2011-03-07 21:22:15 +01:00
bb7388a7fe Don't show right click menu if a new notification for the source is showing
Showing the right click menu causes errors when ungrabbing focus in this case.
It will soon be impossible to get to the right click menu anyway when a new
notification is showing, because we are never going to show the summary
and the new notification at the same time.
2011-03-07 14:24:08 -05:00
797368bf9f Revert "panel: remove accessibility icon"
pending further discussion in
https://bugzilla.gnome.org/show_bug.cgi?id=639762

This reverts commit 7790a07c08.
2011-03-07 13:06:34 -05:00
0cccf1d4cc viewSelector: add Applications pane and search entry to Ctrl-Alt-Tab
Add Ctrl-Alt-Tab support to ViewTab, and fix the Applications pane to
scroll to track the keyboard focus.

The Windows pane can be switched to, but navigation within the pane is
not yet implemented.

https://bugzilla.gnome.org/show_bug.cgi?id=618887
2011-03-07 11:15:05 -05:00
7aa326a836 overview, appDisplay: add Dash to Ctrl-Alt-Tab
Add the dash to Ctrl-Alt-Tab, add appropriate :focus CSS, and connect
to the popup-menu signal on dash icons.

https://bugzilla.gnome.org/show_bug.cgi?id=618887
2011-03-07 11:15:05 -05:00
fe16f2b058 St: add a popup-menu signal to StWidget
Add a popup-menu signal to StWidget, and emit it if the user types the
Menu key or Shift+F10 while the widget is focused.

https://bugzilla.gnome.org/show_bug.cgi?id=618887
2011-03-07 11:15:05 -05:00
af4fcc831e ctrlAltTab: misc improvements
Fix the "panel" icon to be symbolic. Make the overview parts only show
up when in the overview, and the non-overview parts (eg, the Desktop
window, if there is one) only show up when not in the overview. Sort
the different items consistently with their locations on the screen.

https://bugzilla.gnome.org/show_bug.cgi?id=618887
2011-03-07 11:15:05 -05:00
868bf5838d MessageTray: add right click menu for summary items
This provides straight forward controls for opening the corresponding
application or removing the summary item.

https://bugzilla.gnome.org/show_bug.cgi?id=617224
2011-03-07 11:14:11 -05:00
4282748483 Fix removing summary items
Unset this._expandedSummaryItem if it is the summary item that is being removed.
This avoids "this._sourceTitle.clutter_text is null" error.

Destroy the summary item actor only after calling _unsetClickedSummaryItem()
that disconnects from one of its signals.

https://bugzilla.gnome.org/show_bug.cgi?id=644043
2011-03-07 11:14:10 -05:00
7790a07c08 panel: remove accessibility icon
The accessibility menu is not ready for prime time. Remove it for now.

https://bugzilla.gnome.org/show_bug.cgi?id=639762
2011-03-07 11:00:42 -05:00
ef6cce8988 popupMenu, panelMenu: split up panel and non-panel keynav
PopupMenuManager was pretending that it knew nothing about the menu's
sourceActors, while also trying to handle keynav between them. This
was a big mess, and resulted in bugs in navigation between panel menus
and the Activities button, and it totally gets in the way when trying
to add keynav to the dash (whose menu sources are arranged vertically
rather than horizontally).

Fix this up by moving the panel-specific parts to PanelMenuButton
instead.

https://bugzilla.gnome.org/show_bug.cgi?id=641253
2011-03-07 10:57:45 -05:00
df848fdb4d dateMenu: make the menu un-key-navigable
It already doesn't work right, because the PanelMenuButton code
assumes that Left and Right won't be used as part of keynav within a
menu. And the gnome-panel calendar isn't keyboard accessible either,
so this isn't a regression. To be fixed later.

https://bugzilla.gnome.org/show_bug.cgi?id=641253
2011-03-07 10:57:45 -05:00
b4489d9ea6 tools: Fix typo in check-for-missing.py 2011-03-07 15:48:11 +00:00
1496d6af2f Update the spinner to be consistent with adwaita/gtk
https://bugzilla.gnome.org/show_bug.cgi?id=643708
2011-03-07 16:24:19 +01:00
52a05090bf CSS: Update window close button.
https://bugzilla.gnome.org/show_bug.cgi?id=643977
2011-03-07 16:24:19 +01:00
38235ecb97 gnome-shell-build-setup.sh: Add missing deps for evolution-data-server
evolution-data-server requires libical and gperf.

Based on patch from Eric Springer.
2011-03-06 22:30:16 -05:00
bf8b9b4906 Workaround broken Translation 2011-03-07 00:54:10 +01:00
727f2ce994 [l10n] Updated Catalan translation 2011-03-06 18:43:28 +01:00
8b3309f4f6 Updated Norwegian bokmål translation 2011-03-06 13:40:22 +01:00
5e08b248e8 Updated Bulgarian translation 2011-03-05 23:07:36 +02:00
0b1bf5f642 theme: Adjust CSS for RTL locales
Use :ltr/:rtl pseudo selectors where the CSS depends on the locale's
text direction.

https://bugzilla.gnome.org/show_bug.cgi?id=643835
2011-03-05 19:49:21 +01:00
8ed191283a Remove manually added :rtl pseudo classes
To deal with different CSS in RTL locales, we used to manually add
an :rtl pseudo class to some actors. With automatically assigned
:ltr/:rtl selectors this is no longer necessary.

https://bugzilla.gnome.org/show_bug.cgi?id=643835
2011-03-05 19:40:56 +01:00
fefe2df6b5 st-widget: Add automagic rtl/ltr pseudo classes
At times, RTL locales require different CSS, so always create theme
nodes with :ltr/:rtl pseudo classes depending on the widget's text
direction, to provide an easy way to handle those cases without
requiring a separate stylesheet.

https://bugzilla.gnome.org/show_bug.cgi?id=643835
2011-03-05 19:40:52 +01:00
aff9b419cf Updated Vietnamese translation 2011-03-05 15:42:21 +07:00
cae081950d po/vi.po: import from Damned Lies 2011-03-05 15:38:08 +07:00
06bf8d3470 Updated Vietnamese translation 2011-03-05 15:34:35 +07:00
a532b70f70 po/vi.po: update-po 2011-03-05 15:33:49 +07:00
cf85477864 workspace: Move close button to the left in RTL locales
Mutter reverses the button layout in RTL locales, so we should do
the same for the window previews' close buttons.

https://bugzilla.gnome.org/show_bug.cgi?id=643834
2011-03-04 22:42:57 +01:00
614176b269 appSwitcher: Fix logic error in AltTabPopup._allocate 2011-03-04 17:07:45 +01:00
03401bbb58 CtrlAltTabPopup: Fix pixel alignment
CtrlAltTabPopup was using a St.BoxLayout and relied on anchor_gravity
center for positioning. This does not guarantee correct pixel alignment,
so use a St.GenericContainer instead and do the positioning similar to
that of the appSwitcher.

https://bugzilla.gnome.org/show_bug.cgi?id=643820
2011-03-04 17:07:01 +01:00
75ae209653 history: Fix HistoryManager
Make GSettings support optional, refactor text entry handling,
fix some off-by-one bugs in the management itself, use Params
for parsing, fix other typos and bugs.

https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-04 09:07:15 -05:00
8ce97961b4 lookingGlass: Add TelepathyGLib to the default set of imports
https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-03-04 09:07:04 -05:00
8ffe5957e5 updated kn translations 2011-03-04 17:43:43 +05:30
47e2c4ae6c updated kn translations 2011-03-04 17:43:43 +05:30
0065e2cfac xdndHandler: Correctly disconnect the window group visibility handler 2011-03-04 11:23:18 +01:00
2ee4f57395 WindowAttentionHandler: Fix notify callback leak
Keep track of the connected handlers and disconnect them on
when destroying the source.

https://bugzilla.gnome.org/show_bug.cgi?id=640781
2011-03-04 08:27:32 +01:00
e01971eac7 base-icon: Always recreate icon texture on style changes
Currently the icon texture is only updated on style changes when
the icon size is set from CSS and differs from the previously used
icon size.
As the style change may have been triggered by an icon theme change,
textures that are created for themed icons should always be recreated;
given that this is the case for most uses (with the exception of
file thumbnails), recreate the icon texture unconditionally to avoid
complexity.

https://bugzilla.gnome.org/show_bug.cgi?id=643738
2011-03-03 23:14:32 +01:00
d6e29be980 panel: Include panel corners in startup animation
Commit b1654af406 moved the panel positioning (and thus that of its
corners) before the panel startup animation. As the panel corners now
are mapped while the panel animation is active, the initial style-changed
signal which triggers another repositioning is received after the
initial layout and the corners end up at wrong positions.
To fix, animate the corner positions as well during the startup
animation - if anyone could actually see the animation, the corners
should animate with the panel anyway ...

https://bugzilla.gnome.org/show_bug.cgi?id=643804
2011-03-03 22:56:38 +01:00
6fbf8fa9e4 panel: Use a constant for the panel startup animation time
https://bugzilla.gnome.org/show_bug.cgi?id=643804
2011-03-03 22:43:35 +01:00
c64242c276 gnome-shell-build-setup: Install sqlite, libproxy for Ubuntu
Both of these are required by libsoup.  Also add sqlite-devel
for Fedora.
2011-03-03 16:33:37 -05:00
440b222664 Do not launch power statistics app from battery items
https://bugzilla.gnome.org/show_bug.cgi?id=640768
2011-03-03 15:44:38 -05:00
1c759384fa jhbuild: Install evolution-data-server for Ubuntu
Ubuntu's libecal is too old, so add evolution-data-server to the modules
file and have gnome-shell depend on that.  Also add libsoup, libgweather
and glib-networking as indirect dependencies.

Remove evolution-data-server-dev from the list of packages to install
and add libproxy-dev and libdb-dev.
2011-03-03 13:48:54 -05:00
602fa1c657 universal-access: Use "text-scaling-factor" instead of "dpi"
The latter has been removed from the schema, so adjust to that change.
2011-03-03 18:49:40 +01:00
d964d2baae Ensure that all struts we set extends to their boundary
Mutter really expects this, as this is how app-specified struts
happen. For instance, if the primary display is beside a taller
screen and is not positioned at the top, then we extend the struts
for the panel with the size of the unused area above the primary
monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=642881
2011-03-03 15:56:16 +01:00
d235c205d6 Consider struts top/botton or left/right based on primary monitor size
Right now we require a strut to be as wide as the full screen to
create a TOP strut. This means that in a multi-monitor scenario (at
least if the primary monitor is leftmost) we will make the panel strut
be Meta.Side.LEFT due to the random side picking for corner objects.

This changes the width/height comparison to the primary monitor rather
than the screen to get this right. Also adds some docs about how
struts work in a multi-monitor situation.

https://bugzilla.gnome.org/show_bug.cgi?id=642881
2011-03-03 15:56:16 +01:00
b1654af406 Fix positioning of panel on startup
We need to do the initial relayout before we start up the startup
animation, and the startup animation can't hardcode the position
of the panel to zero.

https://bugzilla.gnome.org/show_bug.cgi?id=642881
2011-03-03 15:56:00 +01:00
29e5768f9b messageTray: don't leak Notifications
https://bugzilla.gnome.org/show_bug.cgi?id=640781
2011-03-03 03:53:08 +03:00
3a6b4f3eb5 main: correct pushModal/popModal mechanism
1. disconnect destroy signals in popModal (actors can have great lifetime and then pushed again)
2. incorrect pushModal/popModal pair in overview
https://bugzilla.gnome.org/show_bug.cgi?id=64078
2011-03-03 03:53:04 +03:00
84889d6dea search-display: Minor style updates
Adjust the style of the search display to match current mockups:

 - add a border to search buttons
 - increase padding and spacing
 - remove section background and border
 - decrease font size in section headers

https://bugzilla.gnome.org/show_bug.cgi?id=643632
2011-03-02 23:12:35 +01:00
34ce17c4b3 search-result: Use a larger icon size
Increase the icon size of search results for consistency with the
application view. To account for the larger icons, only display
a single row of results per section.

https://bugzilla.gnome.org/show_bug.cgi?id=643632
2011-03-02 23:12:35 +01:00
7723e59a72 search: Replace 'icon' property in metaInfo with a function
Search results' meta info currently is expected to have an 'icon'
property holding a Clutter.Texture of a fixed icon size. This
property is used to implement the createIcon() function of BaseIcon,
which is used to actually display the result, ignoring the size
parameter due to the fixed icon size.
Given that all available search providers create this property for
the desired icon size using a function with the same signature, it
appears logical to replace the fixed-sized 'icon' property with
such a function, so that the icon size will be defined by the display
actor rather than the search system.

https://bugzilla.gnome.org/show_bug.cgi?id=643632
2011-03-02 23:12:35 +01:00
7f5135016e search: Don't expand search when clicking section headers
Currently section headers in the search view are reactive and run
the corresponding provider's expandSearch() function when clicked,
which should launch an external program displaying all search
results for the section. Unfortunately it is only implemented for
the "Settings" provider, and does not work properly (as it ignores
the search and just launches System Settings).
Also current mockups deemphasize the section header, making the
feature pretty much indiscoverable (except by accident when
interfering with swipe-scrolling).
In conclusion, the feature does not make much sense in its current
form, so remove it.

https://bugzilla.gnome.org/show_bug.cgi?id=643632
2011-03-02 23:12:35 +01:00
08e0485213 search-display: Remove search result count
Currently the total number of matches for a particular section is
displayed on the left of the section's header. While it made sense
in the old layout where it was close to the section's title, it is
now rather disconnected, and has been removed in current mockups.

https://bugzilla.gnome.org/show_bug.cgi?id=643632
2011-03-02 23:12:35 +01:00
04afea76e3 Updated Spanish translation 2011-03-02 20:41:02 +01:00
aa9a0aaf17 Updated Norwegian bokmål translation 2011-03-02 20:22:19 +01:00
3f792df631 Updated Hebrew translation. 2011-03-02 19:58:52 +02:00
b36aa6f41b Updated Arabic translation 2011-03-02 19:08:24 +02:00
6a5345aeed Uploaded Ukranian 2011-03-02 17:37:57 +02:00
b9cb37da5e PopupMenuManager: don't throw exceptions if don't have focus
stage.key_focus can be null, but passing null to _activeMenuContains
throws (from gjs marshalling). In that case, just assume it returned
false.

https://bugzilla.gnome.org/show_bug.cgi?id=642976
2011-03-02 16:30:38 +01:00
6207c68439 extensions: Ignore extensions in directories without read permission
Gio.enumerate_children() throws an exception if called for a directory
without read permissions. Catch this case to allow the shell to start.

https://bugzilla.gnome.org/show_bug.cgi?id=643663
2011-03-02 16:00:52 +01:00
0b149a941d Updated Italian translation 2011-03-02 13:38:03 +01:00
5e8f7ec590 app-display: Rename PREFERENCES search provider to SETTINGS
Both the shell and gnome-control-center prefer "Settings" over
"Preferences", so rename the corresponding search section.
2011-03-02 01:20:24 +01:00
6e3c15e2ab Use standard GObject Introspection make rules
Instead of defining rules manually, use the included make support,
which means Makefiles are less prone to API changes, support
verbosity correctly (instead of inconsistently hardcoding --quiet),
are cleaner to read, and emit GISCAN/GICOMP instead of GEN (which
is nicer).

https://bugzilla.gnome.org/show_bug.cgi?id=643371
2011-03-01 23:03:49 +01:00
3bee2e4228 Require libecal 2.32.0
We need e_cal_view_stop(), which appeared first in that release.

Signed-off-by: Federico Mena Quintero <federico@gnome.org>
2011-03-01 15:26:31 -05:00
89dcd9027d PowerStatus: report 0 minutes as "Estimating..."
When UPower has not yet collected enough data to calculate a time
to discharge, it will report 0 minutes. Show "Estimating..." in
that case instead.

https://bugzilla.gnome.org/show_bug.cgi?id=642753
2011-03-01 20:18:29 +01:00
102b2e2ca6 autoWorkspaces: Better handle apps that open a splashscreen or dialog at startup
Currently we remove a workspace when last window on that workspace closes,
which turned out to be too agressive as some apps open either a splashscreen
or a "I have crashed last time" dialog at startup.

Try to detect such apps and give them a chance to open their "real window(s)"
on the workspace.

https://bugzilla.gnome.org/show_bug.cgi?id=642188
2011-03-01 19:10:21 +01:00
998ea53b46 gnome-shell-jhbuild.in: Kill notification-daemon and notify-osd here
We need to terminate these processes in a replacing-GNOME-2 scenario.

Reviewed by danw on IRC.
2011-03-01 12:54:22 -05:00
2337373a17 gnome-shell: fix running-from-source-dir detection 2011-03-01 11:56:10 -05:00
af29174cb6 Update Simplified Chinese translation. 2011-03-01 15:56:18 +00:00
412c6bf4b5 .gitignore: update for calendar stuff 2011-03-01 10:09:56 -05:00
7fc6a3670c Add a configure option --enable-jhbuild-wrapper-script
The current gnome-shell.in script has a huge amount of
unnecessary complexity for the installed, normal case.  Fix
this by adding a configure option (defaulting to false) that
installs a simple, obvious wrapper script around mutter.

We do change the gnome-shell build setup to pass this option
by default for jhbuild.

https://bugzilla.gnome.org/show_bug.cgi?id=642084
2011-03-01 09:51:06 -05:00
70fbfea5f5 gnome-shell.in: Drop --eval-file option
Not really used, and makes the script smaller.  We could probably
put a sample script on the wiki instead.

https://bugzilla.gnome.org/show_bug.cgi?id=642084
2011-03-01 09:49:47 -05:00
9616b45518 gnome-shell.in: Drop TFP checks
These were only necessary for DRI1, and we just aren't going to
work well there anyways.

https://bugzilla.gnome.org/show_bug.cgi?id=642084
2011-03-01 09:49:46 -05:00
3916b5973d gnome-shell.in: Move extension creation to gnome-shell-extension-tool
https://bugzilla.gnome.org/show_bug.cgi?id=642084
2011-03-01 09:49:44 -05:00
5b3974b6b4 panel: Remove some unused duplicate constants 2011-03-01 09:40:48 -05:00
e8e36e8a66 statusMenu: change IM presence when needed (#617207) 2011-03-01 10:10:14 +01:00
88bcd0a9ce AppDisplay: allow changing categories by scrolling over them
Respond to scrolling over the app categories by changing them, so
it is not required to point and click, or to use the All view.

https://bugzilla.gnome.org/show_bug.cgi?id=643426
2011-02-28 22:57:31 +01:00
29eb3215b3 gnome-shell-calendar-server.c: Fix uninitialized variable usage
In case of of bad command line options being passed, an uninitialized
variable would be accessed.
2011-02-28 16:53:09 -05:00
7c534a87cf dnd: Don't pass null to ClutterActor.disconnect()
_ungrabActor disconnects the event signal handler but does not
check whether it is connected before doing so which can result into
an exception like:

JS ERROR: !!!   Exception was: Error: disconnect() takes one arg, the signal handler id
JS ERROR: !!!     lineNumber = '0'
JS ERROR: !!!     fileName = 'gjs_throw'
JS ERROR: !!!     stack = 'Error("disconnect() takes one arg, the signal handler id")@:0
2011-02-28 22:41:11 +01:00
e9e30138bd Move calendar handling out-of-process
Unfortunately the evolution-data-server client-side libraries seem to
block the calling thread. This is a major problem as we must never
ever block the main thread (doing so causes animations to flicker
etc.). In the worst case, this problem causes login to hang (without
falling back to fall-back mode) and in the best case it slows down
login until a network connection is acquired.

Additionally, in order to sanely use these evolution-data-server
libraries, GConf has to be involved and GConf is not thread-safe. So
it's not really feasible just moving the code to a separate
thread. Therefore, move all calendar IO out of process and use a
simple (and private) D-Bus interface for the shell to communicate with
the out-of-process helper.

For simplification, remove existing in-process code since internal
interfaces have been slightly revised. This means that the shell is no
longer using any native code for drawing the calendar dropdown.

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

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-02-28 16:08:18 -05:00
ddc135839b Extend, don't replace GI_TYPELIB_PATH in gnome-shell launcher
Without this we can't support some gi typelibs being in system
directories.
2011-02-28 21:38:46 +01:00
474ff2e997 Claim DBus names (Shell, Notifictions) *very* early
See commit f2158218bef0c51 in mutter.  Basically, we need
to grab org.freedesktop.Notifications before anything else
in the session gets started.

Note: I intentionally removed the Util.killall bits.  I believe that
for notification-daemon at least, if we specify
DBUS_NAME_FLAG_REPLACE_EXISTING, we'll take over the name.  Not sure
about notify-osd; if that's still a problem, then what we need to do
is add killing (and possibly respawning) of notify-osd to
"gnome-shell --replace", and not have it embedded randomly in a JS file.

https://bugzilla.gnome.org/show_bug.cgi?id=642666
2011-02-28 13:53:44 -05:00
0d2eb76cee Ensure that all signatures are defined in DBus interfaces
The DBus JS binding will complain if the signature of a method
or of a signal is undefined, so we need to define it even if it
is an empty string, and we need to use the correct property name
for signals.

https://bugzilla.gnome.org/show_bug.cgi?id=643374
2011-02-28 18:40:57 +01:00
6172cd3627 gnome-shell-build-setup.sh: belatedly remove xephyr-related stuff
since --xephyr is gone now
2011-02-28 09:16:45 -05:00
c71a6073e3 build: Switch moduleset to clutter-1.6 branch
We are targeting 1.6 for 3.0, so we should not follow the master
branch branch leading to 1.7
2011-02-28 13:09:54 +01:00
91b0e28b28 Updated Hebrew translation. 2011-02-27 22:58:53 +02:00
e15a9f2e73 Updated Arabic translation 2011-02-27 02:24:44 +02:00
cac134076b Updated Korean translation 2011-02-27 06:41:24 +09:00
39e67016b5 [l10n] Updated Estonian translation 2011-02-26 17:27:05 +02:00
c72241df5b alt-tab: Enforce icon size
For applications with no proper desktop file, the window icon is
used as application icon in the tab switcher, but it won't have
the correct icon size. The current approach is to add additional
padding to these icons - the size turns out inconsistent with
other icons, but the icon appears sharp. For the dash it has been
decided that unsharp icons are less evil than differing icon sizes,
so icons are scaled up to the "right" size - for consistency, do the
same in the alt-tab switcher.

https://bugzilla.gnome.org/show_bug.cgi?id=643300
2011-02-26 00:06:44 +01:00
a78e75775d base-icon: Enforce the requested icon size
Mainly due to StTextureCache's way of handling fallback icons, an
implementation of BaseIcon.createIcon() may return an icon smaller
than the requested size. Given that BaseIcon is not used for isolated
elements, but rather for groups of related items (App view, Dash,
Search Results, ...), having some elements end up with the wrong
size is more annoying than having some elements end up ugly due to
scaling, so explicitly enforce the requested icon size.

https://bugzilla.gnome.org/show_bug.cgi?id=642043
2011-02-26 00:06:44 +01:00
91b84e0b06 Updated Spanish translation 2011-02-25 20:35:52 +01:00
3403215698 Uploaded Ukranian 2011-02-25 20:56:17 +02:00
260e6662f0 overview: Remove unused 'getWorkspacesForWindow' method 2011-02-25 19:43:47 +01:00
5137cee3d6 app-display: Escape categories in filter labels
As gnome-shell now switched to use the menu file from gnome-menus,
we no longer have direct control over category names. If such a name
contains unescaped markup, the shell will crash when trying to create
the filter label, so make sure to escape markup in category names.
2011-02-25 18:04:08 +01:00
9915038e9b Drop gs-applications.menu so the standard one is used
gs-applications was introduced because we initially wanted a limited set
of categories, but this has now changed and we're back to categories
similar to the ones in the applications.menu from gnome-menus.

We can fix gnome-menus to have better categories, if needed.

https://bugzilla.gnome.org/show_bug.cgi?id=641148
2011-02-25 16:08:51 +01:00
7ddf54c4d3 appWellMenu: Show the "new window" item for non running apps
There is no reason to not display it, and from a user's point of view the
distinction is confusing.
2011-02-25 15:51:15 +01:00
cc72819579 authentication-agent: Fix typo in user visible string
https://bugzilla.gnome.org/show_bug.cgi?id=643275
2011-02-25 13:50:22 +01:00
6d902633e9 update Punjabi Translation by A S Alam 2011-02-25 07:35:51 +05:30
be775b9206 Use new name of gnome-session quit helper process
Changed names from gnome-session-save to gnome-session-quit.
2011-02-24 17:58:05 -05:00
15ec185be5 Don't declare global variables
Fix a typo in panel.js, and ensure that all variables used in
functions are scoped to the block (using let), to avoid polluting
the global namespace.

https://bugzilla.gnome.org/show_bug.cgi?id=643210
2011-02-24 21:22:44 +01:00
e1f33739b0 Updated Spanish translation 2011-02-24 20:34:52 +01:00
dff8d579ca panel: Don't let the app icon overlap the panel border
Commit 9a048af1f changed the panel border to be drawn below the
background - as a result, the app menu's icon now overlaps the
panel border. As it looks cleaner to leave the border in place,
clip the icon to the panel border.
2011-02-24 18:31:00 +01:00
ef2265de4f Small fixes 2011-02-24 16:33:19 +01:00
f7b4f99d4c Updated Hungarian translation 2011-02-24 16:11:53 +01:00
d5735496af viewSelector: don't process key presses from capture-event
Rather than connecting to stage::capture-event and then trying to
guess whether or not a given key-press should be handled by us or not,
handle the end-search-on-Escape case from entry::key-press-event
(since it only makes sense when the entry is focused anyway) and the
start-search-on-printable-key case from stage::key-press-event (which
will only get the events that no other actor wanted for itself).

Similarly, do exit-overview-on-Escape and switch-panes cases from
stage::key-press-event, rather than
viewSelector.actor::key-press-event, so that they will work correctly
even if the keyboard focus is somewhere else. (Also fix a longstanding
bug in the pane-switching code, which was supposed to be disabled when
a search was active, but was checking a non-existent variable.)

https://bugzilla.gnome.org/show_bug.cgi?id=642502
2011-02-24 09:36:36 -05:00
3755783d41 viewSelector: remove the search entry's event grab
The search entry was taking a sort of grab when it was in the
focused-but-empty state, and would eat up most events for other actors
(except, confusingly, for panel actors). The only bit of "modality" we
really need here is that the entry is supposed to go back to the
unfocused state if you click somewhere outside it when it was in the
focused-but-empty state. So do that.

https://bugzilla.gnome.org/show_bug.cgi?id=642502
2011-02-24 09:36:35 -05:00
5b8d3ba1d6 viewSelector: merge SearchEntry into SearchTab
The division of labor between the two was quite muddled. Rather than
try to invent a clean distinction of what belongs where, just merge
them together.

https://bugzilla.gnome.org/show_bug.cgi?id=642502
2011-02-24 09:36:35 -05:00
63be52e191 scroll-view-fade: Adjust the effect to work in RTL locales
The vertical scrollbar is located on the left in RTL locales, so
pass an additional parameter to the shader which indicates the
locale's text direction.

https://bugzilla.gnome.org/show_bug.cgi?id=643156
2011-02-24 12:30:05 +01:00
d15122c4b2 scroll-view: Make scrollbar position locale aware
In RTL locales, the vertical scrollbar should be located on the
left, so take the widget's text direction into account when
allocating the view's elements.

https://bugzilla.gnome.org/show_bug.cgi?id=643156
2011-02-24 12:30:05 +01:00
6d6ec46f25 XDND: Remove the switch timeout in _onDragEnd
When the user cancels the drag while hovering over a window the timeout
handler will throw an exception because the drag actor will be destroyed
at this point.

Fix that by removing the timeout in _onDragEnd.
2011-02-24 11:47:00 +01:00
8d78c3a2ab XDND: Always update the timestamp on motion
The xdnd timestamp gets updated on every xdnd-position event,
so while waiting for the window timeout to fire we need to make sure we
update the timestamp when getting on motion to activate the window
with the correct timestamp.
2011-02-24 11:46:53 +01:00
7077e57d53 main: Remove left-over 'hotCorner' global
Commit 259c84ed9a refactored out HotCorner into its own class
and added this line and a variable, but it was left behind
when the variable disappeared in commit 7cf311dac0.
2011-02-23 17:50:03 -05:00
031e606972 build: Fix libusb dependency on Ubuntu
I really shouldn't look up package names after midnight ...
2011-02-23 22:58:10 +01:00
d6601645d6 build: Add panel-border.svg to Makefile.am
I forgot to add it in commit 9a048af1fb.
2011-02-23 22:30:30 +01:00
97bb5b6680 telepathyClient: Fix two minor typos
https://bugzilla.gnome.org/show_bug.cgi?id=642793
2011-02-23 15:08:45 -05:00
adb04eb010 polkit: don't show authentication dialog until needed
See https://bugs.freedesktop.org/show_bug.cgi?id=27788#c1 for details
about the problem this patch is solving

In particular, we should never bring up the dialog if there is no
password on the account. While this sounds like a weird corner case,
it's not.. the Live CD, for example, does not have a root password.

This also avoids the initial dialog resize.. before the patch the
authentication dialog appears and a split-second later an StEntry
widget is added.

Also print out more diagnostic information if showing the modal dialog
fails. Also add a comment about how to easily make this happen.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-02-23 14:49:09 -05:00
ff171e3651 panel: Reposition corners on changes to the monitor layout
When the monitor layout changes, the panel might have been moved
to another monitor, in which case the rounded corners need to be
repositioned.

https://bugzilla.gnome.org/show_bug.cgi?id=643064
2011-02-23 20:32:31 +01:00
172d68d1fe panel: Add a relayout() method to position the panel
Currently the panel is positioned from main.js, move that code into
a method in panel.js instead and call it from main.js, which is
consistent with what we do for the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=643064
2011-02-23 20:32:31 +01:00
885f668d53 Track fullscreen status per-monitor in Chrome
This is required since we can have chrome on multiple monitors (due to
per-monitor hot-corners).

Windows are primary associated with the monitor that their center is on.

https://bugzilla.gnome.org/show_bug.cgi?id=642881
2011-02-23 20:16:48 +01:00
7cf311dac0 Put a hot corner on each monitor
https://bugzilla.gnome.org/show_bug.cgi?id=642881
2011-02-23 20:16:48 +01:00
259c84ed9a Move HotCorner to chrome instead of in the panel
This prepares for there being multiple hot corners, one per monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=642881
2011-02-23 20:16:48 +01:00
196d10454a Factor out hot corner handling into a class
This is needed so that we can have several instances, one per
monitor.

This also makes the hot corner environments a container which
contains the corner.

https://bugzilla.gnome.org/show_bug.cgi?id=642881
2011-02-23 20:16:48 +01:00
06198702c2 KeyboardStatus: fix showing current layout
Util.spawn accepts an array of strings as the arguments, and will
not implicitly convert other types.

https://bugzilla.gnome.org/show_bug.cgi?id=643104
2011-02-23 20:13:31 +01:00
12d991f336 A11yStatus: ignore an user default of O dpi
The default for the DPI setting is 0, but 0 * any scaling factor
is 0, so we need to deal with that, by falling back to X default.

https://bugzilla.gnome.org/show_bug.cgi?id=639762
2011-02-23 20:10:44 +01:00
2b740dc34c Updated Italian translation 2011-02-23 18:28:19 +01:00
855bbd523c Updated Arabic translation 2011-02-23 18:51:31 +02:00
a2a72d1998 Add missing file 2011-02-23 18:49:12 +02:00
9a048af1fb panel: Move panel border into the background
In the mockups the bottom border of active panel buttons is drawn
on top of the panel's border. To get this effect, move the panel
border into the background, so that it is not subtracted from the
vertical space given to the buttons. Adjust the drawing of the rounded
corners to reflect that change.

https://bugzilla.gnome.org/show_bug.cgi?id=643001
2011-02-23 17:39:07 +01:00
697139043f polkit: return error when authentication dialog is dismissed
This allows PolicyKit applications to disambiguate between when the
authentication dialog is dismissed versus when authentication fails
(e.g. the wrong password has been entered).

See https://bugs.freedesktop.org/show_bug.cgi?id=30653 for more
information.

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-02-23 11:02:46 -05:00
29ce02b1d2 Add explicit x11 dependencies
Since Ubuntu patches clutter-1.0.pc to remove x11 from the requires,
we have to list it explicitly for places we use X11 functions, like
ST and the shell recorder.

https://bugzilla.gnome.org/show_bug.cgi?id=643003
2011-02-23 10:57:04 -05:00
60ae784c01 Remove unused tracking of visibility in Chrome
https://bugzilla.gnome.org/show_bug.cgi?id=642881
2011-02-23 15:24:28 +01:00
e3511127c7 No need to Check for grabbed menus on hot corner enter/click
We never get enter events anyway due to the menu code, and if
the user clicks on a non-menu the menu is removed and ungrabbed
before the target actor gets the event anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=642881
2011-02-23 15:24:28 +01:00
fbf7528728 dateMenu: Make sure that the event list fills the available width
Currently the menu has a hardcoded width which result into the hover
effect of the "Open Calendar" item being "cut off" in the middle rather
then reaching to the edge.

To be consistent with other menu items, make it expand to fill the available
space.
2011-02-23 14:56:26 +01:00
e46a26aec1 Updated Norwegian bokmål translation. 2011-02-23 09:40:52 +01:00
200 changed files with 51835 additions and 19523 deletions

8
.gitignore vendored
View File

@ -7,7 +7,6 @@ ChangeLog
INSTALL
Makefile
Makefile.in
NEWS
aclocal.m4
autom4te.cache
config.h
@ -40,8 +39,13 @@ src/*-enum-types.[ch]
src/*-marshal.[ch]
src/Makefile
src/Makefile.in
src/gnomeshell-taskpanel
src/calendar-server/org.gnome.Shell.CalendarServer.service
src/gnome-shell
src/gnome-shell-calendar-server
src/gnome-shell-extension-tool
src/gnome-shell-jhbuild
src/gnome-shell-perf-helper
src/gnome-shell-real
src/run-js-test
src/test-recorder
src/test-recorder.ogg

80
NEWS Normal file
View File

@ -0,0 +1,80 @@
3.0.0.2
=======
* Fix missing import that was preventing extensions from loading.
[Maxim Ermilov]
https://bugzilla.gnome.org/show_bug.cgi?id=646333
Translations:
Timo Jyrinki [fi]
3.0.0.1
=======
* Fix problem with stuck event handling if network menu pops down while
user is using the scrollbar. [Owen Taylor]
https://bugzilla.gnome.org/show_bug.cgi?id=646825
Contributors to GNOME Shell 3.0
===============================
Code:
Josh Adams, Kiyoshi Aman, Nuno Araujo, Emmanuele Bassi, Dirk-Jan C. Binnema,
Wouter Bolsterlee, Raphael Bosshard, Milan Bouchet-Valat, Christina Boumpouka,
Mathieu Bridon, Alban Browaeys, Phil Bull, Micro Cai, Giovanni Campagna,
Cosimo Cecchi, Tor-björn Claesson, Matthias Clasen, Jason D. Clinton,
Frederic Crozat, Guillaume Desmottes, Sander Dijkhuis, Neha Doijode,
Maxim Ermilov, Diego Escalante Urrelo, Luca Ferretti, Steve Frécinaux,
Takao Fujiwara, Adel Gadllah, Vadim Girlin, Nick Glynn, Guido Günther,
Leon Handreke, Lex Hider, Richard Hughes, Javier Jardón, Abderrahim Kitouni,
Andre Klapper, Alexander Larsson, Nickolas Lloyd, Ryan Lortie, Kjartan Maraas,
Koop Mast, Rui Matos, Jonathan Matthew, William Jon McCann, Morten Mjelva,
Federico Mena Quintero, Florian Müllner, Jon Nettleton, Hellyna Ng,
Discardi Nicola, Carlos Martín Nieto, Bastien Nocera, Bill Nottingham,
Matt Novenstern, Marc-Antoine Perennou, Neil Perry, Frédéric Péters,
Alejandro Piñeiro, Siegfried-Angel Gevatter Pujals, "res", Neil Roberts,
"Sardem FF7", Florian Scandella, Joseph Scheuhammer, Christian Schramm,
Gustavo Noronha Silva, Jasper St. Pierre, Eric Springer, Jakub Steiner,
Jonathan Strander, Ray Strode, Owen Taylor, Rico Tzschichholz,
Sergey V. Udaltsov, Daiki Ueno, Vincent Untz, Marcelo Jorge Vieira,
Mads Villadsen, Colin Walters, Dan Winship, William Wolf, Thomas Wood,
Pierre Yager, David Zeuthen, Marina Zhurakhinskaya
Design:
Allan Day, William Jon McCann, Jeremy Perry, Jakub Steiner
2008 Boston GNOME design hackfest participants (especially Neil J. Patel
for turning the resulting sketches into our first mockups.)
Everybody on irc.gnome.org:#gnome-design
Translations:
Friedel Wolff (af), Khaled Hosny (ar), Ivaylo Valkov (bg), Jamil Ahmed (bn)
Runa Bhattacharjee (bn_IN), Gil Forcada, Siegfried-Angel Gevatter Pujals,
Jordi Serratosa (ca), Andre Klapper, Petr Kovar (cs), Kenneth Nielsen,
Kris Thomsen (da), Mario Blättermann, Hendrik Brandt, Christian Kirbach,
Hendrik Richter, Wolfgang Stöggl (de), Michael Kotsarinis, Kostas Papadimas,
Jennie Petoumenou, Sterios Prosiniklis, Fotis Tsamis, Simos Xenitellis (el),
Bruce Cowan, Philip Withnall (en_GB), Jorge Gonzalez, Daniel Mustieles (es),
Mattias Põldaru, Ivar Smolin (et), Inaki Larranaga Murgoitio (eu),
Mahyar Moghimi (fa), Timo Jyrinki (fi), Cyril Arnaud, Bruno Brouard,
Pablo Martin-Gomez, Claude Paroz, Frédéric Peters (fr), Seán de Búrca (ga)
Francisco Diéguez, Antón Méixome (gl), Sweta Kothari (gu), Liel Fridman,
Yaron Shahrabani (he), Rajesh Ranjan (hi), Gabor Kelemen (hu), Milo Casagrande,
Luca Ferretti (it), Dirgita, Andika Triwidada (id), Takayuki KUSANO,
Takayoshi OKANO, Kiyotaka NISHIBORI, Futoshi NISHIO (ja), Shankar Prasad (kn),
Young-Ho Cha, Changwoo Ryu (ko), Žygimantas Beručka, Gintautas Miliauskas (lt),
Rudolfs Mazurs (lv), Sandeep Shedmake (mr), Kjartan Maraas (nb),
Wouter Bolsterlee, Sander Dijkhuis, Reinout van Schouwen (nl),
Torstein Winterseth (nn), A S Alam (pa), Tomasz Dominikowski, Piotr Drąg (pl),
Duarte Loreto (pt), Felipe Borges, Rodrigo Padula de Oliveira,
Rodrigo L. M. Flores, Amanda Magalhães, Og B. Maciel, Gabriel F. Vilar,
Jonh Wendell (pt_BR), Lucian Adrian Grijincu, Daniel Șerbănescu (ro),
Sergey V. Kovylov, Andrey Korzinev, Yuri Myasoedov, Marina Zhurakhinskaya (ru),
Daniel Nylander (se), Matej Urbančič, Andrej Žnidaršič (sl),
Miloš Popović (sr, sr@latin), Miroslav Nikolić (sr), Tirumurti Vasudevan (ta),
Sira Nokyoongtong (th), Baris Cicek (tr), Abduxukur Abdurixit,
Gheyret T. Kenji (ug), Maxim V. Dziumanenko, Daniel Korostil (uk),
Nguyễn Thái Ngọc Duy (vi), Jessica Ban, 'jiero', Wei Li, YunQiang Su, Ray Wang,
Aron Xu (zh_CN), Chao-Hsiung Liao (zh_HK, zh_TW)

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[2.91.90],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.0.0.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c])
@ -52,8 +52,8 @@ AC_MSG_CHECKING([for GStreamer (needed for recording functionality)])
if $PKG_CONFIG --exists gstreamer-0.10 '>=' $GSTREAMER_MIN_VERSION ; then
AC_MSG_RESULT(yes)
build_recorder=true
recorder_modules="gstreamer-0.10 gstreamer-base-0.10 xfixes"
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0)
recorder_modules="gstreamer-0.10 gstreamer-base-0.10 x11"
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes)
else
AC_MSG_RESULT(no)
fi
@ -63,46 +63,60 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.5.15
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=0.7.11
MUTTER_MIN_VERSION=2.91.90
MUTTER_MIN_VERSION=3.0.0
GTK_MIN_VERSION=3.0.0
GIO_MIN_VERSION=2.25.9
LIBECAL_REQUIRED=1.6.0
LIBEDATASERVER_REQUIRED=1.2.0
LIBEDATASERVERUI2_REQUIRED=1.2.0
LIBEDATASERVERUI3_REQUIRED=2.91.6
LIBECAL_MIN_VERSION=2.32.0
LIBEDATASERVER_MIN_VERSION=1.2.0
LIBEDATASERVERUI2_MIN_VERSION=1.2.0
LIBEDATASERVERUI3_MIN_VERSION=2.91.6
TELEPATHY_GLIB_MIN_VERSION=0.13.12
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
POLKIT_MIN_VERSION=0.100
# 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 libxml-2.0
gtk+-3.0 >= $GTK_MIN_VERSION
mutter-plugins >= $MUTTER_MIN_VERSION
gjs-internals-1.0 >= $GJS_MIN_VERSION
libgnome-menu $recorder_modules gconf-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
libcanberra
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
polkit-agent-1 >= $POLKIT_MIN_VERSION)
PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
gio-unix-2.0 dbus-glib-1 libxml-2.0
gtk+-3.0 >= $GTK_MIN_VERSION
libmutter >= $MUTTER_MIN_VERSION
gjs-internals-1.0 >= $GJS_MIN_VERSION
libgnome-menu $recorder_modules gconf-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
libcanberra
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes)
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
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"])
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
JHBUILD_TYPELIBDIR="$INTROSPECTION_TYPELIBDIR"
# NM is the only typelib we use that we don't jhbuild
PKG_CHECK_EXISTS([libnm-glib >= 0.8.995],
[NM_TYPELIBDIR=`$PKG_CONFIG --variable=libdir libnm-glib`/girepository-1.0
if test "$INTROSPECTION_TYPELIBDIR" != "$NM_TYPELIBDIR"; then
JHBUILD_TYPELIBDIR="$JHBUILD_TYPELIBDIR:$NM_TYPELIBDIR"
fi])
AC_SUBST(JHBUILD_TYPELIBDIR)
saved_CFLAGS=$CFLAGS
saved_LIBS=$LIBS
CFLAGS=$MUTTER_PLUGIN_CFLAGS
LIBS=$MUTTER_PLUGIN_LIBS
CFLAGS=$GNOME_SHELL_CFLAGS
LIBS=$GNOME_SHELL_LIBS
# 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)
AC_CHECK_FUNCS(JS_NewGlobalObject sn_startup_sequence_get_application_id XFixesCreatePointerBarrier)
CFLAGS=$saved_CFLAGS
LIBS=$saved_LIBS
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 gnome-desktop-3.0 >= 2.90.0)
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 gnome-desktop-3.0 >= 2.90.0 x11)
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)
@ -125,20 +139,17 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
# Default to libedataserverui-3.0, but allow falling back to 1.2
PKG_CHECK_EXISTS(libedataserverui-3.0,
[EDS_API=3.0
LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI3_REQUIRED],
LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI3_MIN_VERSION],
[EDS_API=1.2
LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI2_REQUIRED])
PKG_CHECK_MODULES(LIBECAL, libecal-1.2 >= $LIBECAL_REQUIRED libedataserver-1.2 >= $LIBEDATASERVER_REQUIRED libedataserverui-$EDS_API >= $LIBEDATASERVERUI_REQUIRED)
AC_SUBST(LIBECAL_CFLAGS)
AC_SUBST(LIBECAL_LIBS)
LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI2_MIN_VERSION])
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-$EDS_API >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
AC_SUBST(CALENDAR_SERVER_CFLAGS)
AC_SUBST(CALENDAR_SERVER_LIBS)
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
# FIXME: metacity-plugins.pc should point directly to its .gir file
MUTTER_LIB_DIR=`$PKG_CONFIG --variable=libdir mutter-plugins`
MUTTER_PLUGIN_DIR=`$PKG_CONFIG --variable=plugindir mutter-plugins`
AC_SUBST(MUTTER_BIN_DIR)
AC_SUBST(MUTTER_LIB_DIR)
AC_SUBST(MUTTER_PLUGIN_DIR)
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
AC_SUBST(MUTTER_GIR_DIR)
AC_SUBST(MUTTER_TYPELIB_DIR)
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
AC_SUBST(GJS_CONSOLE)
@ -187,8 +198,9 @@ if test "$enable_compile_warnings" != no ; then
fi
changequote([,])dnl
AC_PATH_PROG(mutter, [mutter])
AC_SUBST(mutter)
AC_ARG_ENABLE(jhbuild-wrapper-script,
AS_HELP_STRING([--jhbuild-wrapper-script=yes],[Make "gnome-shell" script work for jhbuild]),,enable_jhbuild_wrapper_script=no)
AM_CONDITIONAL(USE_JHBUILD_WRAPPER_SCRIPT, test "x$enable_jhbuild_wrapper_script" = xyes)
AC_CONFIG_FILES([
Makefile

View File

@ -24,17 +24,20 @@ dist_theme_DATA = \
theme/calendar-today.svg \
theme/close-window.svg \
theme/close.svg \
theme/corner-ripple.png \
theme/corner-ripple-ltr.png \
theme/corner-ripple-rtl.png \
theme/dash-placeholder.svg \
theme/filter-selected.svg \
theme/filter-selected-ltr.svg \
theme/filter-selected-rtl.svg \
theme/gnome-shell.css \
theme/mosaic-view-active.svg \
theme/mosaic-view.svg \
theme/move-window-on-new.svg \
theme/panel-border.svg \
theme/panel-button-border.svg \
theme/panel-button-highlight-narrow.svg \
theme/panel-button-highlight-wide.svg \
theme/process-working.png \
theme/process-working.svg \
theme/running-indicator.svg \
theme/scroll-button-down-hover.png \
theme/scroll-button-down.png \
@ -47,6 +50,7 @@ dist_theme_DATA = \
theme/separator-white.png \
theme/single-view-active.svg \
theme/single-view.svg \
theme/source-button-border.svg \
theme/toggle-off-us.svg \
theme/toggle-off-intl.svg \
theme/toggle-on-us.svg \
@ -71,11 +75,6 @@ all-local: gschemas.compiled
gconfschemadir = @GCONF_SCHEMA_FILE_DIR@
gconfschema_DATA = gnome-shell.schemas
menudir = $(sysconfdir)/xdg/menus
menu_DATA = \
gs-applications.menu
shadersdir = $(pkgdatadir)/shaders
shaders_DATA = \
shaders/dim-window.glsl

View File

@ -13,3 +13,4 @@ NoDisplay=true
X-GNOME-Autostart-Phase=WindowManager
X-GNOME-Provides=panel;windowmanager;
X-GNOME-Autostart-Notify=true
X-GNOME-AutoRestart=true

View File

@ -81,5 +81,20 @@
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/windows/workspaces_only_on_primary</key>
<applyto>/desktop/gnome/shell/windows/workspaces_only_on_primary</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Workspaces only on primary monitor</short>
<long>
This key overrides /apps/mutter/general/workspaces_only_on_primary when
running GNOME Shell.
</long>
</locale>
</schema>
</schemalist>
</gconfschemafile>

View File

@ -1,85 +0,0 @@
<Menu>
<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>
<And>
<Category>Game</Category>
</And>
</Include>
</Menu>
<Menu>
<Name>Graphics</Name>
<Include>
<And>
<Category>Graphics</Category>
</And>
</Include>
</Menu>
<Menu>
<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>
<Not><Category>Settings</Category></Not>
<Not><Category>Screensaver</Category></Not>
</And>
</Include>
</Menu>
</Menu>

View File

@ -1,5 +1,5 @@
<schemalist>
<schema id="org.gnome.shell" path="/apps/gnome-shell/"
<schema id="org.gnome.shell" path="/org/gnome/shell/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="development-tools" type="b">
<default>true</default>
@ -54,7 +54,7 @@
<child name="recorder" schema="org.gnome.shell.recorder"/>
</schema>
<schema id="org.gnome.shell.calendar" path="/apps/gnome-shell/calendar/"
<schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="show-weekdate" type="b">
<default>false</default>
@ -65,7 +65,7 @@
</key>
</schema>
<schema id="org.gnome.shell.clock" path="/apps/gnome-shell/clock/"
<schema id="org.gnome.shell.clock" path="/org/gnome/shell/clock/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="show-seconds" type="b">
<default>false</default>
@ -83,7 +83,7 @@
</key>
</schema>
<schema id="org.gnome.shell.recorder" path="/apps/gnome-shell/recorder/"
<schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="framerate" type="i">
<default>15</default>

View File

@ -1,24 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<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"
version="1.0"
id="Foreground"
x="0px"
y="0px"
width="22"
height="22"
viewBox="0 0 16 16"
width="32"
height="32"
viewBox="0 0 23.272727 23.272727"
enable-background="new 0 0 16 16"
xml:space="preserve"
sodipodi:version="0.32"
inkscape:version="0.46"
inkscape:version="0.48+devel r10081 custom"
sodipodi:docname="close-window.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata2399"><rdf:RDF><cc:Work
@ -37,11 +39,49 @@
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="16 : 8 : 1"
inkscape:persp3d-origin="8 : 5.3333333 : 1"
id="perspective2401" /></defs><sodipodi:namedview
inkscape:window-height="999"
inkscape:window-width="1680"
id="perspective2401" /><filter
color-interpolation-filters="sRGB"
inkscape:collect="always"
id="filter16494-4"
x="-0.20989846"
width="1.4197969"
y="-0.20903821"
height="1.4180764"><feGaussianBlur
inkscape:collect="always"
stdDeviation="1.3282637"
id="feGaussianBlur16496-8" /></filter><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient16498-6"
id="radialGradient16504-1"
cx="7.6582627"
cy="5.8191104"
fx="7.6582627"
fy="5.8191104"
r="8.6928644"
gradientTransform="matrix(1.0474339,0,0,1.0517402,-0.3632615,-0.42032492)"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
id="linearGradient16498-6"><stop
style="stop-color:#7b7b7b;stop-opacity:1"
offset="0"
id="stop16500-8" /><stop
style="stop-color:#101010;stop-opacity:1"
offset="1"
id="stop16502-0" /></linearGradient><filter
color-interpolation-filters="sRGB"
inkscape:collect="always"
id="filter16524-9"
x="-0.212979"
width="1.425958"
y="-0.21305652"
height="1.426113"><feGaussianBlur
inkscape:collect="always"
stdDeviation="0.71020915"
id="feGaussianBlur16526-0" /></filter></defs><sodipodi:namedview
inkscape:window-height="1114"
inkscape:window-width="1463"
inkscape:pageshadow="2"
inkscape:pageopacity="1"
inkscape:pageopacity="0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
@ -50,27 +90,63 @@
pagecolor="#000000"
id="base"
showgrid="false"
inkscape:zoom="25.648691"
inkscape:cx="8.8097603"
inkscape:cy="9.0472789"
inkscape:zoom="1"
inkscape:cx="10.720189"
inkscape:cy="13.739577"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:current-layer="Foreground"
showguides="true"
inkscape:guide-bbox="true" />
inkscape:guide-bbox="true"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:window-maximized="0"><inkscape:grid
type="xygrid"
id="grid11246"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" /></sodipodi:namedview>
<g
id="g3175"><path
sodipodi:nodetypes="csssc"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.59217799;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path2394"
d="M 0.83987936,8.0425327 C 0.83987936,4.0805265 4.0712155,0.86823453 8.0567103,0.86823453 C 12.042205,0.86823453 15.273542,4.0805265 15.273542,8.0425327 C 15.273542,12.004539 12.042205,15.216831 8.0567103,15.216831 C 4.0712155,15.216831 0.83987936,12.004539 0.83987936,8.0425327 z"
clip-rule="evenodd" /><g
id="g3172"><path
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 5.4242673,5.3313047 L 10.515414,10.421272 L 10.714004,10.646491"
id="path3152" /></g></g><path
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 5.4402527,10.650392 L 10.688082,5.3573033"
id="path3154"
sodipodi:nodetypes="cc" /></svg>
style="display:inline"
id="g16402-8"
transform="translate(4.7533483,2.8238929)"><g
id="g3175-4"><path
sodipodi:type="inkscape:offset"
inkscape:radius="0"
inkscape:original="M 7.65625 0.125 C 3.2589349 0.125 -0.3125 3.7070002 -0.3125 8.125 C -0.3125 12.543001 3.2589349 16.125 7.65625 16.125 C 12.053566 16.125 15.625 12.543001 15.625 8.125 C 15.625 3.7070002 12.053566 0.125 7.65625 0.125 z "
xlink:href="#path2394-32"
style="opacity:0.52994014;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.18181825;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;filter:url(#filter16494-4);enable-background:accumulate"
id="path16480-5"
inkscape:href="#path2394-32"
d="m 7.65625,0.125 c -4.3973151,0 -7.96875,3.5820002 -7.96875,8 0,4.418001 3.5714349,8 7.96875,8 4.397316,0 7.96875,-3.581999 7.96875,-8 0,-4.4179998 -3.571434,-8 -7.96875,-8 z"
transform="translate(0,1.028519)" /><path
clip-rule="evenodd"
d="m -0.30428257,8.1237596 c 0,-4.4179998 3.56522987,-7.9999996 7.96254497,-7.9999996 4.3973156,0 7.9625456,3.5819998 7.9625456,7.9999996 0,4.4180014 -3.56523,8.0000004 -7.9625456,8.0000004 -4.3973151,0 -7.96254497,-3.581999 -7.96254497,-8.0000004 z"
id="path2394-32"
style="color:#000000;fill:url(#radialGradient16504-1);fill-opacity:1;fill-rule:nonzero;stroke:#eeeeec;stroke-width:1.4545455;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;enable-background:accumulate"
sodipodi:nodetypes="csssc"
inkscape:connector-curvature="0" /><g
id="g3172-6" /></g><g
transform="matrix(0.72727273,0,0,0.72727273,2.368236,2.1803254)"
style="fill:#ffffff;fill-opacity:1;display:inline"
id="g27275-6-6"
inkscape:label="window-close"><g
style="fill:#ffffff;fill-opacity:1;display:inline"
id="g27277-1-1"
transform="translate(-41,-760)"><path
sodipodi:type="inkscape:offset"
inkscape:radius="0"
inkscape:original="M 44.21875 764.1875 L 44.21875 765.1875 C 44.19684 765.46825 44.289258 765.74287 44.5 765.9375 L 46.78125 768.21875 L 44.5 770.46875 C 44.31181 770.65692 44.218747 770.92221 44.21875 771.1875 L 44.21875 772.1875 L 45.21875 772.1875 C 45.48404 772.1875 45.749336 772.09444 45.9375 771.90625 L 48.21875 769.625 L 50.5 771.90625 C 50.688164 772.0944 50.953449 772.18749 51.21875 772.1875 L 52.21875 772.1875 L 52.21875 771.1875 C 52.218742 770.9222 52.125688 770.65692 51.9375 770.46875 L 49.6875 768.21875 L 51.96875 765.9375 C 52.18441 765.73815 52.21875 765.47397 52.21875 765.1875 L 52.21875 764.1875 L 51.21875 764.1875 C 50.977922 764.1945 50.796875 764.2695 50.53125 764.5 L 48.21875 766.78125 L 45.9375 764.5 C 45.75987 764.31608 45.504951 764.1987 45.25 764.1875 C 45.23954 764.18704 45.22912 764.18738 45.21875 764.1875 L 44.21875 764.1875 z "
xlink:href="#path27279-0-5"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#bebebe;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.78124988;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter16524-9);enable-background:new;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
id="path16506-5"
inkscape:href="#path27279-0-5"
d="m 44.21875,764.1875 0,1 c -0.02191,0.28075 0.07051,0.55537 0.28125,0.75 l 2.28125,2.28125 -2.28125,2.25 c -0.18819,0.18817 -0.281253,0.45346 -0.28125,0.71875 l 0,1 1,0 c 0.26529,0 0.530586,-0.0931 0.71875,-0.28125 L 48.21875,769.625 50.5,771.90625 c 0.188164,0.18815 0.453449,0.28124 0.71875,0.28125 l 1,0 0,-1 c -8e-6,-0.2653 -0.09306,-0.53058 -0.28125,-0.71875 l -2.25,-2.25 2.28125,-2.28125 c 0.21566,-0.19935 0.25,-0.46353 0.25,-0.75 l 0,-1 -1,0 c -0.240828,0.007 -0.421875,0.082 -0.6875,0.3125 l -2.3125,2.28125 L 45.9375,764.5 c -0.17763,-0.18392 -0.432549,-0.3013 -0.6875,-0.3125 -0.01046,-4.6e-4 -0.02088,-1.2e-4 -0.03125,0 l -1,0 z"
transform="translate(0,1.3535534)" /><path
sodipodi:nodetypes="ccsccccccccccccccccccccccc"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#bebebe;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.78124988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
id="path27279-0-5"
inkscape:connector-curvature="0"
d="m 44.226475,764.17222 1,0 c 0.01037,-1.2e-4 0.02079,-4.6e-4 0.03125,0 0.254951,0.0112 0.50987,0.12858 0.6875,0.3125 l 2.28125,2.28125 2.3125,-2.28125 c 0.265625,-0.2305 0.446672,-0.3055 0.6875,-0.3125 l 1,0 0,1 c 0,0.28647 -0.03434,0.55065 -0.25,0.75 l -2.28125,2.28125 2.25,2.25 c 0.188188,0.18817 0.281242,0.45345 0.28125,0.71875 l 0,1 -1,0 c -0.265301,-1e-5 -0.530586,-0.0931 -0.71875,-0.28125 l -2.28125,-2.28125 -2.28125,2.28125 c -0.188164,0.18819 -0.45346,0.28125 -0.71875,0.28125 l -1,0 0,-1 c -3e-6,-0.26529 0.09306,-0.53058 0.28125,-0.71875 l 2.28125,-2.25 -2.28125,-2.28125 c -0.210742,-0.19463 -0.30316,-0.46925 -0.28125,-0.75 l 0,-1 z" /></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 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.48.1 r9760"
sodipodi:docname="filter-selected-ltr.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"
inkscape:pageshadow="2"
inkscape:zoom="5.5"
inkscape:cx="32.363636"
inkscape:cy="10.181818"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1440"
inkscape:window-height="839"
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></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 10.369085,54.181804 -10.55634072,10.55636 -1e-5,-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.7 KiB

View File

@ -34,13 +34,6 @@ stage {
color: rgba(0,0,0,0.5);
}
.label-real-shadow {
background-gradient-direction: horizontal;
background-gradient-start: rgba(0, 0, 0, 0);
background-gradient-end: rgba(0, 0, 0, 255);
width: 10px;
}
StScrollBar
{
padding: 0px;
@ -82,10 +75,10 @@ StScrollBar StButton#vhandle:hover
}
StTooltip StLabel {
border: 1px solid rgba(79,111,173,1);
border: 1px solid rgba(255,255,255,0.6);
border-radius: 5px;
padding: 4px;
background-color: rgba(79,111,173,0.9);
padding: 2px 12px;
background-color: rgba(0,0,0,0.9);
color: #ffffff;
font-size: 0.8em;
font-weight: normal;
@ -105,12 +98,40 @@ StTooltip StLabel {
.popup-menu {
color: #ffffff;
font-size: 14px;
font-size: 10.5pt;
min-width: 200px;
}
.popup-submenu-menu-item:open {
background-color: #4c4c4c;
}
.popup-sub-menu {
background-color: #606060;
background-gradient-start: rgba(80,80,80,0.3);
background-gradient-end: rgba(80,80,80,0.7);
background-gradient-direction: vertical;
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
}
.popup-sub-menu .popup-menu-item:ltr {
padding-right: 0em;
}
.popup-sub-menu .popup-menu-item:rtl {
padding-left: 0em;
}
.popup-sub-menu StScrollBar {
padding: 4px;
}
.popup-sub-menu StScrollBar StBin#trough {
border-width: 0px;
}
.popup-sub-menu StScrollBar StBin#vhandle {
background-color: #4c4c4c;
border-width: 0px;
}
/* The remaining popup-menu sizing is all done in ems, so that if you
@ -150,6 +171,8 @@ StTooltip StLabel {
-slider-height: 0.3em;
-slider-background-color: #333333;
-slider-border-color: #5f5f5f;
-slider-active-background-color: #76b0ec;
-slider-active-border-color: #1f6dbc;
-slider-border-width: 1px;
-slider-handle-radius: 0.5em;
}
@ -158,14 +181,22 @@ StTooltip StLabel {
spacing: .5em;
}
.popup-inactive-menu-item {
color: #999;
}
.popup-subtitle-menu-item {
font-weight: bold;
}
.popup-menu-icon {
icon-size: 1.14em;
}
/* Switches (to be used in menus) */
.toggle-switch {
width: 4.5em;
height: 1.5em;
width: 65px;
height: 22px;
}
.toggle-switch-us {
@ -182,13 +213,18 @@ StTooltip StLabel {
background-image: url("toggle-on-intl.svg");
}
.nm-menu-item-icons {
spacing: .5em;
}
/* Panel */
#panel {
color: #ffffff;
background-color: black;
border: 0px solid #536272;
border-bottom-width: 1px;
border-image: url("panel-border.svg") 1;
font-size: 10.5pt;
height: 1.86em;
}
#panelLeft, #panelCenter, #panelRight {
@ -196,21 +232,19 @@ StTooltip StLabel {
font-weight: bold;
}
#panelLeft {
#panelLeft:ltr {
padding-right: 4px;
}
#panelLeft:rtl {
padding-right: 0px;
padding-left: 4px;
}
#panelRight {
#panelRight:ltr {
padding-left: 4px;
}
#panelRight:rtl {
padding-left: 0px;
padding-right: 4px;
}
@ -233,6 +267,10 @@ StTooltip StLabel {
spacing: 4px;
}
.panel-button #appMenuIcon {
app-icon-bottom-clip: 1px;
}
.panel-button:active #appMenuIcon,
.panel-button:checked #appMenuIcon,
.panel-button:focus #appMenuIcon {
@ -246,12 +284,16 @@ StTooltip StLabel {
.panel-button {
padding: 0px 12px;
font-size: 14px;
font-weight: bold;
color: #ccc;
transition-duration: 100;
}
.panel-button:hover {
color: white;
text-shadow: black 0px 2px 2px;
}
.panel-button:active,
.panel-button:checked,
.panel-button:focus {
@ -294,6 +336,11 @@ StTooltip StLabel {
padding-left: 14px;
}
#legacyTray:rtl {
padding-left: 0px;
padding-right: 14px;
}
#legacyTray:compact {
spacing: 8px;
}
@ -309,7 +356,7 @@ StTooltip StLabel {
background-color: rgba(0,0,0,0.6);
}
.workspaces-view {
.window-caption {
color: white;
spacing: 25px;
}
@ -338,30 +385,34 @@ StTooltip StLabel {
.workspace-thumbnail-indicator {
outline: 2px solid white;
border: 1px solid #888;
}
.window-caption {
background: rgba(0,0,0,0.8);
border: 1px solid rgba(128,128,128,0.40);
border-radius: 10px;
font-size: 12px;
font-size: 9pt;
padding: 2px 8px;
-shell-caption-spacing: 4px;
}
.window-close {
background-image: url("close-window.svg");
height: 24px;
width: 24px;
-st-background-image-shadow: -2px 2px 6px rgba(0,0,0,0.5);
-shell-close-overlap: 16px;
height: 34px;
width: 34px;
-shell-close-overlap: 20px;
}
.window-close:rtl {
-st-background-image-shadow: 2px 2px 6px rgba(0,0,0,0.5);
}
/* Dash */
#dash {
color: #5f5f5f;
font-size: 12px;
font-size: 9pt;
padding: 4px 0px;
background-color: rgba(0, 0, 0, 0.5);
border: 1px solid rgba(128, 128, 128, 0.4);
@ -387,12 +438,12 @@ StTooltip StLabel {
}
#viewSelector {
spacing: 16px;
font-size: 16px;
spacing: 1em;
font-size: 12pt;
}
#viewSelectorTabBar {
padding: 16px;
padding: 1em;
}
#searchArea {
@ -440,8 +491,8 @@ StTooltip StLabel {
.view-tab-title {
color: #888a85;
font-weight: bold;
padding: 0px 12px;
height: 24px;
padding: 0px 0.75em;
height: 1.5em;
}
.view-tab-title:hover {
@ -451,26 +502,22 @@ StTooltip StLabel {
.view-tab-title:selected {
color: #000000;
background-color: #c2c7cd;
border-radius: 4px;
height: 24px;
}
.view-tab-boxpointer {
-arrow-border-radius: 9px;
-arrow-background-color: rgba(0,0,0,0.5);
-arrow-border-width: 2px;
-arrow-border-color: rgba(255,255,255,0.5);
-arrow-base: 30px;
-arrow-rise: 15px;
border-radius: 0.25em;
}
#searchResults {
padding: 20px 10px 10px 10px;
spacing: 18px;
}
#searchResultsContent {
padding: 0 10px;
spacing: 8px;
padding-right: 20px;
spacing: 36px;
}
#searchResultsContent:rtl {
padding-right: 0px;
padding-left: 20px;
}
.search-statustext,
@ -478,18 +525,11 @@ StTooltip StLabel {
padding: 4px 12px;
spacing: 4px;
color: #6f6f6f;
}
.search-section {
background-color: rgba(128, 128, 128, .1);
border: 1px solid rgba(50, 50, 50, .4);
border-radius: 10px;
font-size: .8em;
}
.search-section-results {
color: #ffffff;
border-radius: 10px;
border: 1px solid rgba(50, 50, 50, .4);
padding: 6px;
}
@ -502,17 +542,18 @@ StTooltip StLabel {
}
.search-providers-box {
spacing: 4px;
spacing: 12px;
}
.dash-search-button {
background-gradient-direction: vertical;
background-gradient-start: rgba(255, 255, 255, 0.2);
background-gradient-end: rgba(255, 255, 255, 0);
/* border: 1px solid #808080;*/
border-radius: 10px;
border: 1px solid #808080;
border-radius: 16px;
height: 32px;
width: 300px;
font-weight: bold;
}
.dash-search-button:selected,
@ -524,14 +565,18 @@ StTooltip StLabel {
.dash-search-button-label {
color: #cccccc;
font-size: 16px;
font-size: 12pt;
}
/* Apps */
.icon-grid {
spacing: 36px;
-shell-grid-item-size: 70px;
-shell-grid-item-size: 118px;
}
.icon-grid .overview-icon {
icon-size: 96px;
}
.all-app {
@ -539,29 +584,38 @@ StTooltip StLabel {
spacing: 20px;
}
.all-app .icon-grid {
-shell-grid-item-size: 118px;
.all-app:rtl {
padding-right: 16px;
padding-left: 25px;
}
.all-app .overview-icon {
icon-size: 96px;
}
.app-filter {
font-size: 14px;
font-size: 10.5pt;
font-weight: bold;
height: 40px;
height: 2.85em;
color: #aaa;
width: 200px;
}
.app-filter:hover {
color: #eee;
}
.app-filter:selected {
color: #ffffff;
background-image: url("filter-selected.svg");
background-image: url("filter-selected-ltr.svg");
background-position: 190px 10px;
}
.app-filter:selected:rtl {
background-image: url("filter-selected-rtl.svg");
background-position: 10px 10px;
}
.app-filter:focus {
outline: 1px solid #aaa;
}
.dash-item-container > .app-well-app {
padding: 4px 8px;
}
@ -579,8 +633,9 @@ StTooltip StLabel {
.remove-favorite > .overview-icon,
.search-result-content > .overview-icon {
border-radius: 4px;
padding: 4px;
font-size: 10px;
padding: 3px;
border: 1px rgba(0,0,0,0);
font-size: 7.5pt;
color: white;
transition-duration: 100;
text-align: center;
@ -604,8 +659,13 @@ StTooltip StLabel {
transition-duration: 100;
}
.app-well-app:focus > .overview-icon,
.search-result-content:focus > .overview-icon {
border: 1px solid #cccccc;
}
.app-well-menu {
font-size: 12px
font-size: 9pt;
}
/* LookingGlass */
@ -733,7 +793,7 @@ StTooltip StLabel {
#calendarArea {
/* this is the width of the entire popup */
width: 600px;
min-width: 600px;
}
.calendar-vertical-separator {
@ -761,7 +821,7 @@ StTooltip StLabel {
.calendar-month-label {
color: #666666;
font-size: 10px;
font-size: 7.5pt;
padding: 2px;
font-weight: bold;
}
@ -772,6 +832,11 @@ StTooltip StLabel {
background-image: url("calendar-arrow-left.svg");
border-radius: 4px;
}
.calendar-change-month-back:rtl {
background-image: url("calendar-arrow-right.svg");
}
.calendar-change-month-back:hover {
background-color: #999999;
}
@ -785,6 +850,11 @@ StTooltip StLabel {
background-image: url("calendar-arrow-right.svg");
border-radius: 4px;
}
.calendar-change-month-forward:rtl {
background-image: url("calendar-arrow-left.svg");
}
.calendar-change-month-forward:hover {
background-color: #999999;
}
@ -794,16 +864,16 @@ StTooltip StLabel {
.datemenu-date-label {
padding: .4em 1.75em;
font-size: 14px;
font-size: 10.5pt;
color: #cccccc;
font-weight: bold;
}
.calendar-day-base {
font-size: 10px;
font-size: 7.5pt;
text-align: center;
width: 24px;
height: 24px;
width: 2.4em;
height: 2.4em;
}
.calendar-day-base:hover {
@ -861,11 +931,13 @@ StTooltip StLabel {
}
.events-header-vbox {
spacing: 8px;
spacing: 6pt;
padding-right: 1.75em;
}
.events-header {
height: 40px;
.events-header-vbox:rtl {
padding-right: 0em;
padding-left: 1.75em;
}
.events-header-hbox {
@ -873,36 +945,54 @@ StTooltip StLabel {
}
.events-day-header {
font-size: 12px;
font-size: 9pt;
font-weight: bold;
color: rgba(153, 153, 153, 1.0);
padding-left: 0.3em;
}
.events-day-header:rtl {
padding-left: 0em;
padding-right: 0.3em;
}
.events-day-dayname {
font-size: 12px;
font-size: 9pt;
color: rgba(153, 153, 153, 1.0);
text-align: left;
}
.events-day-dayname:rtl {
text-align: right;
}
.events-day-time {
font-size: 12px;
font-size: 9pt;
color: #fff;
text-align: right;
}
.events-day-time:rtl {
text-align: left;
}
.events-day-task {
font-size: 12px;
font-size: 9pt;
color: rgba(153, 153, 153, 1.0);
}
.events-day-name-box {
width: 20px;
min-width: 15pt;
}
.events-time-box {
width: 70px;
padding-right: 8px;
min-width: 53pt;
padding-right: 6pt;
}
.events-time-box:rtl {
padding-right: 0px;
padding-left: 6pt;
}
.events-event-box {
@ -916,13 +1006,13 @@ StTooltip StLabel {
#message-tray {
background-gradient-direction: vertical;
background-gradient-start: rgba(0,0,0,0.01);
background-gradient-end: rgba(0,0,0,0.95);
background-gradient-end: rgba(0,0,0,0.82);
height: 36px;
color: white;
}
#notification {
font-size: 16px;
font-size: 12pt;
border-radius: 5px 5px 0px 0px;
background: rgba(0,0,0,0.9);
padding: 8px 8px 4px 8px;
@ -935,7 +1025,7 @@ StTooltip StLabel {
padding-bottom: 8px;
}
.summary-notification-boxpointer {
.summary-boxpointer {
-arrow-border-radius: 9px;
-arrow-background-color: rgba(0,0,0,0.9);
-arrow-border-width: 2px;
@ -944,12 +1034,36 @@ StTooltip StLabel {
-arrow-rise: 15px;
}
.summary-notification-boxpointer #notification {
.summary-boxpointer #notification {
border-radius: 9px;
background: rgba(0,0,0,0) !important;
padding-bottom: 12px;
}
.summary-boxpointer #summary-right-click-menu {
font-size: 10.5pt;
padding-top: 12px;
padding-bottom: 12px;
}
#summary-notification-stack-scrollview {
max-height: 18em;
padding-top: 6px;
padding-bottom: 6px;
}
#summary-notification-stack-scrollview > .top-shadow, #summary-notification-stack-scrollview > .bottom-shadow {
height: 1em;
}
#summary-notification-stack-scrollview:ltr {
padding-right: 8px;
}
#summary-notification-stack-scrollview:rtl {
padding-left: 8px;
}
#notification-scrollview {
max-height: 10em;
}
@ -958,10 +1072,14 @@ StTooltip StLabel {
height: 1em;
}
#notification-scrollview > StScrollBar {
#notification-scrollview:ltr > StScrollBar {
padding-left: 6px;
}
#notification-scrollview:rtl > StScrollBar {
padding-right: 6px;
}
#notification-body {
spacing: 5px;
}
@ -1012,6 +1130,10 @@ StTooltip StLabel {
icon-size: 36px;
}
.chat-log-message {
color: #888888;
}
.chat-received {
background-gradient-direction: horizontal;
background-gradient-start: rgba(255, 255, 255, 0.2);
@ -1021,6 +1143,11 @@ StTooltip StLabel {
border-radius: 4px;
}
.chat-received:rtl {
padding-left: 0px;
padding-right: 4px;
}
.chat-sent {
background-gradient-direction: horizontal;
background-gradient-start: rgba(255, 255, 255, 0);
@ -1030,13 +1157,23 @@ StTooltip StLabel {
border-radius: 4px;
}
.chat-sent:rtl {
padding-left: 0px;
padding-right: 4px;
}
.chat-meta-message {
padding-left: 4px;
border-radius: 4px;
font-size: 14px;
font-size: 10.5pt;
color: #bbbbbb;
}
.chat-meta-message:rtl {
padding-left: 0px;
padding-right: 4px;
}
#notification StEntry {
padding: 4px;
border-radius: 4px;
@ -1073,21 +1210,62 @@ StTooltip StLabel {
height: 36px;
}
.summary-source-button {
padding-left: 4px;
padding-right: 16px;
#summary-mode:rtl {
padding: 2px 4px 0px 0px;
}
.summary-source-button:last-child {
.summary-source-button {
color: #fff;
text-shadow: black 0px 2px 2px;
}
.summary-source-button:ltr {
padding-right: 12px;
}
.summary-source-button:selected .summary-source {
background-image: url("panel-button-highlight-narrow.svg");
border-image: url("source-button-border.svg") 10 10 0 1;
}
.summary-source-button:expanded:selected .summary-source {
background-image: none;
border-image: none;
}
.summary-source-button:expanded:selected {
background-image: url("panel-button-highlight-wide.svg");
border-image: url("source-button-border.svg") 10 10 0 1;
}
.summary-source-button:rtl {
padding-left: 12px;
}
.summary-source-button:last-child:ltr {
padding-right: 12px;
}
.summary-source-button:last-child:rtl {
padding-left: 12px;
}
.summary-source {
padding-right: 4px;
padding-left: 4px;
}
.source-title {
font-size: 12px;
font-size: 9pt;
font-weight: bold;
padding-left: 4px;
}
.source-title:rtl {
padding-left: 0px;
padding-right: 4px;
}
/* App Switcher */
#altTabPopup {
padding: 8px;
@ -1100,7 +1278,7 @@ StTooltip StLabel {
border-radius: 24px;
padding: 20px;
font-size: 12px;
font-size: 9pt;
color: white;
}
@ -1159,7 +1337,11 @@ StTooltip StLabel {
.ripple-box {
width: 52px;
height: 52px;
background-image: url("corner-ripple.png");
background-image: url("corner-ripple-ltr.png");
}
.ripple-box:rtl {
background-image: url("corner-ripple-rtl.png");
}
.switcher-arrow {
@ -1229,10 +1411,14 @@ StTooltip StLabel {
padding-top: 30px;
}
.modal-dialog-button-box {
spacing: 21px;
}
.modal-dialog-button {
border: 1px solid #8b8b8b;
border-radius: 18px;
font-size: 14px;
font-size: 10.5pt;
margin-left: 10px;
margin-right: 10px;
@ -1265,12 +1451,12 @@ StTooltip StLabel {
/* Run Dialog */
.run-dialog-label {
font-size: 12px;
font-size: 9pt;
color: white;
}
.run-dialog-error-label {
font-size: 12px;
font-size: 9pt;
color: white;
}
@ -1280,9 +1466,9 @@ StTooltip StLabel {
}
.run-dialog-entry {
font-size: 14px;
font-size: 10.5pt;
font-weight: bold;
width: 320px;
width: 23em;
color: white;
}
@ -1300,6 +1486,10 @@ StTooltip StLabel {
}
/* End Session Dialog */
.end-session-dialog {
spacing: 42px;
}
.end-session-dialog-subject {
font-size: 12pt;
font-weight: bold;
@ -1309,12 +1499,20 @@ StTooltip StLabel {
padding-bottom: 30px;
}
.end-session-dialog-subject:rtl {
padding-left: 0px;
padding-right: 17px;
}
.end-session-dialog-description {
font-size: 10pt;
color: white;
padding-left: 17px;
padding-right: 40px;
width: 16em;
width: 28em;
}
.end-session-dialog-description:rtl {
padding-right: 17px;
}
.end-session-dialog-logout-icon {
@ -1333,19 +1531,39 @@ StTooltip StLabel {
font-size: 10pt;
max-height: 200px;
padding-top: 42px;
padding-bottom: 42px;
padding-left: 17px;
padding-left: 49px;
padding-right: 32px;
}
.end-session-dialog-app-list:rtl {
padding-right: 49px;
padding-left: 32px;
}
.end-session-dialog-app-list-item {
color: #ccc;
}
.end-session-dialog-app-list-item:hover {
color: white;
}
.end-session-dialog-app-list-item:ltr {
padding-right: 1em;
}
.end-session-dialog-app-list-item-icon {
.end-session-dialog-app-list-item:rtl {
padding-left: 1em;
}
.end-session-dialog-app-list-item-icon:ltr {
padding-right: 17px;
}
.end-session-dialog-app-list-item-icon:rtl {
padding-left: 17px;
}
.end-session-dialog-app-list-item-name {
font-size: 10pt;
}
@ -1362,12 +1580,12 @@ StTooltip StLabel {
}
.polkit-dialog-main-layout {
spacing: 10px;
spacing: 24px;
padding: 10px;
}
.polkit-dialog-message-layout {
spacing: 10px;
spacing: 16px;
}
.polkit-dialog-headline {
@ -1386,10 +1604,23 @@ StTooltip StLabel {
spacing: 10px;
}
.polkit-dialog-password-label {
.polkit-dialog-user-layout:rtl {
padding-left: 0px;
padding-right: 10px;
}
.polkit-dialog-user-root-label {
color: #ff0000;
}
.polkit-dialog-password-label:ltr {
padding-right: 0.5em;
}
.polkit-dialog-password-label:rtl {
padding-left: 0.5em;
}
.polkit-dialog-password-entry {
background-color: white;
color: black;
@ -1397,33 +1628,21 @@ StTooltip StLabel {
}
.polkit-dialog-error-label {
font-size: 12px;
color: white;
}
.polkit-dialog-error-box {
padding-top: 15px;
spacing: 5px;
}
.polkit-dialog-checking-label {
font-size: 12px;
color: white;
}
.polkit-dialog-checking-box {
padding-top: 15px;
spacing: 5px;
font-size: 10pt;
color: #ffff00;
padding-bottom: 8px;
}
.polkit-dialog-info-label {
font-size: 12px;
color: white;
font-size: 10pt;
padding-bottom: 8px;
}
.polkit-dialog-info-box {
padding-top: 15px;
spacing: 5px;
/* intentionally left transparent to avoid dialog changing size */
.polkit-dialog-null-label {
font-size: 10pt;
color: rgba(0,0,0,0);
padding-bottom: 8px;
}

View File

@ -0,0 +1,33 @@
<?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"
width="3"
height="10"
id="svg2"
version="1.1">
<defs
id="defs4" />
<metadata
id="metadata7">
</metadata>
<g
id="layer1">
<rect
style="fill:#000000;fill-opacity:1;stroke-width:0.43599999000000000;stroke-miterlimit:4;stroke-dasharray:none"
id="rect3779"
width="3"
height="10"
x="0"
y="0" />
<rect
style="fill:#536272;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
id="rect3796"
width="3"
height="1"
x="0"
y="9" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,261 @@
<?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"
id="svg5369"
version="1.1"
inkscape:version="0.48+devel r10053 custom"
width="96"
height="48"
sodipodi:docname="process-working.svg"
style="display:inline">
<metadata
id="metadata5375">
<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>
<defs
id="defs5373" />
<sodipodi:namedview
pagecolor="#808080"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1975"
inkscape:window-height="1098"
id="namedview5371"
showgrid="true"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:zoom="16"
inkscape:cx="53.997662"
inkscape:cy="22.367695"
inkscape:window-x="1600"
inkscape:window-y="33"
inkscape:window-maximized="0"
inkscape:current-layer="layer2">
<inkscape:grid
type="xygrid"
id="grid11933"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="tiles"
style="display:none">
<rect
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect12451"
width="24"
height="24"
x="0"
y="0" />
<rect
y="24"
x="0"
height="24"
width="24"
id="rect12453"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
y="0"
x="24"
height="24"
width="24"
id="rect12455"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect12457"
width="24"
height="24"
x="24"
y="24" />
<rect
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect12459"
width="24"
height="24"
x="48"
y="0" />
<rect
y="24"
x="48"
height="24"
width="24"
id="rect12461"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
y="0"
x="72"
height="24"
width="24"
id="rect12463"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect12465"
width="24"
height="24"
x="72"
y="24" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="spinner">
<g
transform="matrix(0.28240106,0,0,0.28240106,146.92015,-382.52444)"
id="g10450-5"
style="display:inline">
<path
inkscape:connector-curvature="0"
style="opacity:0.6;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m -477.76072,1373.3569 0,9.4717"
id="path18768"
sodipodi:nodetypes="cc"
inkscape:transform-center-y="-4.6808838" />
<path
inkscape:connector-curvature="0"
inkscape:transform-center-y="-3.3099227"
sodipodi:nodetypes="cc"
id="path18770"
d="m -461.0171,1380.2922 -7.23427,7.3824"
style="opacity:0.7;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:transform-center-x="-3.3098966" />
<path
inkscape:connector-curvature="0"
inkscape:transform-center-x="-4.6808962"
style="opacity:0.8;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m -454.08163,1397.0359 -9.47165,0"
id="path18772"
sodipodi:nodetypes="cc"
inkscape:transform-center-y="-2.6596956e-05" />
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc"
id="path18774"
d="m -461.01709,1413.7796 -6.93831,-7.0864"
style="opacity:0.9;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:transform-center-x="-3.3098966"
inkscape:transform-center-y="3.3098652" />
<path
inkscape:connector-curvature="0"
inkscape:transform-center-y="4.6808757"
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m -477.76074,1420.715 9e-5,-9.4716"
id="path18776"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc"
id="path18778"
d="m -494.50442,1413.7796 6.79048,-6.9384"
style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:transform-center-y="3.3098769"
inkscape:transform-center-x="3.3098883" />
<path
inkscape:connector-curvature="0"
inkscape:transform-center-x="4.6808941"
style="opacity:0.4;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m -501.43987,1397.0359 9.47174,0"
id="path18780"
sodipodi:nodetypes="cc"
inkscape:transform-center-y="-2.6596956e-05" />
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc"
id="path18782"
d="m -494.5044,1380.2922 6.64243,6.9384"
style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:transform-center-x="3.3098902"
inkscape:transform-center-y="-3.3099302" />
</g>
<use
style="display:inline"
x="0"
y="0"
xlink:href="#g10450-5"
id="use4981"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,36,-4.9705636)"
width="400"
height="400" />
<use
style="display:inline"
x="0"
y="0"
xlink:href="#use4981"
id="use4983"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,43.032478,-21.909695)"
width="400"
height="400" />
<use
style="display:inline"
x="0"
y="0"
xlink:href="#use4983"
id="use4985"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,50.081986,-38.904617)"
width="400"
height="400" />
<use
style="display:inline"
x="0"
y="0"
xlink:href="#use4985"
id="use4987"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,-38.919996,-31.872139)"
width="400"
height="400" />
<use
style="display:inline"
x="0"
y="0"
xlink:href="#use4987"
id="use4989"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,52.986628,2.0890543)"
width="400"
height="400" />
<use
style="display:inline"
x="0"
y="0"
xlink:href="#use4989"
id="use4991"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,60.013026,-14.912936)"
width="400"
height="400" />
<use
style="display:inline"
x="0"
y="0"
xlink:href="#use4991"
id="use4993"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,67.022396,-31.859127)"
width="400"
height="400" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -0,0 +1,74 @@
<?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="21"
height="10"
id="svg2"
version="1.1"
inkscape:version="0.48.0 r9654"
sodipodi:docname="source-button-border.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="44.8"
inkscape:cx="8.704132"
inkscape:cy="5.7029946"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1600"
inkscape:window-height="1145"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1"
guidetolerance="10000"
objecttolerance="10000">
<inkscape:grid
type="xygrid"
id="grid3792"
empspacing="10"
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">
<rect
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
id="rect3796"
width="19"
height="2"
x="1"
y="8" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -6,6 +6,22 @@
<name xml:lang="en">GNOME Shell</name>
<shortdesc xml:lang="en">Next generation GNOME desktop shell</shortdesc>
<description>GNOME Shell provides core user interface functions for the GNOME 3
desktop, like switching to windows and launching applications.
GNOME Shell takes advantage of the capabilities of modern graphics
hardware and introduces innovative user interface concepts to
provide a visually attractive and easy to use experience.
Tarball releases are provided largely for distributions to build
packages. If you are interested in building GNOME Shell from source,
we would recommend building from version control using the build
script described at:
http://live.gnome.org/GnomeShell
Not only will that give you the very latest version of this rapidly
changing project, it will be much easier than get GNOME Shell and
its dependencies to build from tarballs.</description>
<!--
<homepage rdf:resource="http://live.gnome.org/GnomeShell" />
-->

View File

@ -8,6 +8,7 @@ nobase_dist_js_DATA = \
misc/format.js \
misc/gnomeSession.js \
misc/history.js \
misc/modemManager.js \
misc/params.js \
misc/util.js \
perf/core.js \
@ -50,6 +51,7 @@ nobase_dist_js_DATA = \
ui/statusMenu.js \
ui/status/accessibility.js \
ui/status/keyboard.js \
ui/status/network.js \
ui/status/power.js \
ui/status/volume.js \
ui/status/bluetooth.js \

View File

@ -7,7 +7,8 @@ const Signals = imports.signals;
const PresenceIface = {
name: 'org.gnome.SessionManager.Presence',
methods: [{ name: 'SetStatus',
inSignature: 'u' }],
inSignature: 'u',
outSignature: '' }],
properties: [{ name: 'status',
signature: 'u',
access: 'readwrite' }],
@ -101,3 +102,24 @@ Inhibitor.prototype = {
};
DBus.proxifyPrototype(Inhibitor.prototype, InhibitorIface);
Signals.addSignalMethods(Inhibitor.prototype);
// Not the full interface, only the methods we use
const SessionManagerIface = {
name: 'org.gnome.SessionManager',
methods: [
{ name: 'Logout', inSignature: 'u', outSignature: '' },
{ name: 'Shutdown', inSignature: '', outSignature: '' }
]
};
function SessionManager() {
this._init();
}
SessionManager.prototype = {
_init: function() {
DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager');
}
};
DBus.proxifyPrototype(SessionManager.prototype, SessionManagerIface);

View File

@ -2,22 +2,40 @@
const Lang = imports.lang;
const Signals = imports.signals;
const Clutter = imports.gi.Clutter;
const Params = imports.misc.params;
const DEFAULT_LIMIT = 512;
function HistoryManager(settings_key) {
this._init(settings_key);
function HistoryManager(params) {
this._init(params);
}
HistoryManager.prototype = {
_init: function(settings_key, limit) {
this._limit = limit || DEFAULT_LIMIT;
this._key = settings_key;
this._history = global.settings.get_strv(settings_key);
this._historyIndex = -1;
_init: function(params) {
params = Params.parse(params, { gsettingsKey: null,
limit: DEFAULT_LIMIT,
entry: null });
global.settings.connect('changed::' + settings_key,
Lang.bind(this, this._historyChanged));
this._key = params.gsettingsKey;
this._limit = params.limit;
this._historyIndex = 0;
if (this._key) {
this._history = global.settings.get_strv(this._key);
global.settings.connect('changed::' + this._key,
Lang.bind(this, this._historyChanged));
} else {
this._history = [];
}
this._entry = params.entry;
if (this._entry) {
this._entry.connect('key-press-event',
Lang.bind(this, this._onEntryKeyPress));
}
},
_historyChanged: function() {
@ -26,18 +44,32 @@ HistoryManager.prototype = {
},
prevItem: function(text) {
this._setHistory(this._historyIndex--, text);
if (this._historyIndex <= 0)
return text;
if (text)
this._history[this._historyIndex] = text;
this._historyIndex--;
return this._indexChanged();
},
nextItem: function(text) {
this._setHistory(this._historyIndex++, text);
if (this._historyIndex >= this._history.length)
return text;
if (text)
this._history[this._historyIndex] = text;
this._historyIndex++;
return this._indexChanged();
},
lastItem: function() {
this._historyIndex = this._history.length;
return this._indexChanged();
if (this._historyIndex != this._history.length) {
this._historyIndex = this._history.length;
this._indexChanged();
}
return this._historyIndex[this._history.length];
},
addItem: function(input) {
@ -45,28 +77,39 @@ HistoryManager.prototype = {
this._history[this._history.length - 1] != input) {
this._history.push(input);
this._historyIndex = this._history.length;
this._save();
}
},
_onEntryKeyPress: function(entry, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Up) {
this.prevItem(entry.get_text());
return true;
} else if (symbol == Clutter.KEY_Down) {
this.nextItem(entry.get_text());
return true;
}
return false;
},
_indexChanged: function() {
let current = this._history[this._historyIndex] || '';
this.emit('changed', current);
if (this._entry)
this._entry.set_text(current);
return current;
},
_setHistory: function(index, text) {
this._historyIndex = Math.max(this._historyIndex, 0);
this._historyIndex = Math.min(this._historyIndex, this._history.length);
if (text)
this._history[index] = text;
},
_save: function() {
if (this._history.length > this._limit)
this._history.splice(0, this._history.length - this._key);
global.settings.set_strv(this._key, this._history);
this._history.splice(0, this._history.length - this._limit);
if (this._key)
global.settings.set_strv(this._key, this._history);
}
};
Signals.addSignalMethods(HistoryManager.prototype);

225
js/misc/modemManager.js Normal file
View File

@ -0,0 +1,225 @@
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
const DBus = imports.dbus;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
// The following are not the complete interfaces, just the methods we need
// (or may need in the future)
const ModemGsmNetworkInterface = {
name: 'org.freedesktop.ModemManager.Modem.Gsm.Network',
methods: [
{ name: 'GetRegistrationInfo', inSignature: '', outSignature: 'uss' },
{ name: 'GetSignalQuality', inSignature: '', outSignature: 'u' }
],
properties: [
{ name: 'AccessTechnology', signature: 'u', access: 'read' }
],
signals: [
{ name: 'SignalQuality', inSignature: 'u' },
{ name: 'RegistrationInfo', inSignature: 'uss' }
]
};
const ModemGsmNetworkProxy = DBus.makeProxyClass(ModemGsmNetworkInterface);
const ModemCdmaInterface = {
name: 'org.freedesktop.ModemManager.Modem.Cdma',
methods: [
{ name: 'GetSignalQuality', inSignature: '', outSignature: 'u' },
{ name: 'GetServingSystem', inSignature: '', outSignature: 'usu' }
],
signals: [
{ name: 'SignalQuality', inSignature: 'u' }
]
};
const ModemCdmaProxy = DBus.makeProxyClass(ModemCdmaInterface);
let _providersTable;
function _getProvidersTable() {
if (_providersTable)
return _providersTable;
let [providers, countryCodes] = Shell.mobile_providers_parse();
return _providersTable = providers;
}
function ModemGsm() {
this._init.apply(this, arguments);
}
ModemGsm.prototype = {
_init: function(path) {
this._proxy = new ModemGsmNetworkProxy(DBus.system, 'org.freedesktop.ModemManager', path);
this.signal_quality = 0;
this.operator_name = null;
// Code is duplicated because the function have different signatures
this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) {
this.signal_quality = quality;
this.emit('notify::signal-quality');
}));
this._proxy.connect('RegistrationInfo', Lang.bind(this, function(proxy, status, code, name) {
this.operator_name = this._findOperatorName(name, code);
this.emit('notify::operator-name');
}));
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function(result, err) {
if (err) {
log(err);
return;
}
let [status, code, name] = result;
this.operator_name = this._findOperatorName(name, code);
this.emit('notify::operator-name');
}));
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
if (err) {
// it will return an error if the device is not connected
this.signal_quality = 0;
} else {
let [quality] = result;
this.signal_quality = quality;
}
this.emit('notify::signal-quality');
}));
},
_findOperatorName: function(name, opCode) {
if (name.length != 0 && (name.length > 6 || name.length < 5)) {
// this looks like a valid name, i.e. not an MCCMNC (that some
// devices return when not yet connected
return name;
}
if (isNaN(parseInt(name))) {
// name is definitely not a MCCMNC, so it may be a name
// after all; return that
return name;
}
let needle;
if (name.length == 0 && opCode)
needle = opCode;
else if (name.length == 6 || name.length == 5)
needle = name;
else // nothing to search
return null;
return this._findProviderForMCCMNC(needle);
},
_findProviderForMCCMNC: function(needle) {
let table = _getProvidersTable();
let needlemcc = needle.substring(0, 3);
let needlemnc = needle.substring(3, needle.length);
let name2, name3;
for (let iter in table) {
let providers = table[iter];
// Search through each country's providers
for (let i = 0; i < providers.length; i++) {
let provider = providers[i];
// Search through MCC/MNC list
let list = provider.get_gsm_mcc_mnc();
for (let j = 0; j < list.length; j++) {
let mccmnc = list[j];
// Match both 2-digit and 3-digit MNC; prefer a
// 3-digit match if found, otherwise a 2-digit one.
if (mccmnc.mcc != needlemcc)
continue; // MCC was wrong
if (!name3 && needle.length == 6 && needlemnc == mccmnc.mnc)
name3 = provider.name;
if (!name2 && needlemnc.substring(0, 2) == mccmnc.mnc.substring(0, 2))
name2 = provider.name;
if (name2 && name3)
break;
}
}
}
return name3 || name2 || null;
}
}
Signals.addSignalMethods(ModemGsm.prototype);
function ModemCdma() {
this._init.apply(this, arguments);
}
ModemCdma.prototype = {
_init: function(path) {
this._proxy = new ModemCdmaProxy(DBus.system, 'org.freedesktop.ModemManager', path);
this.signal_quality = 0;
this.operator_name = null;
this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) {
this.signal_quality = quality;
this.emit('notify::signal-quality');
// receiving this signal means the device got activated
// and we can finally call GetServingSystem
if (this.operator_name == null)
this._refreshServingSystem();
}));
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
if (err) {
// it will return an error if the device is not connected
this.signal_quality = 0;
} else {
let [quality] = result;
this.signal_quality = quality;
}
this.emit('notify::signal-quality');
}));
},
_refreshServingSystem: function() {
this._proxy.GetServingSystemRemote(Lang.bind(this, function(result, err) {
if (err) {
// it will return an error if the device is not connected
this.operator_name = null;
} else {
let [bandClass, band, id] = result;
if (name.length > 0)
this.operator_name = this._findProviderForSid(id);
else
this.operator_name = null;
}
this.emit('notify::operator-name');
}));
},
_findProviderForSid: function(sid) {
if (sid == 0)
return null;
let table = _getProvidersTable();
// Search through each country
for (let iter in table) {
let providers = table[iter];
// Search through each country's providers
for (let i = 0; i < providers.length; i++) {
let provider = providers[i];
let cdma_sid = provider.get_cdma_sid();
// Search through CDMA SID list
for (let j = 0; j < cdma_sid.length; j++) {
if (cdma_sid[j] == sid)
return provider.name;
}
}
}
return null;
}
};
Signals.addSignalMethods(ModemCdma.prototype);

View File

@ -6,7 +6,6 @@ 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;
@ -56,20 +55,6 @@ function spawnCommandLine(command_line) {
}
}
// 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
//
@ -117,41 +102,9 @@ function trySpawnCommandLine(command_line) {
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);
Main.notifyError(title, err.message);
}
// killall:
@ -178,3 +131,83 @@ function killall(processName) {
logError(e, 'Failed to kill ' + processName);
}
}
// This was ported from network-manager-applet
// Copyright 2007 - 2011 Red Hat, Inc.
// Author: Dan Williams <dcbw@redhat.com>
const _IGNORED_WORDS = [
'Semiconductor',
'Components',
'Corporation',
'Communications',
'Company',
'Corp.',
'Corp',
'Co.',
'Inc.',
'Inc',
'Incorporated',
'Ltd.',
'Limited.',
'Intel?',
'chipset',
'adapter',
'[hex]',
'NDIS',
'Module'
];
const _IGNORED_PHRASES = [
'Multiprotocol MAC/baseband processor',
'Wireless LAN Controller',
'Wireless LAN Adapter',
'Wireless Adapter',
'Network Connection',
'Wireless Cardbus Adapter',
'Wireless CardBus Adapter',
'54 Mbps Wireless PC Card',
'Wireless PC Card',
'Wireless PC',
'PC Card with XJACK(r) Antenna',
'Wireless cardbus',
'Wireless LAN PC Card',
'Technology Group Ltd.',
'Communication S.p.A.',
'Business Mobile Networks BV',
'Mobile Broadband Minicard Composite Device',
'Mobile Communications AB',
'(PC-Suite Mode)'
];
function fixupPCIDescription(desc) {
desc.replace(/[_,]/, ' ');
/* Attempt to shorten ID by ignoring certain phrases */
for (let i = 0; i < _IGNORED_PHRASES.length; i++) {
let item = _IGNORED_PHRASES[i];
let pos = desc.indexOf(item);
if (pos != -1) {
let before = desc.substring(0, pos);
let after = desc.substring(pos + item.length, desc.length);
desc = before + after;
}
}
/* Attmept to shorten ID by ignoring certain individual words */
let words = desc.split(' ');
let out = [ ];
for (let i = 0; i < words; i++) {
let item = words[i];
// skip empty items (that come out from consecutive spaces)
if (item.length == 0)
continue;
if (_IGNORED_WORDS.indexOf(item) == -1) {
out.push(item);
}
}
return out.join(' ');
}

View File

@ -21,26 +21,77 @@ let METRICS = {
overviewFpsSubsequent:
{ description: "Frames rate when going to the overview, second time",
units: "frames / s" },
overviewFps5Windows:
{ description: "Frames rate when going to the overview, 5 windows open",
units: "frames / s" },
overviewFps10Windows:
{ description: "Frames rate when going to the overview, 10 windows open",
units: "frames / s" },
overviewFps5Maximized:
{ description: "Frames rate when going to the overview, 5 maximized windows open",
units: "frames / s" },
overviewFps10Maximized:
{ description: "Frames rate when going to the overview, 10 maximized windows open",
units: "frames / s" },
overviewFps5Alpha:
{ description: "Frames rate when going to the overview, 5 alpha-transparent windows open",
units: "frames / s" },
overviewFps10Alpha:
{ description: "Frames rate when going to the overview, 10 alpha-transparent windows open",
units: "frames / s" },
usedAfterOverview:
{ description: "Malloc'ed bytes after the overview is shown once",
units: "B" },
leakedAfterOverview:
{ description: "Additional malloc'ed bytes the second time the overview is shown",
units: "B" }
units: "B" },
applicationsShowTimeFirst:
{ description: "Time to switch to applications view, first time",
units: "us" },
applicationsShowTimeSubsequent:
{ description: "Time to switch to applications view, second time",
units: "us"}
};
let WINDOW_CONFIGS = [
{ width: 640, height: 480, alpha: false, maximized: false, count: 1, metric: 'overviewFpsSubsequent' },
{ width: 640, height: 480, alpha: false, maximized: false, count: 5, metric: 'overviewFps5Windows' },
{ width: 640, height: 480, alpha: false, maximized: false, count: 10, metric: 'overviewFps10Windows' },
{ width: 640, height: 480, alpha: false, maximized: true, count: 5, metric: 'overviewFps5Maximized' },
{ width: 640, height: 480, alpha: false, maximized: true, count: 10, metric: 'overviewFps10Maximized' },
{ width: 640, height: 480, alpha: true, maximized: false, count: 5, metric: 'overviewFps5Alpha' },
{ width: 640, height: 480, alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha' }
];
function run() {
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview");
Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
Main.overview.connect('shown', function() {
Scripting.scriptEvent('overviewShowDone');
});
yield Scripting.sleep(1000);
yield Scripting.waitLeisure();
for (let i = 0; i < 2; i++) {
for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) {
// We go to the overview twice for each configuration; the first time
// to calculate the mipmaps for the windows, the second time to get
// a clean set of numbers.
if ((i % 2) == 0) {
let config = WINDOW_CONFIGS[i / 2];
yield Scripting.destroyTestWindows();
for (let k = 0; k < config.count; k++)
yield Scripting.createTestWindow(config.width, config.height, config.alpha, config.maximized);
yield Scripting.waitTestWindows();
yield Scripting.sleep(1000);
yield Scripting.waitLeisure();
}
Scripting.scriptEvent('overviewShowStart');
Main.overview.show();
@ -53,6 +104,21 @@ function run() {
Scripting.collectStatistics();
Scripting.scriptEvent('afterShowHide');
}
yield Scripting.destroyTestWindows();
yield Scripting.sleep(1000);
Main.overview.show();
yield Scripting.waitLeisure();
for (let i = 0; i < 2; i++) {
Scripting.scriptEvent('applicationsShowStart');
Main.overview.viewSelector.switchTab('applications');
yield Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone');
Main.overview.viewSelector.switchTab('windows');
yield Scripting.waitLeisure();
}
}
let showingOverview = false;
@ -64,6 +130,8 @@ let mallocUsedSize = 0;
let overviewShowCount = 0;
let firstOverviewUsedSize;
let haveSwapComplete = false;
let applicationsShowStart;
let applicationsShowCount = 0;
function script_overviewShowStart(time) {
showingOverview = true;
@ -79,6 +147,18 @@ function script_overviewShowDone(time) {
finishedShowingOverview = true;
}
function script_applicationsShowStart(time) {
applicationsShowStart = time;
}
function script_applicationsShowDone(time) {
applicationsShowCount++;
if (applicationsShowCount == 1)
METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart;
else
METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart;
}
function script_afterShowHide(time) {
if (overviewShowCount == 1) {
METRICS.usedAfterOverview.value = mallocUsedSize;
@ -113,9 +193,15 @@ function _frameDone(time) {
if (overviewShowCount == 1) {
METRICS.overviewLatencyFirst.value = overviewLatency;
METRICS.overviewFpsFirst.value = fps;
} else {
} else if (overviewShowCount == 2) {
METRICS.overviewLatencySubsequent.value = overviewLatency;
METRICS.overviewFpsSubsequent.value = fps;
}
// Other than overviewFpsFirst, we collect FPS metrics the second
// we show each window configuration. overviewShowCount is 1,2,3...
if (overviewShowCount % 2 == 0) {
let config = WINDOW_CONFIGS[(overviewShowCount / 2) - 1];
METRICS[config.metric].value = fps;
}
}
}

View File

@ -87,7 +87,7 @@ AltTabPopup.prototype = {
let [childMinHeight, childNaturalHeight] = this._appSwitcher.actor.get_preferred_height(primary.width - hPadding);
let [childMinWidth, childNaturalWidth] = this._appSwitcher.actor.get_preferred_width(childNaturalHeight);
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
childBox.x2 = Math.min(childBox.x1 + primary.width - hPadding, childBox.x1 + childNaturalWidth);
childBox.x2 = Math.min(primary.x + primary.width - hPadding, childBox.x1 + childNaturalWidth);
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._appSwitcher.actor.allocate(childBox, flags);
@ -376,7 +376,15 @@ AltTabPopup.prototype = {
this.destroy();
},
_popModal: function() {
if (this._haveModal) {
Main.popModal(this.actor);
this._haveModal = false;
}
},
destroy : function() {
this._popModal();
if (this.actor.visible) {
Tweener.addTween(this.actor,
{ opacity: 0,
@ -392,8 +400,7 @@ AltTabPopup.prototype = {
},
_onDestroy : function() {
if (this._haveModal)
Main.popModal(this.actor);
this._popModal();
if (this._thumbnails)
this._destroyThumbnails();
@ -820,7 +827,7 @@ AppIcon.prototype = {
this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
vertical: true });
this.icon = null;
this._iconBin = new St.Bin();
this._iconBin = new St.Bin({ x_fill: true, y_fill: true });
this.actor.add(this._iconBin, { x_fill: false, y_fill: false } );
this.label = new St.Label({ text: this.app.get_name() });

View File

@ -1,6 +1,7 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
@ -22,6 +23,7 @@ const Workspace = imports.ui.workspace;
const Params = imports.misc.params;
const MENU_POPUP_TIMEOUT = 600;
const SCROLL_TIME = 0.1;
function AlphabeticalView() {
this._init();
@ -66,6 +68,7 @@ AlphabeticalView.prototype = {
let appIcon = new AppWellIcon(this._appSystem.get_app(appInfo.get_id()));
this._grid.addItem(appIcon.actor);
appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
appIcon._appInfo = appInfo;
if (this._filterApp && !this._filterApp(appInfo))
@ -74,6 +77,32 @@ AlphabeticalView.prototype = {
this._apps.push(appIcon);
},
_ensureIconVisible: function(icon) {
let adjustment = this.actor.vscroll.adjustment;
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let offset = 0;
let vfade = this.actor.get_effect("vfade");
if (vfade)
offset = vfade.fade_offset;
// If this gets called as part of a right-click, the actor
// will be needs_allocation, and so "icon.y" would return 0
let box = icon.get_allocation_box();
if (box.y1 < value + offset)
value = Math.max(0, box.y1 - offset);
else if (box.y2 > value + pageSize - offset)
value = Math.min(upper, box.y2 + offset - pageSize);
else
return;
Tweener.addTween(adjustment,
{ value: value,
time: SCROLL_TIME,
transition: 'easeOutQuad' });
},
setFilter: function(filter) {
this._filterApp = filter;
for (let i = 0; i < this._apps.length; i++)
@ -108,7 +137,14 @@ ViewByCategories.prototype = {
this._view = new AlphabeticalView();
this._filters = new St.BoxLayout({ vertical: true });
// categories can be -1 (the All view) or 0...n-1, where n
// is the number of sections
// -2 is a flag to indicate that nothing is selected
// (used only before the actor is mapped the first time)
this._currentCategory = -2;
this._filters = new St.BoxLayout({ vertical: true, reactive: true });
this._filters.connect('scroll-event', Lang.bind(this, this._scrollFilter));
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 });
@ -120,9 +156,28 @@ ViewByCategories.prototype = {
}));
this._sections = [];
// We need a dummy actor to catch the keyboard focus if the
// user Ctrl-Alt-Tabs here before the deferred work creates
// our real contents
this._focusDummy = new St.Bin({ can_focus: true });
this.actor.add(this._focusDummy);
},
_scrollFilter: function(actor, event) {
let direction = event.get_scroll_direction();
if (direction == Clutter.ScrollDirection.UP)
this._selectCategory(Math.max(this._currentCategory - 1, -1))
else if (direction == Clutter.ScrollDirection.DOWN)
this._selectCategory(Math.min(this._currentCategory + 1, this._sections.length - 1));
},
_selectCategory: function(num) {
if (this._currentCategory == num) // nothing to do
return;
this._currentCategory = num;
if (num != -1)
this._allFilter.remove_style_pseudo_class('selected');
else
@ -143,9 +198,10 @@ ViewByCategories.prototype = {
},
_addFilter: function(name, num) {
let button = new St.Button({ label: name,
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
style_class: 'app-filter',
x_align: St.Align.START });
x_align: St.Align.START,
can_focus: true });
this._filters.add(button, { expand: true, x_fill: true, y_fill: false });
button.connect('clicked', Lang.bind(this, function() {
this._selectCategory(num);
@ -180,6 +236,14 @@ ViewByCategories.prototype = {
this._addFilter(sections[i], i);
this._selectCategory(-1);
if (this._focusDummy) {
let focused = this._focusDummy.has_key_focus();
this._focusDummy.destroy();
this._focusDummy = null;
if (focused)
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
}
}
};
@ -230,7 +294,10 @@ BaseAppSearchProvider.prototype = {
return null;
return { 'id': resultId,
'name': app.get_name(),
'icon': app.create_icon_texture(Search.RESULT_ICON_SIZE)};
'createIcon': function(size) {
return app.create_icon_texture(size);
}
};
},
activateResult: function(id, params) {
@ -273,10 +340,6 @@ AppSearchProvider.prototype = {
let app = this._appSys.get_app(resultMeta['id']);
let icon = new AppWellIcon(app);
return icon.actor;
},
expandSearch: function(terms) {
log('TODO expand search');
}
};
@ -288,7 +351,7 @@ PrefsSearchProvider.prototype = {
__proto__: BaseAppSearchProvider.prototype,
_init: function() {
BaseAppSearchProvider.prototype._init.call(this, _("PREFERENCES"));
BaseAppSearchProvider.prototype._init.call(this, _("SETTINGS"));
},
getInitialResultSet: function(terms) {
@ -297,12 +360,6 @@ PrefsSearchProvider.prototype = {
getSubsearchResultSet: function(previousResults, terms) {
return this._appSys.subsearch(true, previousResults, terms);
},
expandSearch: function(terms) {
let controlCenter = this._appSys.load_from_desktop_file('gnomecc.desktop');
controlCenter.launch();
Main.overview.hide();
}
};
@ -338,6 +395,7 @@ AppWellIcon.prototype = {
this.actor = new St.Button({ style_class: 'app-well-app',
reactive: true,
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
can_focus: true,
x_fill: true,
y_fill: true });
this.actor._delegate = this;
@ -347,6 +405,7 @@ AppWellIcon.prototype = {
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu));
this._menu = null;
this._menuManager = new PopupMenu.PopupMenuManager(this);
@ -357,6 +416,10 @@ AppWellIcon.prototype = {
this._removeMenuTimeout();
Main.overview.beginItemDrag(this);
}));
this._draggable.connect('drag-cancelled', Lang.bind(this,
function () {
Main.overview.cancelledItemDrag(this);
}));
this._draggable.connect('drag-end', Lang.bind(this,
function () {
Main.overview.endItemDrag(this);
@ -423,6 +486,11 @@ AppWellIcon.prototype = {
return false;
},
_onKeyboardPopupMenu: function() {
this.popupMenu();
this._menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
getId: function() {
return this.app.get_id();
},
@ -440,10 +508,13 @@ AppWellIcon.prototype = {
if (!isPoppedUp)
this._onMenuPoppedDown();
}));
Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); }));
this._menuManager.addMenu(this._menu);
}
this.actor.set_hover(true);
this.actor.show_tooltip();
this._menu.popup();
return false;
@ -507,6 +578,9 @@ AppIconMenu.prototype = {
PopupMenu.PopupMenu.prototype._init.call(this, source.actor, 0.5, side, 0);
// We want to keep the item hovered while the menu is up
this.blockSourceEvents = true;
this._source = source;
this.connect('activate', Lang.bind(this, this._onActivate));
@ -548,10 +622,9 @@ AppIconMenu.prototype = {
let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
this._newWindowMenuItem = windows.length > 0 ? this._appendMenuItem(_("New Window")) : null;
this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
this._appendSeparator();
if (windows.length > 0)
this._appendSeparator();
this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites")
: _("Add to Favorites"));

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
@ -40,80 +41,80 @@ BoxPointer.prototype = {
this._border.connect('repaint', Lang.bind(this, this._drawBorder));
this._container.add_actor(this._border);
this.bin.raise(this._border);
this._xOffset = 0;
this._yOffset = 0;
this._xPosition = 0;
this._yPosition = 0;
},
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.opacity = 0;
this.actor.show();
if (animate) {
switch (this._arrowSide) {
case St.Side.TOP:
this.actor.y -= rise;
this.yOffset = -rise;
break;
case St.Side.BOTTOM:
this.actor.y += rise;
this.yOffset = rise;
break;
case St.Side.LEFT:
this.actor.x -= rise;
this.xOffset = -rise;
break;
case St.Side.RIGHT:
this.actor.x += rise;
this.xOffset = rise;
break;
}
}
Tweener.addTween(this.actor, { opacity: 255,
x: x,
y: y,
transition: "linear",
onComplete: onComplete,
time: POPUP_ANIMATION_TIME });
Tweener.addTween(this, { opacity: 255,
xOffset: 0,
yOffset: 0,
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 xOffset = 0;
let yOffset = 0;
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;
yOffset = rise;
break;
case St.Side.BOTTOM:
y -= rise;
yOffset = -rise;
break;
case St.Side.LEFT:
x += rise;
xOffset = rise;
break;
case St.Side.RIGHT:
x -= rise;
xOffset = -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();
})
});
Tweener.addTween(this, { opacity: 0,
xOffset: xOffset,
yOffset: yOffset,
transition: "linear",
time: POPUP_ANIMATION_TIME,
onComplete: Lang.bind(this, function () {
this.actor.hide();
this.xOffset = 0;
this.yOffset = 0;
if (onComplete)
onComplete();
})
});
},
_adjustAllocationForArrow: function(isWidth, alloc) {
@ -176,6 +177,9 @@ BoxPointer.prototype = {
break;
}
this.bin.allocate(childBox, flags);
if (this._sourceActor && this._sourceActor.mapped)
this._reposition(this._sourceActor, this._gap, this._alignment);
},
_drawBorder: function(area) {
@ -306,13 +310,20 @@ BoxPointer.prototype = {
// so that we can query the correct size.
this.actor.show();
this._sourceActor = sourceActor;
this._gap = gap;
this._alignment = alignment;
this._reposition(sourceActor, gap, alignment);
},
_reposition: function(sourceActor, gap, alignment) {
// Position correctly relative to the sourceActor
let sourceNode = sourceActor.get_theme_node();
let sourceContentBox = sourceNode.get_content_box(sourceActor.get_allocation_box());
let [sourceX, sourceY] = sourceActor.get_transformed_position();
let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
let sourceCenterX = sourceX + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) / 2;
let sourceCenterY = sourceY + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) / 2;
let sourceAllocation = Shell.util_get_transformed_allocation(sourceActor);
let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) / 2;
let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) / 2;
let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size();
// We also want to keep it onscreen, and separated from the
@ -330,16 +341,16 @@ BoxPointer.prototype = {
switch (this._arrowSide) {
case St.Side.TOP:
resY = sourceY + sourceHeight + gap;
resY = sourceAllocation.y2 + gap;
break;
case St.Side.BOTTOM:
resY = sourceY - natHeight - gap;
resY = sourceAllocation.y1 - natHeight - gap;
break;
case St.Side.LEFT:
resX = sourceX + sourceWidth + gap;
resX = sourceAllocation.x2 + gap;
break;
case St.Side.RIGHT:
resX = sourceX - natWidth - gap;
resX = sourceAllocation.x1 - natWidth - gap;
break;
}
@ -373,9 +384,9 @@ BoxPointer.prototype = {
parent = parent.get_parent();
}
// Actually set the position
this.actor.x = Math.floor(x);
this.actor.y = Math.floor(y);
this._xPosition = Math.floor(x);
this._yPosition = Math.floor(y);
this._shiftActor();
},
// @origin: Coordinate specifying middle of the arrow, along
@ -386,5 +397,42 @@ BoxPointer.prototype = {
this._arrowOrigin = origin;
this._border.queue_repaint();
}
},
_shiftActor : function() {
// Since the position of the BoxPointer depends on the allocated size
// of the BoxPointer and the position of the source actor, trying
// to position the BoxPoiner via the x/y properties will result in
// allocation loops and warnings. Instead we do the positioning via
// the anchor point, which is independent of allocation, and leave
// x == y == 0.
this.actor.set_anchor_point(-(this._xPosition + this._xOffset),
-(this._yPosition + this._yOffset));
},
set xOffset(offset) {
this._xOffset = offset;
this._shiftActor();
},
get xOffset() {
return this._xOffset;
},
set yOffset(offset) {
this._yOffset = offset;
this._shiftActor();
},
get yOffset() {
return this._yOffset;
},
set opacity(opacity) {
this.actor.opacity = opacity;
},
get opacity() {
return this.actor.opacity;
}
};

View File

@ -1,5 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const DBus = imports.dbus;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
@ -158,13 +159,14 @@ function _getEventDayAbbreviation(dayNumber) {
// Abstraction for an appointment/event in a calendar
function CalendarEvent(date, summary, allDay) {
this._init(date, summary, allDay);
function CalendarEvent(date, end, summary, allDay) {
this._init(date, end, summary, allDay);
}
CalendarEvent.prototype = {
_init: function(date, summary, allDay) {
_init: function(date, end, summary, allDay) {
this.date = date;
this.end = end;
this.summary = summary;
this.allDay = allDay;
}
@ -196,139 +198,136 @@ EmptyEventSource.prototype = {
};
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;
}
const CalendarServerIface = {
name: 'org.gnome.Shell.CalendarServer',
methods: [{ name: 'GetEvents',
inSignature: 'xxb',
outSignature: 'a(sssbxxa{sv})' }],
signals: [{ name: 'Changed',
inSignature: '' }]
};
Signals.addSignalMethods(EvolutionEventSource.prototype);
// Finally, an implementation with fake events
function FakeEventSource() {
const CalendarServer = function () {
this._init();
};
CalendarServer.prototype = {
_init: function() {
DBus.session.proxifyObject(this, 'org.gnome.Shell.CalendarServer', '/org/gnome/Shell/CalendarServer');
}
};
DBus.proxifyPrototype(CalendarServer.prototype, CalendarServerIface);
// an implementation that reads data from a session bus service
function DBusEventSource(owner) {
this._init(owner);
}
FakeEventSource.prototype = {
_init: function() {
function _datesEqual(a, b) {
if (a < b)
return false;
else if (a > b)
return false;
return true;
}
this._fakeEvents = [];
function _dateIntervalsOverlap(a0, a1, b0, b1)
{
if (a1 <= b0)
return false;
else if (b1 <= a0)
return false;
else
return true;
}
// 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));
}
DBusEventSource.prototype = {
_init: function(owner) {
this._resetCache();
// '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));
}
this._dbusProxy = new CalendarServer(owner);
this._dbusProxy.connect('Changed', Lang.bind(this, this._onChanged));
// '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;
DBus.session.watch_name('org.gnome.Shell.CalendarServer',
false, // do not launch a name-owner if none exists
Lang.bind(this, this._onNameAppeared),
Lang.bind(this, this._onNameVanished));
},
_updateTransientEvent: function() {
this._includeTransientEvent = !this._includeTransientEvent;
this._transientEventCounter = this._transientEventCounter + 1;
this._transientEvent.summary = 'A Transient Event (' + this._transientEventCounter + ')';
_resetCache: function() {
this._events = [];
this._lastRequestBegin = null;
this._lastRequestEnd = null;
},
_onNameAppeared: function(owner) {
this._resetCache();
this._loadEvents(true);
},
_onNameVanished: function(oldOwner) {
this._resetCache();
this.emit('changed');
Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
},
requestRange: function(begin, end) {
_onChanged: function() {
this._loadEvents(false);
},
_onEventsReceived: function(appointments) {
let newEvents = [];
if (appointments != null) {
for (let n = 0; n < appointments.length; n++) {
let a = appointments[n];
let date = new Date(a[4] * 1000);
let end = new Date(a[5] * 1000);
let summary = a[1];
let allDay = a[3];
let event = new CalendarEvent(date, end, summary, allDay);
newEvents.push(event);
}
newEvents.sort(function(event1, event2) {
return event1.date.getTime() - event2.date.getTime();
});
}
this._events = newEvents;
this.emit('changed');
},
_loadEvents: function(forceReload) {
if (this._curRequestBegin && this._curRequestEnd){
let callFlags = 0;
if (forceReload)
callFlags |= DBus.CALL_FLAG_START;
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
this._curRequestEnd.getTime() / 1000,
forceReload,
Lang.bind(this, this._onEventsReceived),
callFlags);
}
},
requestRange: function(begin, end, forceReload) {
if (forceReload || !(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
this._lastRequestBegin = begin;
this._lastRequestEnd = end;
this._curRequestBegin = begin;
this._curRequestEnd = end;
this._loadEvents(forceReload);
}
},
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) {
for(let n = 0; n < this._events.length; n++) {
let event = this._events[n];
if (_dateIntervalsOverlap (event.date, event.end, begin, 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;
},
@ -343,9 +342,8 @@ FakeEventSource.prototype = {
return true;
}
};
Signals.addSignalMethods(FakeEventSource.prototype);
Signals.addSignalMethods(DBusEventSource.prototype);
// Calendar:
// @eventSource: is an object implementing the EventSource API, e.g. the
@ -358,7 +356,10 @@ Calendar.prototype = {
_init: function(eventSource) {
this._eventSource = eventSource;
this._eventSource.connect('changed', Lang.bind(this, this._update));
this._eventSource.connect('changed', Lang.bind(this,
function() {
this._update(false);
}));
// 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
@ -407,15 +408,17 @@ Calendar.prototype = {
Lang.bind(this, this._onScroll));
this._buildHeader ();
this._update();
},
// Sets the calendar to show a specific date
setDate: function(date) {
setDate: function(date, forceReload) {
if (!_sameDay(date, this._selectedDate)) {
this._selectedDate = date;
this._update();
this._update(forceReload);
this.emit('selected-date-changed', new Date(this._selectedDate));
} else {
if (forceReload)
this._update(forceReload);
}
},
@ -510,7 +513,7 @@ Calendar.prototype = {
}
}
this.setDate(newDate);
this.setDate(newDate, false);
},
_onNextMonthButtonClicked: function() {
@ -532,16 +535,16 @@ Calendar.prototype = {
}
}
this.setDate(newDate);
this.setDate(newDate, false);
},
_onSettingsChange: function() {
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
this._buildHeader();
this._update();
this._update(false);
},
_update: function() {
_update: function(forceReload) {
let now = new Date();
if (_sameYear(this._selectedDate, now))
@ -570,7 +573,7 @@ Calendar.prototype = {
let iterStr = iter.toUTCString();
button.connect('clicked', Lang.bind(this, function() {
let newlySelectedDate = new Date(iterStr);
this.setDate(newlySelectedDate);
this.setDate(newlySelectedDate, false);
}));
let hasEvents = this._eventSource.hasEvents(iter);
@ -620,7 +623,7 @@ Calendar.prototype = {
}
// Signal to the event source that we are interested in events
// only from this date range
this._eventSource.requestRange(beginDate, iter);
this._eventSource.requestRange(beginDate, iter, forceReload);
}
};
@ -698,7 +701,7 @@ EventsList.prototype = {
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 nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
let timeString = _formatEventTime(nothingEvent, clockFormat);
this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
}

View File

@ -13,12 +13,6 @@ const Params = imports.misc.params;
// normal mode (ie, outside the Overview), that surrounds the main
// workspace content.
const Visibility = {
FULL: 1,
FULLSCREEN: 2,
OVERVIEW: 3
};
const defaultParams = {
visibleInOverview: false,
visibleInFullscreen: false,
@ -37,12 +31,13 @@ Chrome.prototype = {
Main.uiGroup.add_actor(this.actor);
this.actor.connect('allocate', Lang.bind(this, this._allocated));
this._inFullscreen = false;
this._monitors = [];
this._inOverview = false;
this.visibility = Visibility.FULL;
this._trackedActors = [];
global.screen.connect('monitors-changed',
Lang.bind(this, this._monitorsChanged));
global.screen.connect('restacked',
Lang.bind(this, this._windowsRestacked));
@ -55,6 +50,8 @@ Chrome.prototype = {
Main.overview.connect('hidden',
Lang.bind(this, this._overviewHidden));
this._updateMonitors();
this._updateFullscreen();
this._queueUpdateRegions();
},
@ -194,24 +191,12 @@ Chrome.prototype = {
let actorData = this._trackedActors[i];
if (this._inOverview && !actorData.visibleInOverview)
this.actor.set_skip_paint(actorData.actor, true);
else if (!this._inOverview && this._inFullscreen && !actorData.visibleInFullscreen)
else if (!this._inOverview && !actorData.visibleInFullscreen &&
this._findMonitorForActor(actorData.actor).inFullscreen)
this.actor.set_skip_paint(actorData.actor, true);
else
this.actor.set_skip_paint(actorData.actor, false);
}
let newVisibility;
if (this._inOverview)
newVisibility = Visibility.OVERVIEW;
else if (this._inFullscreen)
newVisibility = Visibility.FULLSCREEN;
else
newVisibility = Visibility.FULL;
if (newVisibility != this.visibility) {
this.visibility = newVisibility;
this.emit('visibility-changed', this.visibility);
}
},
_overviewShowing: function() {
@ -226,15 +211,77 @@ Chrome.prototype = {
this._queueUpdateRegions();
},
_updateMonitors: function() {
let monitors = global.get_monitors();
let primary = global.get_primary_monitor();
this._monitors = monitors;
for (let i = 0; i < monitors.length; i++) {
let monitor = monitors[i];
if (monitor.x == primary.x &&
monitor.y == primary.y &&
monitor.width == primary.width &&
monitor.height == primary.height)
this._primaryMonitor = monitor;
}
},
_findMonitorForRect: function(x, y, w, h) {
// First look at what monitor the center of the rectangle is at
let cx = x + w/2;
let cy = y + h/2;
for (let i = 0; i < this._monitors.length; i++) {
let monitor = this._monitors[i];
if (cx >= monitor.x && cx < monitor.x + monitor.width &&
cy >= monitor.y && cy < monitor.y + monitor.height)
return monitor;
}
// If the center is not on a monitor, return the first overlapping monitor
for (let i = 0; i < this._monitors.length; i++) {
let monitor = this._monitors[i];
if (x + w > monitor.x && x < monitor.x + monitor.width &&
y + h > monitor.y && y < monitor.y + monitor.height)
return monitor;
}
// otherwise on no monitor
return null;
},
_findMonitorForWindow: function(window) {
return this._findMonitorForRect(window.x, window.y, window.width, window.height);
},
// This call guarantees that we return some monitor to simplify usage of it
// In practice all tracked actors should be visible on some monitor anyway
_findMonitorForActor: function(actor) {
let [x, y] = actor.get_transformed_position();
let [w, h] = actor.get_transformed_size();
let monitor = this._findMonitorForRect(x, y, w, h);
if (monitor)
return monitor;
return this._primaryMonitor; // Not on any monitor, pretend its on the primary
},
_monitorsChanged: function() {
this._updateMonitors();
// Update everything that depends on monitor positions
this._updateFullscreen();
this._updateVisibility();
this._queueUpdateRegions();
},
_queueUpdateRegions: function() {
if (!this._updateRegionIdle)
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
Meta.PRIORITY_BEFORE_REDRAW);
},
_windowsRestacked: function() {
_updateFullscreen: function() {
let windows = Main.getWindowActorsForWorkspace(global.screen.get_active_workspace_index());
let primary = global.get_primary_monitor();
// Reset all monitors to not fullscreen
for (let i = 0; i < this._monitors.length; i++)
this._monitors[i].inFullscreen = false;
// The chrome layer should be visible unless there is a window
// with layer FULLSCREEN, or a window with layer
@ -248,42 +295,51 @@ Chrome.prototype = {
// @windows is sorted bottom to top.
let wasInFullscreen = this._inFullscreen;
this._inFullscreen = false;
for (let i = windows.length - 1; i > -1; i--) {
let layer = windows[i].get_meta_window().get_layer();
// There are 3 cases we check here for:
// 1.) Monitor sized window
// 2.) Window with a position somewhere on the primary screen having the _NET_WM_FULLSCREEN flag set
// 3.) Window that is partly off screen (tries to hide its decorations) which might have negative coords
// We check for 1.) and 2.) by checking if the upper right corner is on the primary monitor, but avoid the case
// where it overlaps with the secondary screen (like window.x + window.width == primary.x + primary.width)
// For 3.) we just ignore negative values as they don't really make sense
let window = windows[i];
let layer = window.get_meta_window().get_layer();
if (layer == Meta.StackLayer.FULLSCREEN) {
if (Math.max(windows[i].x, 0) >= primary.x && Math.max(windows[i].x, 0) < primary.x + primary.width &&
Math.max(windows[i].y, 0) >= primary.y && Math.max(windows[i].y, 0) < primary.y + primary.height) {
this._inFullscreen = true;
break;
}
let monitor = this._findMonitorForWindow(window);
if (monitor)
monitor.inFullscreen = true;
}
if (layer == Meta.StackLayer.OVERRIDE_REDIRECT) {
if (windows[i].x <= primary.x &&
windows[i].x + windows[i].width >= primary.x + primary.width &&
windows[i].y <= primary.y &&
windows[i].y + windows[i].height >= primary.y + primary.height) {
this._inFullscreen = true;
break;
}
let monitor = this._findMonitorForWindow(window);
if (monitor &&
window.x <= monitor.x &&
window.x + window.width >= monitor.x + monitor.width &&
window.y <= monitor.y &&
window.y + window.height >= monitor.y + monitor.height)
monitor.inFullscreen = true;
} else
break;
}
},
if (this._inFullscreen != wasInFullscreen) {
_windowsRestacked: function() {
let wasInFullscreen = [];
for (let i = 0; i < this._monitors.length; i++)
wasInFullscreen[i] = this._monitors[i].inFullscreen;
this._updateFullscreen();
let changed = false;
for (let i = 0; i < wasInFullscreen.length; i++) {
if (wasInFullscreen[i] != this._monitors[i].inFullscreen) {
changed = true;
break;
}
}
if (changed) {
this._updateVisibility();
this._queueUpdateRegions();
}
// Figure out where the pointer is in case we lost track of
// it during a grab. (In particular, if a trayicon popup menu
// is dismissed, see if we need to close the message tray.)
global.sync_pointer();
},
_updateRegions: function() {
@ -312,41 +368,75 @@ Chrome.prototype = {
if (!actorData.affectsStruts)
continue;
// Limit struts to the size of the screen
let x1 = Math.max(x, 0);
let x2 = Math.min(x + w, global.screen_width);
let y1 = Math.max(y, 0);
let y2 = Math.min(y + h, global.screen_height);
// NetWM struts are not really powerful enought to handle
// a multi-monitor scenario, they only describe what happens
// around the outer sides of the full display region. However
// it can describe a partial region along each side, so
// we can support having the struts only affect the
// primary monitor. This should be enough as we only have
// chrome affecting the struts on the primary monitor so
// far.
//
// Metacity wants to know what side of the screen the
// strut is considered to be attached to. If the actor is
// only touching one edge, or is touching the entire
// width/height of one edge, then it's obvious which side
// to call it. If it's in a corner, we pick a side
// border of the primary monitor, then it's obvious which
// side to call it. If it's in a corner, we pick a side
// arbitrarily. If it doesn't touch any edges, or it spans
// the width/height across the middle of the screen, then
// we don't create a strut for it at all.
let side;
if (w >= global.screen_width) {
if (y <= 0)
let primary = this._primaryMonitor;
if (x1 <= primary.x && x2 >= primary.x + primary.width) {
if (y1 <= primary.y)
side = Meta.Side.TOP;
else if (y + h >= global.screen_height)
else if (y2 >= primary.y + primary.height)
side = Meta.Side.BOTTOM;
else
continue;
} else if (h >= global.screen_height) {
if (x <= 0)
} else if (y1 <= primary.y && y2 >= primary.y + primary.height) {
if (x1 <= 0)
side = Meta.Side.LEFT;
else if (x + w >= global.screen_width)
else if (x2 >= global.screen_width)
side = Meta.Side.RIGHT;
else
continue;
} else if (x <= 0)
} else if (x1 <= 0)
side = Meta.Side.LEFT;
else if (y <= 0)
else if (y1 <= 0)
side = Meta.Side.TOP;
else if (x + w >= global.screen_width)
else if (x2 >= global.screen_width)
side = Meta.Side.RIGHT;
else if (y + h >= global.screen_height)
else if (y2 >= global.screen_height)
side = Meta.Side.BOTTOM;
else
continue;
let strut = new Meta.Strut({ rect: rect, side: side });
// Ensure that the strut rects goes all the way to the screen edge,
// as this really what mutter expects.
switch (side) {
case Meta.Side.TOP:
y1 = 0;
break;
case Meta.Side.BOTTOM:
y2 = global.screen_height;
break;
case Meta.Side.LEFT:
x1 = 0;
break;
case Meta.Side.RIGHT:
x2 = global.screen_width;
break;
}
let strutRect = new Meta.Rectangle({ x: x1, y: y1, width: x2 - x1, height: y2 - y1});
let strut = new Meta.Strut({ rect: strutRect, side: side });
struts.push(strut);
}

View File

@ -10,11 +10,18 @@ const St = imports.gi.St;
const AltTab = imports.ui.altTab;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const POPUP_APPICON_SIZE = 96;
const POPUP_FADE_TIME = 0.1; // seconds
const SortGroup = {
TOP: 0,
MIDDLE: 1,
BOTTOM: 2
};
function CtrlAltTabManager() {
this._init();
}
@ -23,14 +30,18 @@ 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 });
addGroup: function(root, name, icon, params) {
let item = Params.parse(params, { sortGroup: SortGroup.MIDDLE,
proxy: root,
focusCallback: null });
item.root = root;
item.name = name;
item.iconName = icon;
this._items.push(item);
root.connect('destroy', Lang.bind(this, function() { this.removeGroup(root); }));
this._focusManager.add_group(root);
},
@ -45,38 +56,73 @@ CtrlAltTabManager.prototype = {
}
},
focusGroup: function(root) {
focusGroup: function(item) {
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);
if (item.window)
Main.activateWindow(item.window);
else if (item.focusCallback)
item.focusCallback();
else
item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
// Sort the items into a consistent order; panel first, tray last,
// and everything else in between, sorted by X coordinate, so that
// they will have the same left-to-right ordering in the
// Ctrl-Alt-Tab dialog as they do onscreen.
_sortItems: function(a, b) {
if (a.sortGroup != b.sortGroup)
return a.sortGroup - b.sortGroup;
let y;
if (a.x == undefined) {
if (a.window)
a.x = a.window.get_compositor_private().x;
else
[a.x, y] = a.proxy.get_transformed_position();
}
if (b.x == undefined) {
if (b.window)
b.x = b.window.get_compositor_private().x;
else
[b.x, y] = b.proxy.get_transformed_position();
}
return a.x - b.x;
},
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; });
let items = this._items.filter(function (item) { return item.proxy.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 (!Main.overview.visible) {
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,
sortGroup: SortGroup.MIDDLE });
}
}
if (!items.length)
return;
items.sort(Lang.bind(this, this._sortItems));
new CtrlAltTabPopup().show(items, backwards);
}
};
@ -91,12 +137,12 @@ function CtrlAltTabPopup() {
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 = new Shell.GenericContainer({ name: 'ctrlAltTabPopup',
reactive: true });
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.actor.connect('destroy', Lang.bind(this, this._onDestroy));
@ -106,6 +152,37 @@ CtrlAltTabPopup.prototype = {
Main.uiGroup.add_actor(this.actor);
},
_getPreferredWidth: function (actor, forHeight, alloc) {
let primary = global.get_primary_monitor();
alloc.min_size = primary.width;
alloc.natural_size = primary.width;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
let primary = global.get_primary_monitor();
alloc.min_size = primary.height;
alloc.natural_size = primary.height;
},
_allocate: function (actor, box, flags) {
let childBox = new Clutter.ActorBox();
let primary = global.get_primary_monitor();
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let vPadding = this.actor.get_theme_node().get_vertical_padding();
let hPadding = this.actor.get_theme_node().get_horizontal_padding();
let [childMinHeight, childNaturalHeight] = this._switcher.actor.get_preferred_height(primary.width - hPadding);
let [childMinWidth, childNaturalWidth] = this._switcher.actor.get_preferred_width(childNaturalHeight);
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
childBox.x2 = Math.min(primary.width - hPadding, childBox.x1 + childNaturalWidth);
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._switcher.actor.allocate(childBox, flags);
},
show : function(items, startBackwards) {
if (!Main.pushModal(this.actor))
return false;
@ -180,11 +257,7 @@ CtrlAltTabPopup.prototype = {
_finish : function() {
this.destroy();
let item = this._items[this._selection];
if (item.root)
Main.ctrlAltTabManager.focusGroup(item.root);
else
Main.activateWindow(item.window);
Main.ctrlAltTabManager.focusGroup(this._items[this._selection]);
},
_popModal: function() {
@ -208,6 +281,7 @@ CtrlAltTabPopup.prototype = {
},
_onDestroy : function() {
this._popModal();
if (this._keyPressEventId)
this.actor.disconnect(this._keyPressEventId);
if (this._keyReleaseEventId)

View File

@ -262,11 +262,6 @@ Dash.prototype = {
clip_to_allocation: true });
this._box._delegate = this;
// This will eventually be automatic, see
// https://bugzilla.gnome.org/show_bug.cgi?id=584662
if (St.Widget.get_default_direction () == St.TextDirection.RTL)
this._box.add_style_pseudo_class('rtl');
this.actor = new St.Bin({ y_align: St.Align.START, child: this._box });
this.actor.connect('notify::height', Lang.bind(this,
function() {
@ -288,20 +283,37 @@ Dash.prototype = {
Lang.bind(this, this._onDragBegin));
Main.overview.connect('item-drag-end',
Lang.bind(this, this._onDragEnd));
Main.overview.connect('item-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
Main.overview.connect('window-drag-begin',
Lang.bind(this, this._onDragBegin));
Main.overview.connect('window-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
Main.overview.connect('window-drag-end',
Lang.bind(this, this._onDragEnd));
},
_onDragBegin: function() {
this._dragCancelled = false;
this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion)
};
DND.addDragMonitor(this._dragMonitor);
},
_onDragCancelled: function() {
this._dragCancelled = true;
this._endDrag();
},
_onDragEnd: function() {
if (this._dragCancelled)
return;
this._endDrag();
},
_endDrag: function() {
this._clearDragPlaceholder();
if (this._favRemoveTarget) {
this._favRemoveTarget.actor.hide();
@ -377,6 +389,8 @@ Dash.prototype = {
Lang.bind(this, function() {
display.actor.opacity = 255;
}));
display.actor.set_tooltip_text(app.get_name());
let item = new DashItemContainer();
item.setChild(display.actor);

View File

@ -52,9 +52,7 @@ DateMenuButton.prototype = {
let hbox;
let vbox;
//this._eventSource = new Calendar.EmptyEventSource();
//this._eventSource = new Calendar.FakeEventSource();
this._eventSource = new Calendar.EvolutionEventSource();
this._eventSource = new Calendar.DBusEventSource();
let menuAlignment = 0.25;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
@ -92,6 +90,7 @@ DateMenuButton.prototype = {
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));
item.actor.can_focus = false;
vbox.add(item.actor);
// Add vertical separator
@ -104,20 +103,34 @@ DateMenuButton.prototype = {
// Fill up the second column
vbox = new St.BoxLayout({vertical: true});
hbox.add(vbox);
hbox.add(vbox, { expand: true });
// Event list
vbox.add(this._eventList.actor);
vbox.add(this._eventList.actor, { expand: true });
item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
item.actor.can_focus = false;
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);
/* Passing true to setDate() forces events to be reloaded. We
* want this behavior, because
*
* o It will cause activation of the calendar server which is
* useful if it has crashed
*
* o It will cause the calendar server to reload events which
* is useful if dynamic updates are not supported or not
* properly working
*
* Since this only happens when the menu is opened, the cost
* isn't very big.
*/
this._calendar.setDate(now, true);
// No need to update this._eventList as ::selected-date-changed
// signal will fire
}
@ -172,21 +185,6 @@ DateMenuButton.prototype = {
}
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));
@ -196,19 +194,19 @@ DateMenuButton.prototype = {
dateFormat = _("%A %B %e, %Y");
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClockAndDate));
Mainloop.timeout_add_seconds(1, Lang.bind(this, this._updateClockAndDate));
return false;
},
_onPreferencesActivate: function() {
this.menu.close();
Util.spawnDesktop('gnome-datetime-panel');
let app = Shell.AppSystem.get_default().get_app('gnome-datetime-panel.desktop');
app.activate(-1);
},
_onOpenCalendarActivate: function() {
this.menu.close();
// TODO: pass '-c calendar' (to force the calendar at startup)
// TODO: pass the selected day
Util.spawnDesktop('evolution');
},
Util.spawn(['evolution', '-c', 'calendar']);
}
};

View File

@ -87,6 +87,10 @@ _Draggable.prototype = {
this.actor.connect('destroy', Lang.bind(this, function() {
this._actorDestroyed = true;
// If the drag actor is destroyed and we were going to fix
// up its hover state, fix up the parent hover state instead
if (this.actor == this._firstLeaveActor)
this._firstLeaveActor = this._dragOrigParent;
if (this._dragInProgress)
this._cancelDrag(global.get_current_time());
this.disconnectAll();
@ -101,6 +105,12 @@ _Draggable.prototype = {
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).
// During the drag, we eat enter/leave events so that actors don't prelight or show
// tooltips. But we remember the actors that we first left/last entered so we can
// fix up the hover state after the drag ends.
this._firstLeaveActor = null;
this._lastEnterActor = null;
this._eventsGrabbed = false;
},
@ -144,6 +154,8 @@ _Draggable.prototype = {
_ungrabActor: function() {
Clutter.ungrab_pointer();
if (!this._onEventId)
return;
this.actor.disconnect(this._onEventId);
this._onEventId = null;
},
@ -198,6 +210,11 @@ _Draggable.prototype = {
this._cancelDrag(event.get_time());
return true;
}
} else if (event.type() == Clutter.EventType.LEAVE) {
if (this._firstLeaveActor == null)
this._firstLeaveActor = event.get_source();
} else if (event.type() == Clutter.EventType.ENTER) {
this._lastEnterActor = event.get_source();
}
return false;
@ -463,7 +480,9 @@ _Draggable.prototype = {
let [parentX, parentY] = this._dragOrigParent.get_transformed_position();
let [parentWidth, parentHeight] = this._dragOrigParent.get_size();
let [parentScaledWidth, parentScaledHeight] = this._dragOrigParent.get_transformed_size();
let parentScale = parentScaledWidth / parentWidth;
let parentScale = 1.0;
if (parentWidth != 0)
parentScale = parentScaledWidth / parentWidth;
x = parentX + parentScale * this._dragOrigX;
y = parentY + parentScale * this._dragOrigY;
@ -479,14 +498,18 @@ _Draggable.prototype = {
},
_cancelDrag: function(eventTime) {
this.emit('drag-cancelled', eventTime);
this._dragInProgress = false;
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
if (this._actorDestroyed) {
global.unset_cursor();
if (!this._buttonDown)
this._ungrabEvents();
this._dragComplete();
this.emit('drag-end', eventTime, false);
if (!this._dragOrigParent)
this._dragActor.destroy();
return;
}
@ -542,12 +565,36 @@ _Draggable.prototype = {
this._dragComplete();
},
// Actor is an actor we have entered or left during the drag; call
// st_widget_sync_hover on all StWidget ancestors
_syncHover: function(actor) {
while (actor) {
let parent = actor.get_parent();
if (actor instanceof St.Widget)
actor.sync_hover();
actor = parent;
}
},
_dragComplete: function() {
Shell.util_set_hidden_from_pick(this._dragActor, false);
if (!this._actorDestroyed)
Shell.util_set_hidden_from_pick(this._dragActor, false);
this._ungrabEvents();
if (this._firstLeaveActor) {
this._syncHover(this._firstLeaveActor);
this._firstLeaveActor = null;
}
if (this._lastEnterActor) {
this._syncHover(this._lastEnterActor);
this._lastEnterActor = null;
}
this._dragActor = undefined;
currentDraggable = null;
this._ungrabEvents();
}
};

View File

@ -26,7 +26,10 @@ DocSearchProvider.prototype = {
return null;
return { 'id': resultId,
'name': docInfo.name,
'icon': docInfo.createIcon(Search.RESULT_ICON_SIZE)};
'createIcon': function(size) {
return docInfo.createIcon(size);
}
};
},
activateResult: function(id, params) {
@ -43,9 +46,5 @@ DocSearchProvider.prototype = {
getSubsearchResultSet: function(previousResults, terms) {
return this._docManager.subsearch(previousResults, terms);
},
expandSearch: function(terms) {
log('TODO expand docs search');
}
};

View File

@ -54,7 +54,7 @@ const EndSessionDialogIface = {
}
],
signals: [{ name: 'Canceled',
outSignature: '',
inSignature: '',
}],
properties: []
};
@ -66,16 +66,20 @@ const logoutDialogContent = {
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"),
confirmButtons: [{ signal: 'ConfirmedLogout',
label: _("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"),
subject: _("Power Off"),
inhibitedDescription: _("Click Power Off to quit these applications and power off the system."),
uninhibitedDescription: _("The system will power off automatically in %d seconds."),
endDescription: _("Powering off the system."),
confirmButtons: [{ signal: 'ConfirmedReboot',
label: _("Restart") },
{ signal: 'ConfirmedShutdown',
label: _("Power Off") }],
iconName: 'system-shutdown',
iconStyleClass: 'end-session-dialog-shutdown-icon'
};
@ -85,7 +89,8 @@ const restartDialogContent = {
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"),
confirmButtons: [{ signal: 'ConfirmedReboot',
label: _("Restart") }],
iconName: 'system-shutdown',
iconStyleClass: 'end-session-dialog-shutdown-icon'
};
@ -233,7 +238,7 @@ EndSessionDialog.prototype = {
__proto__: ModalDialog.ModalDialog.prototype,
_init: function() {
ModalDialog.ModalDialog.prototype._init.call(this);
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'end-session-dialog' });
this._user = Gdm.UserManager.ref_default().get_user(GLib.get_user_name());
@ -288,12 +293,26 @@ EndSessionDialog.prototype = {
this.contentLayout.add(scrollView,
{ x_fill: true,
y_fill: true });
scrollView.hide();
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 });
this._applicationList.connect('actor-added',
Lang.bind(this, function() {
if (this._applicationList.get_children().length == 1)
scrollView.show();
}));
this._applicationList.connect('actor-removed',
Lang.bind(this, function() {
if (this._applicationList.get_children().length == 0)
scrollView.hide();
}));
},
_onDestroy: function() {
@ -347,8 +366,10 @@ EndSessionDialog.prototype = {
if (this._user.is_loaded && !dialogContent.iconName) {
let iconFile = this._user.get_icon_file();
this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
if (GLib.file_test(iconFile, GLib.FileTest.EXISTS))
this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
else
this._setIconFromName('avatar-default', dialogContent.iconStyleClass);
} else if (dialogContent.iconName) {
this._setIconFromName(dialogContent.iconName,
dialogContent.iconStyleClass);
@ -392,18 +413,27 @@ EndSessionDialog.prototype = {
return;
let dialogContent = DialogContent[this._type];
let confirmButtonText = _("Confirm");
let buttons = [{ action: Lang.bind(this, this.cancel),
label: _("Cancel"),
key: Clutter.Escape }];
if (dialogContent.confirmButtonText)
confirmButtonText = dialogContent.confirmButtonText;
for (let i = 0; i < dialogContent.confirmButtons.length; i++) {
let signal = dialogContent.confirmButtons[i].signal;
let label = dialogContent.confirmButtons[i].label;
buttons.push({ action: Lang.bind(this, function() {
this._confirm(signal);
}),
label: label });
}
this.setButtons([{ label: _("Cancel"),
action: Lang.bind(this, this.cancel),
key: Clutter.Escape
},
{ label: confirmButtonText,
action: Lang.bind(this, this._confirm)
}]);
this.setButtons(buttons);
},
close: function() {
ModalDialog.ModalDialog.prototype.close.call(this);
DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
'org.gnome.SessionManager.EndSessionDialog',
'Closed', '', []);
},
cancel: function() {
@ -414,12 +444,12 @@ EndSessionDialog.prototype = {
this.close(global.get_current_time());
},
_confirm: function() {
_confirm: function(signal) {
this._fadeOutDialog();
this._stopTimer();
DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
'org.gnome.SessionManager.EndSessionDialog',
'Confirmed', '', []);
signal, '', []);
},
_onOpened: function() {
@ -434,7 +464,11 @@ EndSessionDialog.prototype = {
time: this._secondsLeft,
transition: 'linear',
onUpdate: Lang.bind(this, this._updateContent),
onComplete: Lang.bind(this, this._confirm),
onComplete: Lang.bind(this, function() {
let dialogContent = DialogContent[this._type];
let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1];
this._confirm(button.signal);
}),
});
},

View File

@ -17,7 +17,7 @@ function _patchContainerClass(containerClass) {
// This one is a straightforward mapping of the C method
containerClass.prototype.child_set = function(actor, props) {
let meta = this.get_child_meta(actor);
for (prop in props)
for (let prop in props)
meta[prop] = props[prop];
};
@ -64,6 +64,11 @@ function init() {
Tweener.init();
String.prototype.format = Format.format;
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
Date.prototype.toLocaleFormat = function(format) {
return Shell.util_format_date(format, this.getTime());
};
// Set the default direction for St widgets (this needs to be done before any use of St)
if (Gettext_gtk30.gettext('default:LTR') == 'default:RTL') {
St.Widget.set_default_direction(St.TextDirection.RTL);

View File

@ -3,6 +3,7 @@
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;
@ -67,7 +68,13 @@ function loadExtension(dir, enabled, type) {
return;
}
let [success, metadataContents, len, etag] = metadataFile.load_contents(null);
let metadataContents;
try {
metadataContents = Shell.get_file_contents_utf8_sync(metadataFile.get_path());
} catch (e) {
global.logError(baseErrorString + 'Failed to load metadata.json: ' + e);
return;
}
let meta;
try {
meta = JSON.parse(metadataContents);
@ -174,8 +181,15 @@ function init() {
}
function _loadExtensionsIn(dir, type) {
let fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
let fileEnum;
let file, info;
try {
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
} catch (e) {
global.logError('' + e);
return;
}
while ((info = fileEnum.next_file(null)) != null) {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)

View File

@ -52,8 +52,7 @@ BaseIcon.prototype = {
this.createIcon = params.createIcon;
this._setSizeManually = params.setSizeManually;
this.icon = this.createIcon(this.iconSize);
this._iconBin.set_child(this.icon);
this.icon = null;
},
_allocate: function(actor, box, flags) {
@ -116,16 +115,23 @@ BaseIcon.prototype = {
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._createIconTexture(size);
},
_createIconTexture: function(size) {
if (this.icon)
this.icon.destroy();
this.iconSize = size;
this.icon = this.createIcon(this.iconSize);
// The icon returned by createIcon() might actually be smaller than
// the requested icon size (for instance StTextureCache does this
// for fallback icons), so set the size explicitly.
this.icon.set_size(this.iconSize, this.iconSize);
this._iconBin.child = this.icon;
},
@ -133,12 +139,15 @@ BaseIcon.prototype = {
let node = this.actor.get_theme_node();
this._spacing = node.get_length('spacing');
if (this._setSizeManually)
return;
let size;
if (this._setSizeManually) {
size = this.iconSize;
} else {
let [found, len] = node.lookup_length('icon-size', false);
size = found ? len : ICON_SIZE;
}
let len = node.get_length('icon-size');
if (len > 0)
this._setIconSize(len);
this._createIconTexture(size);
}
};
@ -272,8 +281,11 @@ IconGrid.prototype = {
}
},
childrenInRow: function(rowWidth) {
return this._computeLayout(rowWidth)[0];
},
_computeLayout: function (forWidth) {
let children = this._grid.get_children();
let nColumns = 0;
let usedWidth = 0;
while ((this._colLimit == null || nColumns < this._colLimit) &&

View File

@ -27,6 +27,7 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
'const Mainloop = imports.mainloop; ' +
'const Meta = imports.gi.Meta; ' +
'const Shell = imports.gi.Shell; ' +
'const Tp = imports.gi.TelepathyGLib; ' +
'const Main = imports.ui.main; ' +
'const Lang = imports.lang; ' +
'const Tweener = imports.ui.tweener; ' +
@ -777,23 +778,8 @@ LookingGlass.prototype = {
return true;
}));
this._history = new History.HistoryManager(HISTORY_KEY);
this._history.connect('changed', Lang.bind(this, function(history, text) {
this._entry.text = text;
}));
this._entry.clutter_text.connect('key-press-event', Lang.bind(this, function(o, e) {
let symbol = e.get_key_symbol();
if (symbol == Clutter.Up) {
this._history.prevItem(o.get_text());
return true;
} else if (symbol == Clutter.Down) {
this._history.nextItem(o.get_text());
return true;
} else {
return false;
}
}));
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
entry: this._entry.clutter_text });
},
_updateFont: function() {

View File

@ -48,6 +48,7 @@ DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
let chrome = null;
let panel = null;
let hotCorners = [];
let placesManager = null;
let overview = null;
let runDialog = null;
@ -85,9 +86,11 @@ function start() {
global.logError = _logError;
global.log = _logDebug;
// Chain up async errors reported from C
global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); });
Gio.DesktopAppInfo.set_desktop_env('GNOME');
global.grab_dbus_service();
shellDBusService = new ShellDBus.GnomeShell();
// Force a connection now; dbus.js will do this internally
// if we use its name acquisition stuff but we aren't right
@ -95,6 +98,10 @@ function start() {
// back into sync ones.
DBus.session.flush();
// Load the calendar server. Note that we are careful about
// not loading any events until the user presses the clock
global.launch_calendar_server();
Environment.init();
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
@ -129,12 +136,14 @@ function start() {
// Set up stage hierarchy to group all UI actors under one container.
uiGroup = new Clutter.Group();
St.set_ui_root(global.stage, uiGroup);
global.window_group.reparent(uiGroup);
global.overlay_group.reparent(uiGroup);
global.stage.add_actor(uiGroup);
placesManager = new PlaceDisplay.PlacesManager();
xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
overview = new Overview.Overview();
chrome = new Chrome.Chrome();
magnifier = new Magnifier.Magnifier();
@ -149,9 +158,6 @@ function start() {
overview.init();
statusIconDispatcher.start(messageTray.actor);
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
ctrlAltTabManager.addGroup(panel.actor, _("Panel"), 'gnome-panel');
_startDate = new Date();
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
@ -187,11 +193,14 @@ function start() {
// Attempt to become a PolicyKit authentication agent
PolkitAuthenticationAgent.init()
global.gdk_screen.connect('monitors-changed', _relayout);
global.screen.connect('monitors-changed', _relayout);
ExtensionSystem.init();
ExtensionSystem.loadExtensions();
// Perform initial relayout here
_relayout();
panel.startStatusArea();
panel.startupAnimation();
@ -200,9 +209,6 @@ function start() {
global.stage.connect('captured-event', _globalKeyPressHandler);
// Perform initial relayout here
_relayout();
_log('info', 'loaded at ' + _startDate);
log('GNOME Shell started at ' + _startDate);
@ -214,18 +220,38 @@ function start() {
}
global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
Mainloop.idle_add(_nWorkspacesChanged);
global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
global.screen.connect('window-left-monitor', _windowLeftMonitor);
_nWorkspacesChanged();
}
let _workspaces = [];
let _checkWorkspacesId = 0;
/*
* When the last window closed on a workspace is a dialog or splash
* screen, we assume that it might be an initial window shown before
* the main window of an application, and give the app a grace period
* where it can map another window before we remove the workspace.
*/
const LAST_WINDOW_GRACE_TIME = 1000;
function _checkWorkspaces() {
let i;
let emptyWorkspaces = [];
for (i = 0; i < _workspaces.length; i++)
emptyWorkspaces[i] = true;
for (i = 0; i < _workspaces.length; i++) {
let lastRemoved = _workspaces[i]._lastRemovedWindow;
if (lastRemoved &&
(lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG))
emptyWorkspaces[i] = false;
else
emptyWorkspaces[i] = true;
}
let windows = global.get_window_actors();
for (i = 0; i < windows.length; i++) {
@ -244,16 +270,61 @@ function _checkWorkspaces() {
emptyWorkspaces.push(false);
}
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let removingCurrentWorkspace = (emptyWorkspaces[activeWorkspaceIndex] &&
activeWorkspaceIndex < emptyWorkspaces.length - 1);
// Don't enter the overview when removing multiple empty workspaces at startup
let showOverview = (removingCurrentWorkspace &&
!emptyWorkspaces.every(function(x) { return x; }));
if (removingCurrentWorkspace) {
// "Merge" the empty workspace we are removing with the one at the end
wm.blockAnimations();
}
// Delete other empty workspaces; do it from the end to avoid index changes
for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
if (emptyWorkspaces[i])
global.screen.remove_workspace(_workspaces[i], global.get_current_time());
}
if (removingCurrentWorkspace) {
global.screen.get_workspace_by_index(global.screen.n_workspaces - 1).activate(global.get_current_time());
wm.unblockAnimations();
if (!overview.visible && showOverview)
overview.show();
}
_checkWorkspacesId = 0;
return false;
}
function _windowRemoved(workspace, window) {
workspace._lastRemovedWindow = window;
_queueCheckWorkspaces();
Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, function() {
if (workspace._lastRemovedWindow == window) {
workspace._lastRemovedWindow = null;
_queueCheckWorkspaces();
}
});
}
function _windowLeftMonitor(metaScreen, monitorIndex, metaWin) {
// If the window left the primary monitor, that
// might make that workspace empty
if (monitorIndex == global.get_primary_monitor_index())
_queueCheckWorkspaces();
}
function _windowEnteredMonitor(metaScreen, monitorIndex, metaWin) {
// If the window entered the primary monitor, that
// might make that workspace non-empty
if (monitorIndex == global.get_primary_monitor_index())
_queueCheckWorkspaces();
}
function _queueCheckWorkspaces() {
if (_checkWorkspacesId == 0)
_checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, _checkWorkspaces);
@ -277,7 +348,7 @@ function _nWorkspacesChanged() {
for (w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let workspace = _workspaces[w];
workspace._windowAddedId = workspace.connect('window-added', _queueCheckWorkspaces);
workspace._windowRemovedId = workspace.connect('window-removed', _queueCheckWorkspaces);
workspace._windowRemovedId = workspace.connect('window-removed', _windowRemoved);
}
} else {
@ -346,6 +417,27 @@ function loadTheme() {
themeContext.set_theme (theme);
}
/**
* notifyError:
* @msg: An error message
* @details: Additional information
*
* See shell_global_notify_problem().
*/
function notifyError(msg, details) {
// Also print to stderr so it's logged somewhere
if (details)
log("error: " + msg + ": " + details);
else
log("error: " + msg)
let source = new MessageTray.SystemNotificationSource();
messageTray.add(source);
let notification = new MessageTray.Notification(source, msg, details);
notification.setTransient(true);
source.notify(notification);
}
/**
* _log:
* @category: string message type ('info', 'error')
@ -388,9 +480,73 @@ function _getAndClearErrorStack() {
}
function _relayout() {
let monitors = global.get_monitors();
// destroy old corners
for (let i = 0; i < hotCorners.length; i++)
hotCorners[i].destroy();
hotCorners = [];
let primary = global.get_primary_monitor();
panel.actor.set_position(primary.x, primary.y);
panel.actor.set_size(primary.width, Panel.PANEL_HEIGHT);
for (let i = 0; i < monitors.length; i++) {
let monitor = monitors[i];
let isPrimary = (monitor.x == primary.x &&
monitor.y == primary.y &&
monitor.width == primary.width &&
monitor.height == primary.height);
let cornerX = monitor.x;
let cornerY = monitor.y;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
cornerX += monitor.width;
let haveTopLeftCorner = true;
/* Check if we have a top left (right for RTL) corner.
* I.e. if there is no monitor directly above or to the left(right) */
let besideX;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
besideX = monitor.x + 1;
else
besideX = cornerX - 1;
let besideY = cornerY;
let aboveX = cornerX;
let aboveY = cornerY - 1;
for (let j = 0; j < monitors.length; j++) {
if (i == j)
continue;
let otherMonitor = monitors[j];
if (besideX >= otherMonitor.x &&
besideX < otherMonitor.x + otherMonitor.width &&
besideY >= otherMonitor.y &&
besideY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
if (aboveX >= otherMonitor.x &&
aboveX < otherMonitor.x + otherMonitor.width &&
aboveY >= otherMonitor.y &&
aboveY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
}
/* We only want hot corners where there is a natural top-left
* corner, and on the primary monitor */
if (!isPrimary && !haveTopLeftCorner)
continue;
let corner = new Panel.HotCorner(isPrimary ? panel.button : null);
hotCorners.push(corner);
corner.actor.set_position(cornerX, cornerY);
if (isPrimary)
panel.setHotCorner(corner);
}
panel.relayout();
overview.relayout();
// To avoid updating the position and size of the workspaces
@ -483,10 +639,8 @@ function _globalKeyPressHandler(actor, event) {
function _findModal(actor) {
for (let i = 0; i < modalActorFocusStack.length; i++) {
let [stackActor, stackFocus] = modalActorFocusStack[i];
if (stackActor == actor) {
if (modalActorFocusStack[i].actor == actor)
return i;
}
}
return -1;
}
@ -512,7 +666,6 @@ function _findModal(actor) {
* Returns: true iff we successfully acquired a grab or already had one
*/
function pushModal(actor, timestamp) {
if (timestamp == undefined)
timestamp = global.get_current_time();
@ -526,20 +679,24 @@ function pushModal(actor, timestamp) {
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
modalCount += 1;
actor.connect('destroy', function() {
let actorDestroyId = actor.connect('destroy', function() {
let index = _findModal(actor);
if (index >= 0)
modalActorFocusStack.splice(index, 1);
});
let curFocus = global.stage.get_key_focus();
let curFocusDestroyId;
if (curFocus != null) {
curFocus.connect('destroy', function() {
curFocusDestroyId = curFocus.connect('destroy', function() {
let index = _findModal(actor);
if (index >= 0)
modalActorFocusStack[index][1] = null;
modalActorFocusStack[index].actor = null;
});
}
modalActorFocusStack.push([actor, curFocus]);
modalActorFocusStack.push({ actor: actor,
focus: curFocus,
destroyId: actorDestroyId,
focusDestroyId: curFocusDestroyId });
global.stage.set_key_focus(actor);
return true;
@ -559,28 +716,42 @@ function pushModal(actor, timestamp) {
* global.get_current_time() is assumed.
*/
function popModal(actor, timestamp) {
if (timestamp == undefined)
timestamp = global.get_current_time();
modalCount -= 1;
let focusIndex = _findModal(actor);
if (focusIndex >= 0) {
if (focusIndex == modalActorFocusStack.length - 1) {
let [stackActor, stackFocus] = modalActorFocusStack[focusIndex];
global.stage.set_key_focus(stackFocus);
} else {
// Remove from the middle, shift the focus chain up
for (let i = focusIndex; i < modalActorFocusStack.length - 1; i++) {
modalActorFocusStack[i + 1][1] = modalActorFocusStack[i][1];
}
}
modalActorFocusStack.splice(focusIndex, 1);
if (focusIndex < 0) {
global.stage.set_key_focus(null);
global.end_modal(timestamp);
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
throw new Error('incorrect pop');
}
modalCount -= 1;
let record = modalActorFocusStack[focusIndex];
record.actor.disconnect(record.destroyId);
if (focusIndex == modalActorFocusStack.length - 1) {
if (record.focus)
record.focus.disconnect(record.focusDestroyId);
global.stage.set_key_focus(record.focus);
} else {
let t = modalActorFocusStack[modalActorFocusStack.length - 1];
if (t.focus)
t.focus.disconnect(t.focusDestroyId);
// Remove from the middle, shift the focus chain up
for (let i = modalActorFocusStack.length - 1; i > focusIndex; i--) {
modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus;
modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId;
}
}
modalActorFocusStack.splice(focusIndex, 1);
if (modalCount > 0)
return;
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

View File

@ -39,13 +39,20 @@ ModalDialog.prototype = {
params = Params.parse(params, { styleClass: null });
this.state = State.CLOSED;
this._hasModal = false;
this._group = new St.Group({ visible: false,
x: 0,
y: 0 });
Main.uiGroup.add_actor(this._group);
let constraint = new Clutter.BindConstraint({ source: global.stage,
coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
this._group.add_constraint(constraint);
global.focus_manager.add_group(this._group);
this._initialKeyFocus = this._group;
this._savedKeyFocus = null;
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
@ -60,12 +67,18 @@ ModalDialog.prototype = {
this._group.add_actor(this._backgroundBin);
this._lightbox.highlight(this._backgroundBin);
this._backgroundStack = new Shell.Stack();
this._backgroundBin.child = this._backgroundStack;
this._eventBlocker = new Clutter.Group({ reactive: true });
this._backgroundStack.add_actor(this._eventBlocker);
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._backgroundStack.add_actor(this._dialogLayout);
this.contentLayout = new St.BoxLayout({ vertical: true });
this._dialogLayout.add(this.contentLayout,
@ -74,8 +87,9 @@ ModalDialog.prototype = {
x_align: St.Align.MIDDLE,
y_align: St.Align.START });
this._buttonLayout = new St.BoxLayout({ opacity: 220,
vertical: false });
this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
opacity: 220,
vertical: false });
this._dialogLayout.add(this._buttonLayout,
{ expand: true,
x_align: St.Align.MIDDLE,
@ -154,22 +168,23 @@ ModalDialog.prototype = {
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this._initialKeyFocus.grab_key_focus();
this.state = State.OPENED;
this.emit('opened');
}),
})
});
},
setInitialKeyFocus: function(actor) {
this._initialKeyFocus = actor;
},
open: function(timestamp) {
if (this.state == State.OPENED || this.state == State.OPENING)
return true;
if (!Main.pushModal(this._group, timestamp))
if (!this.pushModal(timestamp))
return false;
global.stage.set_key_focus(this._group);
this._fadeOpen();
return true;
},
@ -178,14 +193,8 @@ ModalDialog.prototype = {
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;
this.popModal(timestamp);
Tweener.addTween(this._group,
{ opacity: 0,
@ -195,13 +204,46 @@ ModalDialog.prototype = {
function() {
this.state = State.CLOSED;
this._group.hide();
if (needsPopModal)
Main.popModal(this._group, timestamp);
})
});
},
// Drop modal status without closing the dialog; this makes the
// dialog insensitive as well, so it needs to be followed shortly
// by either a close() or a pushModal()
popModal: function(timestamp) {
if (!this._hasModal)
return;
let focus = global.stage.key_focus;
if (focus && this._group.contains(focus))
this._savedKeyFocus = focus;
else
this._savedKeyFocus = null;
Main.popModal(this._group, timestamp);
global.gdk_screen.get_display().sync();
this._hasModal = false;
this._eventBlocker.raise_top();
},
pushModal: function (timestamp) {
if (this._hasModal)
return true;
if (!Main.pushModal(this._group, timestamp))
return false;
this._hasModal = true;
if (this._savedKeyFocus) {
this._savedKeyFocus.grab_key_focus();
this._savedKeyFocus = null;
} else
this._initialKeyFocus.grab_key_focus();
this._eventBlocker.lower_bottom();
return true;
},
// 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
@ -220,6 +262,7 @@ ModalDialog.prototype = {
if (this.state == State.FADED_OUT)
return;
this.popModal(timestamp);
Tweener.addTween(this._dialogLayout,
{ opacity: 0,
time: FADE_OUT_DIALOG_TIME,
@ -227,7 +270,6 @@ ModalDialog.prototype = {
onComplete: Lang.bind(this,
function() {
this.state = State.FADED_OUT;
Main.popModal(this._group, timestamp);
})
});
}

View File

@ -1,5 +1,6 @@
/* -*- 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;
@ -93,16 +94,6 @@ NotificationDaemon.prototype = {
_init: function() {
DBus.session.exportObject('/org/freedesktop/Notifications', this);
this._everAcquiredName = false;
DBus.session.acquire_name('org.freedesktop.Notifications',
// We pass MANY_INSTANCES so that if
// notification-daemon is running, we'll
// get queued behind it and then get the
// name after killing it below
DBus.MANY_INSTANCES,
Lang.bind(this, this._acquiredName),
Lang.bind(this, this._lostName));
this._sources = {};
this._senderToPid = {};
this._notifications = {};
@ -117,22 +108,6 @@ NotificationDaemon.prototype = {
Lang.bind(this, this._onFocusAppChanged));
},
_acquiredName: function() {
this._everAcquiredName = true;
},
_lostName: function() {
if (this._everAcquiredName)
log('Lost name org.freedesktop.Notifications!');
else if (GLib.getenv('GNOME_SHELL_NO_REPLACE'))
log('Failed to acquire org.freedesktop.Notifications');
else {
log('Failed to acquire org.freedesktop.Notifications; trying again');
Util.killall('notification-daemon');
Util.killall('notify-osd');
}
},
_iconForNotificationData: function(icon, hints, size) {
let textureCache = St.TextureCache.get_default();
@ -214,9 +189,11 @@ NotificationDaemon.prototype = {
actions, hints, timeout) {
let id;
// Filter out notifications from Empathy, since we
// Filter out chat and presence notifications from Empathy, since we
// handle that information from telepathyClient.js
if (appName == 'Empathy') {
if (appName == 'Empathy' && (hints['category'] == 'im.received' ||
hints['category'] == 'presence.online' ||
hints['category'] == 'presence.offline')) {
// Ignore replacesId since we already sent back a
// NotificationClosed for that id.
id = nextNotificationId++;
@ -371,7 +348,7 @@ NotificationDaemon.prototype = {
notification.setTransient(hints['transient'] == true);
let sourceIconActor = source.useNotificationIcon ? this._iconForNotificationData(icon, hints, source.ICON_SIZE) : null;
source.notify(notification, sourceIconActor);
source.processNotification(notification, sourceIconActor);
},
CloseNotification: function(id) {
@ -415,8 +392,7 @@ NotificationDaemon.prototype = {
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();
source.destroyNonResidentNotifications();
return;
}
}
@ -461,20 +437,57 @@ Source.prototype = {
MessageTray.Source.prototype._init.call(this, title);
this._pid = pid;
this._appStateChangedId = 0;
this._setApp();
if (this.app)
this.title = this.app.get_name();
else
this.useNotificationIcon = true;
this._isTrayIcon = false;
this._trayIcon = null;
},
notify: function(notification, icon) {
processNotification: function(notification, icon) {
if (!this.app)
this._setApp();
if (!this.app && icon)
this._setSummaryIcon(icon);
MessageTray.Source.prototype.notify.call(this, notification);
let tracker = Shell.WindowTracker.get_default();
if (notification.resident && this.app && tracker.focus_app == this.app)
this.pushNotification(notification);
else
this.notify(notification);
},
handleSummaryClick: function() {
if (!this._trayIcon)
return false;
let event = Clutter.get_current_event();
if (event.type() != Clutter.EventType.BUTTON_RELEASE)
return false;
// Left clicks are passed through only where there aren't unacknowledged
// notifications, so it possible to open them in summary mode; right
// clicks are always forwarded, as the right click menu is not useful for
// tray icons
if (event.get_button() == 1 &&
this.notifications.length > 0)
return false;
if (Main.overview.visible) {
// We can't just connect to Main.overview's 'hidden' signal,
// because it's emitted *before* it calls popModal()...
let id = global.connect('notify::stage-input-mode', Lang.bind(this,
function () {
global.disconnect(id);
this._trayIcon.click(event);
}));
Main.overview.hide();
} else {
this._trayIcon.click(event);
}
return true;
},
_setApp: function() {
@ -485,9 +498,13 @@ Source.prototype = {
if (!this.app)
return;
// We only update the app if this.app is null, so we can't disconnect the old this._appStateChangedId
// even if it were non-zero for some reason.
this._appStateChangedId = this.app.connect('notify::state', Lang.bind(this, this._appStateChanged));
// 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) {
if (!this._trayIcon) {
this.useNotificationIcon = false;
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
}
@ -496,15 +513,29 @@ Source.prototype = {
setTrayIcon: function(icon) {
this._setSummaryIcon(icon);
this.useNotificationIcon = false;
this._isTrayIcon = true;
this._trayIcon = icon;
},
_notificationClicked: function(notification) {
open: function(notification) {
this.destroyNonResidentNotifications();
this.openApp();
},
_notificationRemoved: function() {
if (!this._isTrayIcon)
_lastNotificationRemoved: function() {
if (!this._trayIcon)
this.destroy();
},
_appStateChanged: function() {
// Destroy notification sources when their apps exit.
// The app exiting would normally result in a tray icon being removed,
// so the associated source would be destroyed through the code path
// that handles the tray icon being removed. We should not destroy
// the source associated with a tray icon when the application state
// is Shell.AppState.STOPPED because running applications that have
// no open windows would also have that state. This is often the case
// for applications that use tray icons.
if (!this._trayIcon && this.app.get_state() == Shell.AppState.STOPPED)
this.destroy();
},
@ -517,5 +548,13 @@ Source.prototype = {
let mostRecentWindow = windows[0];
Main.activateWindow(mostRecentWindow);
}
},
destroy: function() {
if (this.app && this._appStateChangedId) {
this.app.disconnect(this._appStateChangedId);
this._appStateChangedId = 0;
}
MessageTray.Source.prototype.destroy.call(this);
}
};

View File

@ -24,6 +24,7 @@ const PlaceDisplay = imports.ui.placeDisplay;
const Tweener = imports.ui.tweener;
const ViewSelector = imports.ui.viewSelector;
const WorkspacesView = imports.ui.workspacesView;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
// Time for initial animation going into Overview mode
const ANIMATION_TIME = 0.25;
@ -74,11 +75,13 @@ ShellInfo.prototype = {
Main.messageTray.add(this._source);
}
let notification = this._source.notification;
if (notification == null)
let notification = null;
if (this._source.notifications.length == 0) {
notification = new MessageTray.Notification(this._source, text, null);
else
} else {
notification = this._source.notifications[0];
notification.update(text, null, { clear: true });
}
notification.setTransient(true);
@ -180,10 +183,10 @@ Overview.prototype = {
this._group.add_actor(this.viewSelector.actor);
this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
this.viewSelector.addViewTab(_("Windows"), this._workspacesDisplay.actor);
this.viewSelector.addViewTab('windows', _("Windows"), this._workspacesDisplay.actor, 'text-x-generic');
let appView = new AppDisplay.AllAppDisplay();
this.viewSelector.addViewTab(_("Applications"), appView.actor);
this.viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
// Default search providers
this.viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider());
@ -197,6 +200,10 @@ Overview.prototype = {
this.dash.actor.add_constraint(this.viewSelector.constrainY);
this.dash.actor.add_constraint(this.viewSelector.constrainHeight);
// Translators: this is the name of the dock/favorites area on
// the left of the overview
Main.ctrlAltTabManager.addGroup(this.dash.actor, _("Dash"), 'user-bookmarks');
},
_onDragBegin: function() {
@ -213,8 +220,18 @@ Overview.prototype = {
global.screen.get_workspace_by_index(this._lastActiveWorkspaceIndex).activate(time);
this.hideTemporarily();
}
this._resetWindowSwitchTimeout();
this._lastHoveredWindow = null;
DND.removeMonitor(this._dragMonitor);
this.endItemDrag();
},
_resetWindowSwitchTimeout: function() {
if (this._windowSwitchTimeoutId != 0) {
Mainloop.source_remove(this._windowSwitchTimeoutId);
this._windowSwitchTimeoutId = 0;
this._needsFakePointerEvent = false;
}
},
_fakePointerEvent: function() {
@ -229,7 +246,10 @@ Overview.prototype = {
_onDragMotion: function(dragEvent) {
let targetIsWindow = dragEvent.targetActor &&
dragEvent.targetActor._delegate &&
dragEvent.targetActor._delegate.metaWindow;
dragEvent.targetActor._delegate.metaWindow &&
!(dragEvent.targetActor._delegate instanceof WorkspaceThumbnail.WindowClone);
this._windowSwitchTimestamp = global.get_current_time();
if (targetIsWindow &&
dragEvent.targetActor._delegate.metaWindow == this._lastHoveredWindow)
@ -237,15 +257,10 @@ Overview.prototype = {
this._lastHoveredWindow = null;
if (this._windowSwitchTimeoutId != 0) {
Mainloop.source_remove(this._windowSwitchTimeoutId);
this._windowSwitchTimeoutId = 0;
this._needsFakePointerEvent = false;
}
this._resetWindowSwitchTimeout();
if (targetIsWindow) {
this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow;
this._windowSwitchTimestamp = global.get_current_time();
this._windowSwitchTimeoutId = Mainloop.timeout_add(DND_WINDOW_SWITCH_TIMEOUT,
Lang.bind(this, function() {
this._needsFakePointerEvent = true;
@ -428,7 +443,7 @@ Overview.prototype = {
let primary = global.get_primary_monitor();
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
let contentY = Panel.PANEL_HEIGHT;
let contentY = Main.panel.actor.height;
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
this._group.set_position(primary.x, primary.y);
@ -463,6 +478,10 @@ Overview.prototype = {
this.emit('item-drag-begin');
},
cancelledItemDrag: function(source) {
this.emit('item-drag-cancelled');
},
endItemDrag: function(source) {
this.emit('item-drag-end');
},
@ -471,35 +490,14 @@ Overview.prototype = {
this.emit('window-drag-begin');
},
cancelledWindowDrag: function(source) {
this.emit('window-drag-cancelled');
},
endWindowDrag: function(source) {
this.emit('window-drag-end');
},
// Returns the scale the Overview has when we just start zooming out
// to overview mode. That is, when just the active workspace is showing.
getZoomedInScale : function() {
return 1 / this.workspaces.getScale();
},
// Returns the position the Overview has when we just start zooming out
// to overview mode. That is, when just the active workspace is showing.
getZoomedInPosition : function() {
let [posX, posY] = this.workspaces.getActiveWorkspacePosition();
let scale = this.getZoomedInScale();
return [- posX * scale, - posY * scale];
},
// Returns the current scale of the Overview.
getScale : function() {
return this.workspaces.actor.scaleX;
},
// Returns the current position of the Overview.
getPosition : function() {
return [this.workspaces.actor.x, this.workspaces.actor.y];
},
// show:
//
// Animates the overview visible and grabs mouse and keyboard input
@ -507,7 +505,7 @@ Overview.prototype = {
if (this._shown)
return;
// Do this manually instead of using _syncInputMode, to handle failure
if (!Main.pushModal(this.viewSelector.actor))
if (!Main.pushModal(this._group))
return;
this._modal = true;
this._animateVisible();
@ -553,30 +551,13 @@ Overview.prototype = {
});
}
// Create a zoom out effect. First scale the workspaces view up and
// position it so that the active workspace fills up the whole screen,
// then transform it to its normal dimensions and position.
// The opposite transition is used in hide().
this.workspaces.actor.scaleX = this.workspaces.actor.scaleY = this.getZoomedInScale();
[this.workspaces.actor.x, this.workspaces.actor.y] = this.getZoomedInPosition();
let primary = global.get_primary_monitor();
Tweener.addTween(this.workspaces.actor,
{ x: primary.x - this._group.x,
y: primary.y - this._group.y,
scaleX: 1,
scaleY: 1,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
onComplete: this._showDone,
onCompleteScope: this
});
// Make the other elements fade in.
this._group.opacity = 0;
Tweener.addTween(this._group,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME
time: ANIMATION_TIME,
onComplete: this._showDone,
onCompleteScope: this
});
this._coverPane.raise_top();
@ -638,18 +619,6 @@ Overview.prototype = {
this.show();
},
/**
* getWorkspacesForWindow:
* @metaWindow: A #MetaWindow
*
* Returns the Workspaces object associated with the given window.
* This method is not be accessible if the overview is not open
* and will return %null.
*/
getWorkspacesForWindow: function(metaWindow) {
return this.workspaces;
},
//// Private methods ////
_syncInputMode: function() {
@ -661,20 +630,20 @@ Overview.prototype = {
if (this._shown) {
if (!this._modal) {
if (Main.pushModal(this.dash.actor))
if (Main.pushModal(this._group))
this._modal = true;
else
this.hide();
}
} else if (this._shownTemporarily) {
if (this._modal) {
Main.popModal(this.dash.actor);
Main.popModal(this._group);
this._modal = false;
}
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
} else {
if (this._modal) {
Main.popModal(this.dash.actor);
Main.popModal(this._group);
this._modal = false;
}
else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
@ -700,27 +669,13 @@ Overview.prototype = {
this.workspaces.hide();
// Create a zoom in effect by transforming the workspaces view so that
// the active workspace fills up the whole screen. The opposite
// transition is used in show().
let scale = this.getZoomedInScale();
let [posX, posY] = this.getZoomedInPosition();
Tweener.addTween(this.workspaces.actor,
{ x: posX,
y: posY,
scaleX: scale,
scaleY: scale,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
onComplete: this._hideDone,
onCompleteScope: this
});
// Make other elements fade out.
Tweener.addTween(this._group,
{ opacity: 0,
transition: 'easeOutQuad',
time: ANIMATION_TIME
time: ANIMATION_TIME,
onComplete: this._hideDone,
onCompleteScope: this
});
this._coverPane.raise_top();
@ -739,6 +694,7 @@ Overview.prototype = {
this._animateNotVisible();
this._syncInputMode();
global.sync_pointer();
},
_hideDone: function() {

View File

@ -13,6 +13,7 @@ const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Config = imports.misc.config;
const CtrlAltTab = imports.ui.ctrlAltTab;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu;
@ -21,17 +22,16 @@ const DateMenu = imports.ui.dateMenu;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const PANEL_HEIGHT = 26;
const PANEL_ICON_SIZE = 24;
const STARTUP_ANIMATION_TIME = 0.2;
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 SPINNER_ANIMATION_TIME = 0.2;
const STANDARD_TRAY_ICON_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'bluetooth', 'network', 'battery'];
const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
@ -44,13 +44,11 @@ const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
if (Config.HAVE_BLUETOOTH)
STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['bluetooth'] = imports.ui.status.bluetooth.Indicator;
// in org.gnome.desktop.interface
const CLOCK_FORMAT_KEY = 'clock-format';
// in org.gnome.shell.clock
const CLOCK_SHOW_DATE_KEY = 'show-date';
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
try {
STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['network'] = imports.ui.status.network.NMApplet;
} catch(e) {
log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
}
// To make sure the panel corners blend nicely with the panel,
// we draw background and borders the same way, e.g. drawing
@ -249,6 +247,10 @@ AppMenuButton.prototype = {
let bin = new St.Bin({ name: 'appMenu' });
this.actor.set_child(bin);
this.actor.reactive = false;
this._targetIsCurrent = false;
this._container = new Shell.GenericContainer();
bin.set_child(this._container);
this._container.connect('get-preferred-width', Lang.bind(this, this._getContentPreferredWidth));
@ -276,20 +278,13 @@ AppMenuButton.prototype = {
this.hide();
}));
this._updateId = 0;
this._animationStep = 0;
this._clipWidth = PANEL_ICON_SIZE;
this._direction = SPINNER_SPEED;
this._stop = true;
this._spinner = new AnimatedIcon('process-working.png',
this._spinner = new AnimatedIcon('process-working.svg',
PANEL_ICON_SIZE);
this._container.add_actor(this._spinner.actor);
this._spinner.actor.lower_bottom();
this._shadow = new St.Bin({ style_class: 'label-real-shadow' });
this._shadow.hide();
this._container.add_actor(this._shadow);
let tracker = Shell.WindowTracker.get_default();
tracker.connect('notify::focus-app', Lang.bind(this, this._sync));
tracker.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
@ -305,6 +300,10 @@ AppMenuButton.prototype = {
this._visible = true;
this.actor.show();
if (!this._targetIsCurrent)
return;
Tweener.removeTweens(this.actor);
Tweener.addTween(this.actor,
{ opacity: 255,
@ -317,6 +316,11 @@ AppMenuButton.prototype = {
return;
this._visible = false;
if (!this._targetIsCurrent) {
this.actor.hide();
return;
}
Tweener.removeTweens(this.actor);
Tweener.addTween(this.actor,
{ opacity: 0,
@ -339,62 +343,26 @@ AppMenuButton.prototype = {
this._iconBox.remove_clip();
},
_stopAnimation: function(animate) {
this._label.actor.remove_clip();
if (this._updateId) {
this._shadow.hide();
if (animate) {
Tweener.addTween(this._spinner.actor,
{ opacity: 0,
time: 0.2,
transition: "easeOutQuad",
onCompleteScope: this,
onComplete: function() {
this._spinner.actor.opacity = 255;
this._spinner.actor.hide();
}
});
}
Mainloop.source_remove(this._updateId);
this._updateId = 0;
}
if (!animate)
this._spinner.actor.hide();
},
stopAnimation: function() {
this._direction = SPINNER_SPEED * 3;
this._stop = true;
},
if (this._stop)
return;
_update: function() {
this._animationStep += this._direction;
if (this._animationStep > 1 && this._stop) {
this._animationStep = 1;
this._stopAnimation(true);
return false;
}
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 {
this._label.actor.set_clip(this._label.actor.width - this._clipWidth, 0, this._clipWidth, this.actor.height);
}
this._container.queue_relayout();
return true;
this._stop = true;
Tweener.addTween(this._spinner.actor,
{ opacity: 0,
time: SPINNER_ANIMATION_TIME,
transition: "easeOutQuad",
onCompleteScope: this,
onComplete: function() {
this._spinner.actor.opacity = 255;
this._spinner.actor.hide();
}
});
},
startAnimation: function() {
this._direction = SPINNER_SPEED;
this._stopAnimation(false);
this._animationStep = 0;
this._update();
this._stop = false;
this._updateId = Mainloop.timeout_add(SPINNER_UPDATE_TIMEOUT, Lang.bind(this, this._update));
this._spinner.actor.show();
this._shadow.show();
},
_getContentPreferredWidth: function(actor, forHeight, alloc) {
@ -410,7 +378,7 @@ AppMenuButton.prototype = {
let [minSize, naturalSize] = this._iconBox.get_preferred_height(forWidth);
alloc.min_size = minSize;
alloc.natural_size = naturalSize;
[minSizfe, naturalSize] = this._label.actor.get_preferred_height(forWidth);
[minSize, naturalSize] = this._label.actor.get_preferred_height(forWidth);
if (minSize > alloc.min_size)
alloc.min_size = minSize;
if (naturalSize > alloc.natural_size)
@ -456,18 +424,13 @@ AppMenuButton.prototype = {
this._label.actor.allocate(childBox, flags);
if (direction == St.TextDirection.LTR) {
childBox.x1 = Math.floor(iconWidth / 2) + this._clipWidth + this._shadow.width;
childBox.x1 = Math.floor(iconWidth / 2) + this._label.actor.width;
childBox.x2 = childBox.x1 + this._spinner.actor.width;
childBox.y1 = box.y1;
childBox.y2 = box.y2 - 1;
this._spinner.actor.allocate(childBox, flags);
childBox.x1 = Math.floor(iconWidth / 2) + this._clipWidth + 2;
childBox.x2 = childBox.x1 + this._shadow.width;
childBox.y1 = box.y1;
childBox.y2 = box.y2 - 1;
this._shadow.allocate(childBox, flags);
} else {
childBox.x1 = this._label.actor.width - this._clipWidth - this._spinner.actor.width;
childBox.x1 = -this._spinner.actor.width;
childBox.x2 = childBox.x1 + this._spinner.actor.width;
childBox.y1 = box.y1;
childBox.y2 = box.y2 - 1;
@ -506,13 +469,6 @@ AppMenuButton.prototype = {
lastStartedApp = this._startingApps[i];
let focusedApp = tracker.focus_app;
let targetApp = focusedApp != null ? focusedApp : lastStartedApp;
if (targetApp == this._targetApp) {
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING)
this.stopAnimation();
return;
}
this._stopAnimation();
if (!focusedApp) {
// If the app has just lost focus to the panel, pretend
@ -522,27 +478,56 @@ AppMenuButton.prototype = {
return;
}
let targetApp = focusedApp != null ? focusedApp : lastStartedApp;
if (targetApp == null) {
if (!this._targetIsCurrent)
return;
this.actor.reactive = false;
this._targetIsCurrent = false;
Tweener.removeTweens(this.actor);
Tweener.addTween(this.actor, { opacity: 0,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad' });
return;
}
if (!this._targetIsCurrent) {
this.actor.reactive = true;
this._targetIsCurrent = true;
Tweener.removeTweens(this.actor);
Tweener.addTween(this.actor, { opacity: 255,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad' });
}
if (targetApp == this._targetApp) {
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING)
this.stopAnimation();
return;
}
this._spinner.actor.hide();
if (this._iconBox.child != null)
this._iconBox.child.destroy();
this._iconBox.hide();
this._label.setText('');
this.actor.reactive = false;
this._targetApp = targetApp;
if (targetApp != null) {
let icon = targetApp.get_faded_icon(2 * PANEL_ICON_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._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.actor.reactive = true;
this._iconBox.set_child(icon);
this._iconBox.show();
this._iconBox.set_child(icon);
this._iconBox.show();
if (targetApp.get_state() == Shell.AppState.STARTING)
this.startAnimation();
}
if (targetApp.get_state() == Shell.AppState.STARTING)
this.startAnimation();
this.emit('changed');
}
@ -560,7 +545,7 @@ PanelCorner.prototype = {
this._side = side;
this.actor = new St.DrawingArea({ style_class: 'panel-corner' });
this.actor.connect('repaint', Lang.bind(this, this._repaint));
this.actor.connect('style-changed', Lang.bind(this, this._reposition));
this.actor.connect('style-changed', Lang.bind(this, this.relayout));
},
_repaint: function() {
@ -580,18 +565,19 @@ PanelCorner.prototype = {
cr.moveTo(0, 0);
if (this._side == St.Side.LEFT)
cr.arc(cornerRadius,
innerBorderWidth + outerBorderWidth + cornerRadius,
innerBorderWidth + cornerRadius,
cornerRadius, Math.PI, 3 * Math.PI / 2);
else
cr.arc(0,
innerBorderWidth + outerBorderWidth + cornerRadius,
innerBorderWidth + cornerRadius,
cornerRadius, 3 * Math.PI / 2, 2 * Math.PI);
cr.lineTo(cornerRadius, 0);
cr.closePath();
let savedPath = cr.copyPath();
let over = _over(outerBorderColor, backgroundColor);
let over = _over(innerBorderColor,
_over(outerBorderColor, backgroundColor));
Clutter.cairo_set_source_color(cr, over);
cr.fill();
@ -607,12 +593,12 @@ PanelCorner.prototype = {
cr.restore();
if (this._side == St.Side.LEFT)
cr.rectangle(cornerRadius - offset, 0, offset, innerBorderWidth);
cr.rectangle(cornerRadius - offset, 0, offset, outerBorderWidth);
else
cr.rectangle(0, 0, offset, innerBorderWidth);
cr.rectangle(0, 0, offset, outerBorderWidth);
cr.fill();
offset = innerBorderWidth + outerBorderWidth;
offset = innerBorderWidth;
Clutter.cairo_set_source_color(cr, backgroundColor);
cr.save();
@ -622,24 +608,194 @@ PanelCorner.prototype = {
cr.restore();
},
_reposition: function() {
relayout: function() {
let node = this.actor.get_theme_node();
let cornerRadius = node.get_length("-panel-corner-radius");
let innerBorderWidth = node.get_length('-panel-corner-inner-border-width');
let outerBorderWidth = node.get_length('-panel-corner-outer-border-width');
this.actor.set_size(cornerRadius,
innerBorderWidth + outerBorderWidth + cornerRadius);
innerBorderWidth + cornerRadius);
if (this._side == St.Side.LEFT)
this.actor.set_position(Main.panel.actor.x,
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth - outerBorderWidth);
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
else
this.actor.set_position(Main.panel.actor.x + Main.panel.actor.width - cornerRadius,
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth - outerBorderWidth);
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
}
};
/**
* HotCorner:
*
* This class manages the "hot corner" that can toggle switching to
* overview.
*/
function HotCorner(button) {
this._init(button);
}
HotCorner.prototype = {
_init : function(button) {
// This is the activities button associated with this hot corner,
// if this is on the primary monitor (or null with the corner is
// on a different monitor)
this._button = button;
// We use this flag to mark the case where the user has entered the
// hot corner and has not left both the hot corner and a surrounding
// guard area (the "environs"). This avoids triggering the hot corner
// multiple times due to an accidental jitter.
this._entered = false;
this.actor = new Clutter.Group({ width: 3,
height: 3,
reactive: true });
this._corner = new Clutter.Rectangle({ width: 1,
height: 1,
opacity: 0,
reactive: true });
this.actor.add_actor(this._corner);
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
this._corner.set_position(this.actor.width - this._corner.width, 0);
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
} else {
this._corner.set_position(0, 0);
}
this._activationTime = 0;
this.actor.connect('enter-event',
Lang.bind(this, this._onEnvironsEntered));
this.actor.connect('leave-event',
Lang.bind(this, this._onEnvironsLeft));
// Clicking on the hot corner environs should result in the same bahavior
// as clicking on the hot corner.
this.actor.connect('button-release-event',
Lang.bind(this, this._onCornerClicked));
// In addition to being triggered by the mouse enter event, the hot corner
// can be triggered by clicking on it. This is useful if the user wants to
// undo the effect of triggering the hot corner once in the hot corner.
this._corner.connect('enter-event',
Lang.bind(this, this._onCornerEntered));
this._corner.connect('button-release-event',
Lang.bind(this, this._onCornerClicked));
this._corner.connect('leave-event',
Lang.bind(this, this._onCornerLeft));
this._corner._delegate = this._corner;
this._corner.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);
}
}
});
Main.chrome.addActor(this.actor, { visibleInOverview: true, affectsStruts: false });
},
destroy: function() {
this.actor.destroy();
},
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
// We draw a ripple by using a source image and animating it scaling
// outwards and fading away. We want the ripples to move linearly
// or it looks unrealistic, but if the opacity of the ripple goes
// linearly to zero it fades away too quickly, so we use Tweener's
// 'onUpdate' to give a non-linear curve to the fade-away and make
// it more visible in the middle section.
let [x, y] = this._corner.get_transformed_position();
let ripple = new St.BoxLayout({ style_class: 'ripple-box',
opacity: 255 * Math.sqrt(startOpacity),
scale_x: startScale,
scale_y: startScale,
x: x,
y: y });
ripple._opacity = startOpacity;
if (ripple.get_direction() == St.TextDirection.RTL)
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
Tweener.addTween(ripple, { _opacity: finalOpacity,
scale_x: finalScale,
scale_y: finalScale,
delay: delay,
time: time,
transition: 'linear',
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
onComplete: function() { ripple.destroy(); } });
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);
},
_onEnvironsEntered : function() {
if (this._button)
this._button.hover = true;
},
_onCornerEntered : function() {
if (!this._entered) {
this._entered = true;
if (!Main.overview.animationInProgress) {
this._activationTime = Date.now() / 1000;
this.rippleAnimation();
Main.overview.toggle();
}
}
return false;
},
_onCornerClicked : function() {
if (!Main.overview.animationInProgress)
this.maybeToggleOverviewOnClick();
return false;
},
_onCornerLeft : function(actor, event) {
if (event.get_related() != this.actor)
this._entered = false;
// Consume event, otherwise this will confuse onEnvironsLeft
return true;
},
_onEnvironsLeft : function(actor, event) {
if (this._button)
this._button.hover = false;
if (event.get_related() != this._corner)
this._entered = false;
return false;
},
// Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
// of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
// and clicked the Activities button.
maybeToggleOverviewOnClick: function() {
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
Main.overview.toggle();
this._activationTime = 0;
}
}
function Panel() {
this._init();
@ -659,19 +815,14 @@ Panel.prototype = {
this.actor.remove_style_class_name('in-overview');
}));
this._leftPointerBarrier = 0;
this._rightPointerBarrier = 0;
this._menus = new PopupMenu.PopupMenuManager(this);
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
this._centerBox = new St.BoxLayout({ name: 'panelCenter' });
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
// This will eventually be automatic, see
// https://bugzilla.gnome.org/show_bug.cgi?id=584662
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
this._leftBox.add_style_pseudo_class('rtl');
this._rightBox.add_style_pseudo_class('rtl');
}
this._leftCorner = new PanelCorner(St.Side.LEFT);
this._rightCorner = new PanelCorner(St.Side.RIGHT);
@ -712,27 +863,6 @@ Panel.prototype = {
sideWidth = (allocWidth - centerWidth) / 2;
let childBox = new Clutter.ActorBox();
childBox.y1 = 0;
childBox.y2 = this._hotCornerEnvirons.height;
if (this.actor.get_direction() == St.TextDirection.RTL) {
childBox.x1 = allocWidth - this._hotCornerEnvirons.width;
childBox.x2 = allocWidth;
} else {
childBox.x1 = 0;
childBox.x2 = this._hotCornerEnvirons.width;
}
this._hotCornerEnvirons.allocate(childBox, flags);
childBox.y1 = 0;
childBox.y2 = this._hotCorner.height;
if (this.actor.get_direction() == St.TextDirection.RTL) {
childBox.x1 = allocWidth - this._hotCorner.width;
childBox.x2 = allocWidth;
} else {
childBox.x1 = 0;
childBox.x2 = this._hotCorner.width;
}
this._hotCorner.allocate(childBox, flags);
childBox.y1 = 0;
childBox.y2 = allocHeight;
@ -800,55 +930,7 @@ Panel.prototype = {
corner.actor.set_style_pseudo_class(pseudoClass);
}));
// We use this flag to mark the case where the user has entered the
// hot corner and has not left both the hot corner and a surrounding
// guard area (the "environs"). This avoids triggering the hot corner
// multiple times due to an accidental jitter.
this._hotCornerEntered = false;
this._hotCornerEnvirons = new Clutter.Rectangle({ width: 3,
height: 3,
opacity: 0,
reactive: true });
this._hotCorner = new Clutter.Rectangle({ width: 1,
height: 1,
opacity: 0,
reactive: true });
this._hotCornerActivationTime = 0;
this._hotCornerEnvirons.connect('leave-event',
Lang.bind(this, this._onHotCornerEnvironsLeft));
// Clicking on the hot corner environs should result in the same bahavior
// as clicking on the hot corner.
this._hotCornerEnvirons.connect('button-release-event',
Lang.bind(this, this._onHotCornerClicked));
// In addition to being triggered by the mouse enter event, the hot corner
// can be triggered by clicking on it. This is useful if the user wants to
// undo the effect of triggering the hot corner once in the hot corner.
this._hotCorner.connect('enter-event',
Lang.bind(this, this._onHotCornerEntered));
this._hotCorner.connect('button-release-event',
Lang.bind(this, this._onHotCornerClicked));
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);
this._hotCorner = null;
let appMenuButton = new AppMenuButton();
this._leftBox.add(appMenuButton.actor);
@ -894,7 +976,7 @@ Panel.prototype = {
// to switch to.
this.button.connect('clicked', Lang.bind(this, function(b) {
if (!Main.overview.animationInProgress) {
this._maybeToggleOverviewOnClick();
this._hotCorner.maybeToggleOverviewOnClick();
return true;
} else {
return false;
@ -917,6 +999,9 @@ Panel.prototype = {
Main.chrome.addActor(this._rightCorner.actor, { visibleInOverview: true,
affectsStruts: false,
affectsInputRegion: false });
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here',
{ sortGroup: CtrlAltTab.SortGroup.TOP });
},
_xdndShowOverview: function (actor) {
@ -938,6 +1023,14 @@ Panel.prototype = {
this.button._xdndTimeOut = 0;
},
// While there can be multiple hotcorners (one per monitor), the hot corner
// that is on top of the Activities button is special since it needs special
// coordination with clicking on that button
setHotCorner: function(corner) {
this._hotCorner = corner;
},
startStatusArea: function() {
for (let i = 0; i < STANDARD_TRAY_ICON_ORDER.length; i++) {
let role = STANDARD_TRAY_ICON_ORDER[i];
@ -957,12 +1050,51 @@ Panel.prototype = {
},
startupAnimation: function() {
this.actor.y = -this.actor.height;
let oldY = this.actor.y;
this.actor.y = oldY - this.actor.height;
Tweener.addTween(this.actor,
{ y: 0,
time: 0.2,
{ y: oldY,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad'
});
let oldCornerY = this._leftCorner.actor.y;
this._leftCorner.actor.y = oldCornerY - this.actor.height;
this._rightCorner.actor.y = oldCornerY - this.actor.height;
Tweener.addTween(this._leftCorner.actor,
{ y: oldCornerY,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad'
});
Tweener.addTween(this._rightCorner.actor,
{ y: oldCornerY,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad'
});
},
relayout: function() {
let primary = global.get_primary_monitor();
this.actor.set_position(primary.x, primary.y);
this.actor.set_size(primary.width, -1);
if (this._leftPointerBarrier)
global.destroy_pointer_barrier(this._leftPointerBarrier);
if (this._rightPointerBarrier)
global.destroy_pointer_barrier(this._rightPointerBarrier);
this._leftPointerBarrier =
global.create_pointer_barrier(primary.x, primary.y,
primary.x, primary.y + this.actor.height,
1 /* BarrierPositiveX */);
this._rightPointerBarrier =
global.create_pointer_barrier(primary.x + primary.width, primary.y,
primary.x + primary.width, primary.y + this.actor.height,
4 /* BarrierNegativeX */);
this._leftCorner.relayout();
this._rightCorner.relayout();
},
_onTrayIconAdded: function(o, icon, role) {
@ -1001,88 +1133,4 @@ Panel.prototype = {
this._trayBox.remove_actor(icon);
},
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
// We draw a ripple by using a source image and animating it scaling
// outwards and fading away. We want the ripples to move linearly
// or it looks unrealistic, but if the opacity of the ripple goes
// linearly to zero it fades away too quickly, so we use Tweener's
// 'onUpdate' to give a non-linear curve to the fade-away and make
// it more visible in the middle section.
let [x, y] = this._hotCorner.get_transformed_position();
let ripple = new St.BoxLayout({ style_class: 'ripple-box',
opacity: 255 * Math.sqrt(startOpacity),
scale_x: startScale,
scale_y: startScale,
x: x,
y: y });
ripple._opacity = startOpacity;
Tweener.addTween(ripple, { _opacity: finalOpacity,
scale_x: finalScale,
scale_y: finalScale,
delay: delay,
time: time,
transition: 'linear',
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
onComplete: function() { ripple.destroy(); } });
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;
if (!this._hotCornerEntered) {
this._hotCornerEntered = true;
if (!Main.overview.animationInProgress) {
this._hotCornerActivationTime = Date.now() / 1000;
this.rippleAnimation();
Main.overview.toggle();
}
}
return false;
},
_onHotCornerClicked : function() {
if (this._menus.grabbed)
return false;
if (!Main.overview.animationInProgress) {
this._maybeToggleOverviewOnClick();
}
return false;
},
_onHotCornerLeft : function(actor, event) {
if (event.get_related() != this._hotCornerEnvirons) {
this._hotCornerEntered = false;
}
return false;
},
_onHotCornerEnvironsLeft : function(actor, event) {
if (event.get_related() != this._hotCorner) {
this._hotCornerEntered = false;
}
return false;
},
// Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
// of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
// and clicked the Activities button.
_maybeToggleOverviewOnClick: function() {
if (this._hotCornerActivationTime == 0 || Date.now() / 1000 - this._hotCornerActivationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
Main.overview.toggle();
this._hotCornerActivationTime = 0;
}
};

View File

@ -1,7 +1,9 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk;
const St = imports.gi.St;
const Lang = imports.lang;
const PopupMenu = imports.ui.popupMenu;
const Main = imports.ui.main;
@ -20,32 +22,59 @@ Button.prototype = {
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.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0);
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
Main.chrome.addActor(this.menu.actor, { visibleInOverview: true,
affectsStruts: false });
this.menu.actor.hide();
},
_onButtonPress: function(actor, event) {
if (!this.menu.isOpen) {
// Setting the max-height won't do any good if the minimum height of the
// menu is higher then the screen; it's useful if part of the menu is
// scrollable so the minimum height is smaller than the natural height
let monitor = global.get_primary_monitor();
this.menu.actor.style = ('max-height: ' +
Math.round(monitor.height - Main.panel.actor.height) +
'px;');
}
this.menu.toggle();
},
_onKeyPress: function(actor, event) {
_onSourceKeyPress: 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_Escape && this.menu.isOpen) {
this.menu.close();
return true;
} else if (symbol == Clutter.KEY_Down) {
if (!this.menu.isOpen)
this.menu.toggle();
this.menu.activateFirst();
this.menu.actor.navigate_focus(this.actor, Gtk.DirectionType.DOWN, false);
return true;
} else
return false;
},
_onMenuKeyPress: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
let focusManager = St.FocusManager.get_for_stage(global.stage);
let group = focusManager.get_group(this.actor);
if (group) {
let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT;
group.navigate_focus(this.actor, direction, false);
return true;
}
}
return false;
},
_onOpenStateChanged: function(menu, open) {
if (open)
this.actor.add_style_pseudo_class('active');

View File

@ -176,37 +176,8 @@ PlacesManager.prototype = {
Util.spawn(['nautilus-connect-server']);
});
let networkApp = null;
try {
networkApp = Shell.AppSystem.get_default().load_from_desktop_file('gnome-network-scheme.desktop');
} catch(e) {
try {
networkApp = Shell.AppSystem.get_default().load_from_desktop_file('network-scheme.desktop');
} catch(e) {
log('Cannot create "Network" item, .desktop file not found or corrupt.');
}
}
if (networkApp != null) {
this._network = new PlaceInfo('special:network', networkApp.get_name(),
function(size) {
return networkApp.create_icon_texture(size);
},
function (params) {
params = Params.parse(params, { workspace: null,
timestamp: 0 });
networkApp.launch_full(params.timestamp, [],
params.workspace ? params.workspace.index() : -1);
});
}
this._defaultPlaces.push(this._home);
this._defaultPlaces.push(this._desktopMenu);
if (this._network)
this._defaultPlaces.push(this._network);
this._defaultPlaces.push(this._connect);
/*
@ -415,7 +386,10 @@ PlaceSearchProvider.prototype = {
return null;
return { 'id': resultId,
'name': placeInfo.name,
'icon': placeInfo.iconFactory(Search.RESULT_ICON_SIZE) };
'createIcon': function(size) {
return placeInfo.iconFactory(size);
}
};
},
activateResult: function(id, params) {

View File

@ -36,18 +36,21 @@ const PolkitAgent = imports.gi.PolkitAgent;
const ModalDialog = imports.ui.modalDialog;
function AuthenticationDialog(message, cookie, userNames) {
this._init(message, cookie, userNames);
function AuthenticationDialog(actionId, message, cookie, userNames) {
this._init(actionId, message, cookie, userNames);
}
AuthenticationDialog.prototype = {
__proto__: ModalDialog.ModalDialog.prototype,
_init: function(message, cookie, userNames) {
_init: function(actionId, message, cookie, userNames) {
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'polkit-dialog' });
this.actionId = actionId;
this.message = message;
this.userNames = userNames;
this._wasDismissed = false;
this._completed = false;
let mainContentBox = new St.BoxLayout({ style_class: 'polkit-dialog-main-layout',
vertical: false });
@ -68,7 +71,7 @@ AuthenticationDialog.prototype = {
{ y_align: St.Align.START });
this._subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline',
text: _('Authentication Required') });
text: _("Authentication Required") });
messageBox.add(this._subjectLabel,
{ y_fill: false,
@ -99,32 +102,35 @@ AuthenticationDialog.prototype = {
Lang.bind(this, this._onUserChanged));
// Special case 'root'
if (userName == 'root')
userRealName = _('Administrator');
let userIsRoot = false;
if (userName == 'root') {
userIsRoot = true;
userRealName = _("Administrator");
}
// Work around Gdm.UserManager returning an empty string for the real name
if (userRealName.length == 0)
userRealName = userName;
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
vertical: false });
messageBox.add(userBox);
this._userIcon = new St.Icon();
this._userIcon.hide();
userBox.add(this._userIcon,
{ x_fill: true,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.START });
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-label',
text: userRealName }));
userBox.add(userLabel,
{ x_fill: true,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
if (userIsRoot) {
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-root-label',
text: userRealName }));
messageBox.add(userLabel);
} else {
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
vertical: false });
messageBox.add(userBox);
this._userIcon = new St.Icon();
this._userIcon.hide();
userBox.add(this._userIcon,
{ x_fill: true,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.START });
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-label',
text: userRealName }));
userBox.add(userLabel,
{ x_fill: true,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
}
this._onUserChanged();
@ -133,45 +139,41 @@ AuthenticationDialog.prototype = {
this._passwordLabel = new St.Label(({ style_class: 'polkit-dialog-password-label' }));
this._passwordBox.add(this._passwordLabel);
this._passwordEntry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
text: _(''),
text: "",
can_focus: true});
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivate));
this._passwordBox.add(this._passwordEntry,
{expand: true });
this._passwordBox.hide();
this._errorBox = new St.BoxLayout({ style_class: 'polkit-dialog-error-box' });
messageBox.add(this._errorBox);
let errorIcon = new St.Icon({ icon_name: 'dialog-error',
icon_size: 24,
style_class: 'polkit-dialog-error-icon' });
this._errorBox.add(errorIcon, { y_align: St.Align.MIDDLE });
this._errorMessage = new St.Label({ style_class: 'polkit-dialog-error-label' });
this._errorMessage.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._errorMessage.clutter_text.line_wrap = true;
this._errorBox.add(this._errorMessage, { expand: true,
y_align: St.Align.MIDDLE,
y_fill: true });
this._errorBox.hide();
this._errorMessageLabel = new St.Label({ style_class: 'polkit-dialog-error-label' });
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._errorMessageLabel.clutter_text.line_wrap = true;
messageBox.add(this._errorMessageLabel);
this._errorMessageLabel.hide();
this._infoBox = new St.BoxLayout({ style_class: 'polkit-dialog-info-box' });
messageBox.add(this._infoBox);
let infoIcon = new St.Icon({ icon_name: 'dialog-information',
icon_size: 24,
style_class: 'polkit-dialog-info-icon' });
this._infoBox.add(infoIcon, { y_align: St.Align.MIDDLE });
this._infoMessage = new St.Label({ style_class: 'polkit-dialog-info-label'});
this._infoMessage.clutter_text.line_wrap = true;
this._infoBox.add(this._infoMessage, { expand: true,
y_align: St.Align.MIDDLE,
y_fill: true });
this._infoBox.hide();
this._infoMessageLabel = new St.Label({ style_class: 'polkit-dialog-info-label' });
this._infoMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._infoMessageLabel.clutter_text.line_wrap = true;
messageBox.add(this._infoMessageLabel);
this._infoMessageLabel.hide();
this.setButtons([{ label: _('Cancel'),
/* text is intentionally non-blank otherwise the height is not the same as for
* infoMessage and errorMessageLabel - but it is still invisible because
* gnome-shell.css sets the color to be transparent
*/
this._nullMessageLabel = new St.Label({ style_class: 'polkit-dialog-null-label',
text: 'abc'});
this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._nullMessageLabel.clutter_text.line_wrap = true;
messageBox.add(this._nullMessageLabel);
this._nullMessageLabel.show();
this.setButtons([{ label: _("Cancel"),
action: Lang.bind(this, this.cancel),
key: Clutter.Escape
},
{ label: _('Authenticate'),
{ label: _("Authenticate"),
action: Lang.bind(this, this._onAuthenticateButtonPressed)
}]);
@ -186,16 +188,45 @@ AuthenticationDialog.prototype = {
this._session.connect('request', Lang.bind(this, this._onSessionRequest));
this._session.connect('show-error', Lang.bind(this, this._onSessionShowError));
this._session.connect('show-info', Lang.bind(this, this._onSessionShowInfo));
// Delay focus grab to avoid ModalDialog stealing focus with
// its buttons
this.connect('opened',
Lang.bind(this, function() {
this._session.initiate();
this._passwordEntry.grab_key_focus();
}));
},
_emitDone: function(keepVisible) {
startAuthentication: function() {
this._session.initiate();
},
_ensureOpen: function() {
// NOTE: ModalDialog.open() is safe to call if the dialog is
// already open - it just returns true without side-effects
if (!this.open(global.get_current_time())) {
// This can fail if e.g. unable to get input grab
//
// In an ideal world this wouldn't happen (because the
// Shell is in complete control of the session) but that's
// just not how things work right now.
//
// One way to make this happen is by running 'sleep 3;
// pkexec bash' and then opening a popup menu.
//
// We could add retrying if this turns out to be a problem
log('polkitAuthenticationAgent: Failed to show modal dialog.' +
' Dismissing authentication request for action-id ' + this.actionId +
' cookie ' + this._cookie);
this._emitDone(false, true);
}
},
_emitDone: function(keepVisible, dismissed) {
if (!this._doneEmitted) {
this._doneEmitted = true;
this.emit('done', keepVisible);
this.emit('done', keepVisible, dismissed);
}
},
@ -204,8 +235,9 @@ AuthenticationDialog.prototype = {
this._session.response(response);
// When the user responds, dismiss already shown info and
// error texts (if any)
this._errorBox.hide();
this._infoBox.hide();
this._errorMessageLabel.hide();
this._infoMessageLabel.hide();
this._nullMessageLabel.show();
},
_onAuthenticateButtonPressed: function() {
@ -213,14 +245,35 @@ AuthenticationDialog.prototype = {
},
_onSessionCompleted: function(session, gainedAuthorization) {
this._passwordBox.hide();
this._emitDone(!gainedAuthorization);
if (this._completed)
return;
this._completed = true;
if (!gainedAuthorization) {
/* Unless we are showing an existing error message from the PAM
* module (the PAM module could be reporting the authentication
* error providing authentication-method specific information),
* show "Sorry, that didn't work. Please try again."
*/
if (!this._errorMessageLabel.visible && !this._wasDismissed) {
/* Translators: "that didn't work" refers to the fact that the
* requested authentication was not gained; this can happen
* because of an authentication error (like invalid password),
* for instance. */
this._errorMessageLabel.set_text(_("Sorry, that didn\'t work. Please try again."));
this._errorMessageLabel.show();
this._infoMessageLabel.hide();
this._nullMessageLabel.hide();
}
}
this._emitDone(!gainedAuthorization, false);
},
_onSessionRequest: function(session, request, echo_on) {
// Cheap localization trick
if (request == 'Password:')
this._passwordLabel.set_text(_('Password:'));
this._passwordLabel.set_text(_("Password:"));
else
this._passwordLabel.set_text(request);
@ -232,45 +285,56 @@ AuthenticationDialog.prototype = {
this._passwordBox.show();
this._passwordEntry.set_text('');
this._passwordEntry.grab_key_focus();
this._ensureOpen();
},
_onSessionShowError: function(session, text) {
this._passwordEntry.set_text('');
this._errorMessage.set_text(text);
this._errorBox.show();
this._errorMessageLabel.set_text(text);
this._errorMessageLabel.show();
this._infoMessageLabel.hide();
this._nullMessageLabel.hide();
this._ensureOpen();
},
_onSessionShowInfo: function(session, text) {
this._passwordEntry.set_text('');
this._infoMessage.set_text(text);
this._infoBox.show();
this._infoMessageLabel.set_text(text);
this._infoMessageLabel.show();
this._errorMessageLabel.hide();
this._nullMessageLabel.hide();
this._ensureOpen();
},
destroySession: function() {
if (this._session) {
this._session.cancel();
if (!this._completed)
this._session.cancel();
this._session = null;
}
},
_onUserChanged: function() {
if (this._user.is_loaded) {
let iconFileName = this._user.get_icon_file();
let iconFile = Gio.file_new_for_path(iconFileName);
let icon;
if (iconFile.query_exists(null)) {
icon = new Gio.FileIcon({file: iconFile});
} else {
icon = new Gio.ThemedIcon({name: 'avatar-default'});
if (this._userIcon) {
let iconFileName = this._user.get_icon_file();
let iconFile = Gio.file_new_for_path(iconFileName);
let icon;
if (iconFile.query_exists(null)) {
icon = new Gio.FileIcon({file: iconFile});
} else {
icon = new Gio.ThemedIcon({name: 'avatar-default'});
}
this._userIcon.set_gicon (icon);
this._userIcon.show();
}
this._userIcon.set_gicon (icon);
this._userIcon.show();
}
},
cancel: function() {
this._wasDismissed = true;
this.close(global.get_current_time());
this._emitDone(false);
this._emitDone(false, true);
},
};
@ -290,42 +354,40 @@ AuthenticationAgent.prototype = {
},
_onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
this._currentDialog = new AuthenticationDialog(message, cookie, userNames);
if (!this._currentDialog.open(global.get_current_time())) {
// This can fail if e.g. unable to get input grab
//
// In an ideal world this wouldn't happen (because the
// Shell is in complete control of the session) but that's
// just not how things work right now.
//
// We could add retrying if this turns out to be a problem
log('polkitAuthenticationAgent: Failed to show modal dialog');
this._currentDialog.destroySession();
this._currentDialog = null;
this._native.complete()
} else {
this._currentDialog.connect('done', Lang.bind(this, this._onDialogDone));
}
this._currentDialog = new AuthenticationDialog(actionId, message, cookie, userNames);
// We actually don't want to open the dialog until we know for
// sure that we're going to interact with the user. For
// example, if the password for the identity to auth is blank
// (which it will be on a live CD) then there will be no
// conversation at all... of course, we don't *know* that
// until we actually try it.
//
// See https://bugzilla.gnome.org/show_bug.cgi?id=643062 for more
// discussion.
this._currentDialog.connect('done', Lang.bind(this, this._onDialogDone));
this._currentDialog.startAuthentication();
},
_onCancel: function(nativeAgent) {
this._completeRequest(false);
this._completeRequest(false, false);
},
_onDialogDone: function(dialog, keepVisible) {
this._completeRequest(keepVisible);
_onDialogDone: function(dialog, keepVisible, dismissed) {
this._completeRequest(keepVisible, dismissed);
},
_reallyCompleteRequest: function() {
_reallyCompleteRequest: function(dismissed) {
this._currentDialog.close();
this._currentDialog.destroySession();
this._currentDialog = null;
this._isCompleting = false;
this._native.complete()
this._native.complete(dismissed)
},
_completeRequest: function(keepVisible) {
_completeRequest: function(keepVisible, wasDismissed) {
if (this._isCompleting)
return;
@ -337,10 +399,10 @@ AuthenticationAgent.prototype = {
Mainloop.timeout_add(2000,
Lang.bind(this,
function() {
this._reallyCompleteRequest();
this._reallyCompleteRequest(wasDismissed);
}));
} else {
this._reallyCompleteRequest();
this._reallyCompleteRequest(wasDismissed);
}
}
}

View File

@ -54,12 +54,14 @@ PopupBaseMenuItem.prototype = {
}
if (params.reactive && params.hover)
this.actor.connect('notify::hover', Lang.bind(this, this._onHoverChanged));
if (params.reactive)
if (params.reactive) {
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
this.actor.connect('key-focus-out', Lang.bind(this, this._onKeyFocusOut));
}
},
_onStyleChanged: function (actor) {
this._spacing = actor.get_theme_node().get_length('spacing');
this._spacing = Math.round(actor.get_theme_node().get_length('spacing'));
},
_onButtonReleaseEvent: function (actor, event) {
@ -81,6 +83,10 @@ PopupBaseMenuItem.prototype = {
this.setActive(true);
},
_onKeyFocusOut: function (actor) {
this.setActive(false);
},
_onHoverChanged: function (actor) {
this.setActive(actor.hover);
},
@ -167,6 +173,8 @@ PopupBaseMenuItem.prototype = {
cr.fill();
},
// This returns column widths in logical order (i.e. from the dot
// to the image), not in visual order (left to right)
getColumnWidths: function() {
let widths = [];
for (let i = 0, col = 0; i < this._children.length; i++) {
@ -218,19 +226,36 @@ PopupBaseMenuItem.prototype = {
_allocate: function(actor, box, flags) {
let height = box.y2 - box.y1;
let direction = this.actor.get_direction();
if (this._dot) {
// The dot is placed outside box
// one quarter of padding from the border of the container
// (so 3/4 from the inner border)
// (padding is box.x1)
let dotBox = new Clutter.ActorBox();
let dotWidth = Math.round(box.x1 / 2);
dotBox.x1 = Math.round(box.x1 / 4);
dotBox.x2 = dotBox.x1 + dotWidth;
if (direction == St.TextDirection.LTR) {
dotBox.x1 = Math.round(box.x1 / 4);
dotBox.x2 = dotBox.x1 + dotWidth;
} else {
dotBox.x2 = box.x2 + 3 * Math.round(box.x1 / 4);
dotBox.x1 = dotBox.x2 - dotWidth;
}
dotBox.y1 = Math.round(box.y1 + (height - dotWidth) / 2);
dotBox.y2 = dotBox.y1 + dotWidth;
this._dot.allocate(dotBox, flags);
}
let x = box.x1;
let x;
if (direction == St.TextDirection.LTR)
x = box.x1;
else
x = box.x2;
// if direction is ltr, x is the right edge of the last added
// actor, and it's constantly increasing, whereas if rtl, x is
// the left edge and it decreases
for (let i = 0, col = 0; i < this._children.length; i++) {
let child = this._children[i];
let childBox = new Clutter.ActorBox();
@ -238,9 +263,12 @@ PopupBaseMenuItem.prototype = {
let [minWidth, naturalWidth] = child.actor.get_preferred_width(-1);
let availWidth, extraWidth;
if (this._columnWidths) {
if (child.span == -1)
availWidth = box.x2 - x;
else {
if (child.span == -1) {
if (direction == St.TextDirection.LTR)
availWidth = box.x2 - x;
else
availWidth = x - box.x1;
} else {
availWidth = 0;
for (let j = 0; j < child.span; j++)
availWidth += this._columnWidths[col++];
@ -251,18 +279,36 @@ PopupBaseMenuItem.prototype = {
extraWidth = 0;
}
if (child.expand) {
childBox.x1 = x;
childBox.x2 = x + availWidth;
} else if (child.align === St.Align.CENTER) {
childBox.x1 = x + Math.round(extraWidth / 2);
childBox.x2 = childBox.x1 + naturalWidth;
} else if (child.align === St.Align.END) {
childBox.x2 = x + availWidth;
childBox.x1 = childBox.x2 - naturalWidth;
if (direction == St.TextDirection.LTR) {
if (child.expand) {
childBox.x1 = x;
childBox.x2 = x + availWidth;
} else if (child.align === St.Align.CENTER) {
childBox.x1 = x + Math.round(extraWidth / 2);
childBox.x2 = childBox.x1 + naturalWidth;
} else if (child.align === St.Align.END) {
childBox.x2 = x + availWidth;
childBox.x1 = childBox.x2 - naturalWidth;
} else {
childBox.x1 = x;
childBox.x2 = x + naturalWidth;
}
} else {
childBox.x1 = x;
childBox.x2 = x + naturalWidth;
if (child.expand) {
childBox.x1 = x - availWidth;
childBox.x2 = x;
} else if (child.align === St.Align.CENTER) {
childBox.x1 = x - Math.round(extraWidth / 2);
childBox.x2 = childBox.x1 + naturalWidth;
} else if (child.align === St.Align.END) {
// align to the left
childBox.x1 = x - availWidth;
childBox.x2 = childBox.x1 + naturalWidth;
} else {
// align to the right
childBox.x2 = x;
childBox.x1 = x - naturalWidth;
}
}
let [minHeight, naturalHeight] = child.actor.get_preferred_height(-1);
@ -271,7 +317,10 @@ PopupBaseMenuItem.prototype = {
child.actor.allocate(childBox, flags);
x += availWidth + this._spacing;
if (direction == St.TextDirection.LTR)
x += availWidth + this._spacing;
else
x -= availWidth + this._spacing;
}
}
};
@ -479,12 +528,30 @@ PopupSliderMenuItem.prototype = {
let sliderBorderColor = themeNode.get_color('-slider-border-color');
let sliderColor = themeNode.get_color('-slider-background-color');
let sliderActiveBorderColor = themeNode.get_color('-slider-active-border-color');
let sliderActiveColor = themeNode.get_color('-slider-active-background-color');
cr.setSourceRGBA (
sliderActiveColor.red / 255,
sliderActiveColor.green / 255,
sliderActiveColor.blue / 255,
sliderActiveColor.alpha / 255);
cr.rectangle(handleRadius, (height - sliderHeight) / 2, sliderWidth * this._value, sliderHeight);
cr.fillPreserve();
cr.setSourceRGBA (
sliderActiveBorderColor.red / 255,
sliderActiveBorderColor.green / 255,
sliderActiveBorderColor.blue / 255,
sliderActiveBorderColor.alpha / 255);
cr.setLineWidth(sliderBorderWidth);
cr.stroke();
cr.setSourceRGBA (
sliderColor.red / 255,
sliderColor.green / 255,
sliderColor.blue / 255,
sliderColor.alpha / 255);
cr.rectangle(handleRadius, (height - sliderHeight) / 2, sliderWidth, sliderHeight);
cr.rectangle(handleRadius + sliderWidth * this._value, (height - sliderHeight) / 2, sliderWidth * (1 - this._value), sliderHeight);
cr.fillPreserve();
cr.setSourceRGBA (
sliderBorderColor.red / 255,
@ -684,28 +751,6 @@ PopupImageMenuItem.prototype = {
}
};
function mod(a, b) {
return (a + b) % b;
}
function findNextInCycle(items, current, direction) {
let cur;
if (items.length == 0)
return current;
else if (items.length == 1)
return items[0];
if (current)
cur = items.indexOf(current);
else if (direction == 1)
cur = items.length - 1;
else
cur = 0;
return items[mod(cur + direction, items.length)];
}
function PopupMenuBase() {
throw new TypeError('Trying to instantiate abstract class PopupMenuBase');
}
@ -720,8 +765,18 @@ PopupMenuBase.prototype = {
} else {
this.box = new St.BoxLayout({ vertical: true });
}
this.box.connect_after('queue-relayout', Lang.bind(this, this._menuQueueRelayout));
this.isOpen = false;
// If set, we don't send events (including crossing events) to the source actor
// for the menu which causes its prelight state to freeze
this.blockSourceEvents = false;
// Can be set while a menu is up to let all events through without special
// menu handling useful for scrollbars in menus, and probably not otherwise.
this.passEvents = false;
this._activeMenuItem = null;
},
@ -822,6 +877,8 @@ PopupMenuBase.prototype = {
let columnWidths = [];
let items = this.box.get_children();
for (let i = 0; i < items.length; i++) {
if (!items[i].visible)
continue;
if (items[i]._delegate instanceof PopupBaseMenuItem || items[i]._delegate instanceof PopupMenuBase) {
let itemColumnWidths = items[i]._delegate.getColumnWidths();
for (let j = 0; j < itemColumnWidths.length; j++) {
@ -841,6 +898,16 @@ PopupMenuBase.prototype = {
}
},
// Because of the above column-width funniness, we need to do a
// queue-relayout on every item whenever the menu itself changes
// size, to force clutter to drop its cached size requests. (The
// menuitems will in turn call queue_relayout on their parent, the
// menu, but that call will be a no-op since the menu already
// has a relayout queued, so we won't get stuck in a loop.
_menuQueueRelayout: function() {
this.box.get_children().map(function (actor) { actor.queue_relayout(); });
},
addActor: function(actor) {
this.box.add(actor);
},
@ -861,17 +928,6 @@ PopupMenuBase.prototype = {
}
},
activateFirst: function() {
let children = this.box.get_children();
for (let i = 0; i < children.length; i++) {
let actor = children[i];
if (actor._delegate && actor._delegate instanceof PopupBaseMenuItem && actor.visible && actor.reactive) {
actor._delegate.setActive(true);
break;
}
}
},
toggle: function() {
if (this.isOpen)
this.close(true);
@ -909,6 +965,8 @@ PopupMenu.prototype = {
this.actor = this._boxPointer.actor;
this.actor._delegate = this;
this.actor.style_class = 'popup-menu-boxpointer';
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this._boxWrapper = new Shell.GenericContainer();
this._boxWrapper.connect('get-preferred-width', Lang.bind(this, this._boxGetPreferredWidth));
this._boxWrapper.connect('get-preferred-height', Lang.bind(this, this._boxGetPreferredHeight));
@ -937,6 +995,15 @@ PopupMenu.prototype = {
this.box.allocate(box, flags);
},
_onKeyPressEvent: function(actor, event) {
if (event.get_key_symbol() == Clutter.Escape) {
this.close(true);
return true;
}
return false;
},
setArrowOrigin: function(origin) {
this._boxPointer.setArrowOrigin(origin);
},
@ -975,45 +1042,109 @@ PopupSubMenu.prototype = {
__proto__: PopupMenuBase.prototype,
_init: function(sourceActor, sourceArrow) {
PopupMenuBase.prototype._init.call(this, sourceActor, 'popup-sub-menu');
PopupMenuBase.prototype._init.call(this, sourceActor);
this._arrow = sourceArrow;
this._arrow.rotation_center_z_gravity = Clutter.Gravity.CENTER;
this.actor = this.box;
// Since a function of a submenu might be to provide a "More.." expander
// with long content, we make it scrollable - the scrollbar will only take
// effect if a CSS max-height is set on the top menu.
this.actor = new St.ScrollView({ style_class: 'popup-sub-menu',
hscrollbar_policy: Gtk.PolicyType.NEVER,
vscrollbar_policy: Gtk.PolicyType.NEVER });
// StScrollbar plays dirty tricks with events, calling
// clutter_set_motion_events_enabled (FALSE) during the scroll; this
// confuses our event tracking, so we just turn it off during the
// scroll.
let vscroll = this.actor.get_vscroll_bar();
vscroll.connect('scroll-start',
Lang.bind(this, function() {
let topMenu = this._getTopMenu();
if (topMenu)
topMenu.passEvents = true;
}));
vscroll.connect('scroll-stop',
Lang.bind(this, function() {
let topMenu = this._getTopMenu();
if (topMenu)
topMenu.passEvents = false;
}));
this.actor.add_actor(this.box);
this.actor._delegate = this;
this.actor.clip_to_allocation = true;
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this.actor.hide();
},
_getTopMenu: function() {
let actor = this.actor.get_parent();
while (actor) {
if (actor._delegate && actor._delegate instanceof PopupMenu)
return actor._delegate;
actor = actor.get_parent();
}
return null;
},
_needsScrollbar: function() {
let topMenu = this._getTopMenu();
let [topMinHeight, topNaturalHeight] = topMenu.actor.get_preferred_height(-1);
let topThemeNode = topMenu.actor.get_theme_node();
let topMaxHeight = topThemeNode.get_max_height();
return topMaxHeight >= 0 && topNaturalHeight >= topMaxHeight;
},
open: function(animate) {
if (this.isOpen)
return;
this.isOpen = true;
// we don't implement the !animate case because that doesn't
// currently get used...
let [naturalHeight, minHeight] = this.actor.get_preferred_height(-1);
this.actor.height = 0;
this.actor.show();
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrow_rotation: 90,
height: naturalHeight,
time: 0.25,
onUpdateScope: this,
onUpdate: function() {
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
},
onCompleteScope: this,
onComplete: function() {
this.actor.set_height(-1);
this.emit('open-state-changed', true);
}
});
let needsScrollbar = this._needsScrollbar();
// St.ScrollView always requests space horizontally for a possible vertical
// scrollbar if in AUTOMATIC mode. Doing better would require implementation
// of width-for-height in St.BoxLayout and St.ScrollView. This looks bad
// when we *don't* need it, so turn off the scrollbar when that's true.
// Dynamic changes in whether we need it aren't handled properly.
this.actor.vscrollbar_policy =
needsScrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
// It looks funny if we animate with a scrollbar (at what point is
// the scrollbar added?) so just skip that case
if (animate && needsScrollbar)
animate = false;
if (animate) {
let [minHeight, naturalHeight] = this.actor.get_preferred_height(-1);
this.actor.height = 0;
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrow_rotation: 90,
height: naturalHeight,
time: 0.25,
onUpdateScope: this,
onUpdate: function() {
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
},
onCompleteScope: this,
onComplete: function() {
this.actor.set_height(-1);
this.emit('open-state-changed', true);
}
});
} else {
this._arrow.rotation_angle_z = 90;
this.emit('open-state-changed', true);
}
},
close: function(animate) {
@ -1025,6 +1156,9 @@ PopupSubMenu.prototype = {
if (this._activeMenuItem)
this._activeMenuItem.setActive(false);
if (animate && this._needsScrollbar())
animate = false;
if (animate) {
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
@ -1127,11 +1261,17 @@ PopupSubMenuMenuItem.prototype = {
},
_onKeyPressEvent: function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Right) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Right) {
this.menu.open(true);
this.menu.activateFirst();
this.menu.actor.navigate_focus(null, Gtk.DirectionType.DOWN, false);
return true;
} else if (symbol == Clutter.KEY_Left && this.menu.isOpen) {
this.menu.close();
return true;
}
return PopupBaseMenuItem.prototype._onKeyPressEvent.call(this, actor, event);
},
@ -1158,12 +1298,13 @@ PopupMenuManager.prototype = {
this.grabbed = false;
this._eventCaptureId = 0;
this._keyPressEventId = 0;
this._enterEventId = 0;
this._leaveEventId = 0;
this._keyFocusNotifyId = 0;
this._activeMenu = null;
this._menus = [];
this._preGrabInputMode = null;
this._grabbedFromKeynav = false;
},
addMenu: function(menu, position) {
@ -1172,15 +1313,13 @@ PopupMenuManager.prototype = {
openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
destroyId: menu.connect('destroy', Lang.bind(this, this._onMenuDestroy)),
enterId: 0,
focusInId: 0,
focusOutId: 0
focusInId: 0
};
let source = menu.sourceActor;
if (source) {
menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
menudata.focusInId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
menudata.focusOutId = source.connect('key-focus-out', Lang.bind(this, function() { this._onKeyFocusOut(menu); }));
}
if (position == undefined)
@ -1205,8 +1344,6 @@ PopupMenuManager.prototype = {
menu.sourceActor.disconnect(menudata.enterId);
if (menudata.focusInId)
menu.sourceActor.disconnect(menudata.focusInId);
if (menudata.focusOutId)
menu.sourceActor.disconnect(menudata.focusOutId);
this._menus.splice(position, 1);
},
@ -1215,10 +1352,10 @@ PopupMenuManager.prototype = {
Main.pushModal(this._owner.actor);
this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
// captured-event doesn't see enter/leave events
this._enterEventId = global.stage.connect('enter-event', Lang.bind(this, this._onEventCapture));
this._leaveEventId = global.stage.connect('leave-event', Lang.bind(this, this._onEventCapture));
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
this.grabbed = true;
},
@ -1226,49 +1363,47 @@ PopupMenuManager.prototype = {
_ungrab: function() {
global.stage.disconnect(this._eventCaptureId);
this._eventCaptureId = 0;
global.stage.disconnect(this._keyPressEventId);
this._keyPressEventId = 0;
global.stage.disconnect(this._enterEventId);
this._enterEventId = 0;
global.stage.disconnect(this._leaveEventId);
this._leaveEventId = 0;
global.stage.disconnect(this._keyFocusNotifyId);
this._keyFocusNotifyId = 0;
this.grabbed = false;
Main.popModal(this._owner.actor);
},
_onMenuOpenState: function(menu, open) {
if (open)
this._activeMenu = menu;
// Check what the focus was before calling pushModal/popModal
let focus = global.stage.key_focus;
let hadFocus = focus && this._activeMenuContains(focus);
if (open) {
if (!this.grabbed) {
this._preGrabInputMode = global.stage_input_mode;
this._grabbedFromKeynav = hadFocus;
this._grab();
}
this._activeMenu = menu;
// if the focus is not already associated with the menu,
// then focus the menu
let focus = global.stage.key_focus;
if (!this._activeMenuContains(focus))
menu.sourceActor.grab_key_focus();
if (hadFocus)
focus.grab_key_focus();
else
menu.actor.grab_key_focus();
} else if (menu == this._activeMenu) {
let focus = global.stage.key_focus;
let fromActive = this._activeMenuContains(focus);
if (this.grabbed)
this._ungrab();
this._activeMenu = null;
// If keynav was in effect before we grabbed, then we need
// to properly re-establish it after we ungrab. (popModal
// will have unset the focus.) If some part of the menu
// was focused at the time of the ungrab then focus its
// sourceActor. Otherwise just reset the focus to where it
// was right before the ungrab.
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED) {
global.stage_input_mode = Shell.StageInputMode.FOCUSED;
if (fromActive)
if (this._grabbedFromKeynav) {
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED)
global.stage_input_mode = Shell.StageInputMode.FOCUSED;
if (hadFocus && menu.sourceActor)
menu.sourceActor.grab_key_focus();
else
else if (focus)
focus.grab_key_focus();
}
}
@ -1296,29 +1431,20 @@ PopupMenuManager.prototype = {
return false;
},
_onKeyFocusOut: function(menu) {
if (!this.grabbed || menu != this._activeMenu)
_onKeyFocusChanged: function() {
if (!this.grabbed || !this._activeMenu)
return;
// We want to close the menu if the focus has moved somewhere
// other than inside the menu or to another menu's sourceActor.
// Unfortunately, when key-focus-out is emitted,
// stage.key_focus will be null. So we have to wait until
// after it emits the key-focus-in as well.
let id = global.stage.connect('notify::key-focus', Lang.bind(this,
function () {
global.stage.disconnect(id);
let focus = global.stage.key_focus;
if (focus) {
if (this._activeMenuContains(focus))
return;
if (focus._delegate && focus._delegate.menu &&
this._findMenu(focus._delegate.menu) != -1)
return;
}
if (menu != this._activeMenu)
return;
let focus = global.stage.key_focus;
if (!focus || this._activeMenuContains(focus))
return;
if (focus._delegate && this._findMenu(focus._delegate.menu) != -1)
return;
menu.close(true);
}));
this._closeMenu();
},
_onMenuDestroy: function(menu) {
@ -1335,14 +1461,20 @@ PopupMenuManager.prototype = {
return this._activeMenuContains(event.get_source());
},
_eventIsOnAnyMenuSource: function(event) {
_shouldBlockEvent: function(event) {
let src = event.get_source();
if (this._activeMenu != null && this._activeMenu.actor.contains(src))
return false;
for (let i = 0; i < this._menus.length; i++) {
let menu = this._menus[i].menu;
if (menu.sourceActor && menu.sourceActor.contains(src))
return true;
if (menu.sourceActor && !menu.blockSourceEvents && menu.sourceActor.contains(src)) {
return false;
}
}
return false;
return true;
},
_findMenu: function(item) {
@ -1354,18 +1486,6 @@ PopupMenuManager.prototype = {
return -1;
},
_nextMenu: function(pos, direction) {
for (let i = 1; i < this._menus.length; i++) {
let candidate = mod(pos + i * direction, this._menus.length);
let menu = this._menus[candidate].menu;
if (!menu.sourceActor || menu.sourceActor.visible)
return menu;
}
// no menu is found? this should not happen
// anyway stay on current menu
return this._menus[pos];
},
_onEventCapture: function(actor, event) {
if (!this.grabbed)
return false;
@ -1374,8 +1494,12 @@ PopupMenuManager.prototype = {
this._owner.menuEventFilter(event))
return true;
if (this._activeMenu != null && this._activeMenu.passEvents)
return false;
let activeMenuContains = this._eventIsOnActiveMenu(event);
let eventType = event.type();
if (eventType == Clutter.EventType.BUTTON_RELEASE) {
if (activeMenuContains) {
return false;
@ -1383,38 +1507,16 @@ PopupMenuManager.prototype = {
this._closeMenu();
return true;
}
} else if ((eventType == Clutter.EventType.BUTTON_PRESS && !activeMenuContains)
|| (eventType == Clutter.EventType.KEY_PRESS && event.get_key_symbol() == Clutter.Escape)) {
} else if (eventType == Clutter.EventType.BUTTON_PRESS && !activeMenuContains) {
this._closeMenu();
return true;
} else if (activeMenuContains || this._eventIsOnAnyMenuSource(event)) {
} else if (!this._shouldBlockEvent(event)) {
return false;
}
return true;
},
_onKeyPressEvent: function(actor, event) {
if (!this.grabbed || !this._activeMenu)
return false;
if (!this._eventIsOnActiveMenu(event))
return false;
let symbol = event.get_key_symbol();
if (symbol == Clutter.Left || symbol == Clutter.Right) {
let direction = symbol == Clutter.Right ? 1 : -1;
let pos = this._findMenu(this._activeMenu);
let next = this._nextMenu(pos, direction);
if (next != this._activeMenu) {
this._changeMenu(next);
next.activateFirst();
}
return true;
}
return false;
},
_closeMenu: function() {
if (this._activeMenu != null)
this._activeMenu.close(true);

View File

@ -22,6 +22,9 @@ const MAX_FILE_DELETED_BEFORE_INVALID = 10;
const HISTORY_KEY = 'command-history';
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
const DISABLE_COMMAND_LINE_KEY = 'disable-command-line';
const DIALOG_GROW_TIME = 0.1;
function CommandCompleter() {
@ -167,6 +170,7 @@ __proto__: ModalDialog.ModalDialog.prototype,
_init : function() {
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'run-dialog' });
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
global.settings.connect('changed::development-tools', Lang.bind(this, function () {
this._enableInternalCommands = global.settings.get_boolean('development-tools');
}));
@ -206,10 +210,7 @@ __proto__: ModalDialog.ModalDialog.prototype,
this._entryText = entry.clutter_text;
this.contentLayout.add(entry, { y_align: St.Align.START });
this.connect('opened',
Lang.bind(this, function() {
this._entryText.grab_key_focus();
}));
this.setInitialKeyFocus(this._entryText);
this._errorBox = new St.BoxLayout({ style_class: 'run-dialog-error-box' });
@ -234,31 +235,26 @@ __proto__: ModalDialog.ModalDialog.prototype,
this._commandCompleter = new CommandCompleter();
this._group.connect('notify::visible', Lang.bind(this._commandCompleter, this._commandCompleter.update));
this._history = new History.HistoryManager(HISTORY_KEY);
this._history.connect('changed', Lang.bind(this, function(history, text) {
this._entryText.set_text(text);
}));
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
entry: this._entryText });
this._entryText.connect('key-press-event', Lang.bind(this, function(o, e) {
let symbol = e.get_key_symbol();
if (symbol == Clutter.Down) {
this._history.nextItem(o.get_text());
return true;
}
if (symbol == Clutter.Up) {
this._history.prevItem(o.get_text());
return true;
}
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
this.popModal();
if (Shell.get_event_state(e) & Clutter.ModifierType.CONTROL_MASK)
this._run(o.get_text(), true);
else
this._run(o.get_text(), false);
if (!this._commandError)
this.close(global.get_current_time());
this.close();
else {
if (!this.pushModal())
this.close();
}
return true;
}
if (symbol == Clutter.Escape) {
this.close(global.get_current_time());
this.close();
return true;
}
if (symbol == Clutter.slash) {
@ -364,6 +360,9 @@ __proto__: ModalDialog.ModalDialog.prototype,
this._entryText.set_text('');
this._commandError = false;
if (this._lockdownSettings.get_boolean(DISABLE_COMMAND_LINE_KEY))
return;
ModalDialog.ModalDialog.prototype.open.call(this);
},

View File

@ -1,5 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const DBus = imports.dbus;
const Gio = imports.gi.Gio;
const Mainloop = imports.mainloop;
@ -68,6 +69,104 @@ function waitLeisure() {
};
}
const PerfHelperIface = {
name: 'org.gnome.Shell.PerfHelper',
methods: [{ name: 'CreateWindow', inSignature: 'iibb', outSignature: '' },
{ name: 'WaitWindows', inSignature: '', outSignature: '' },
{ name: 'DestroyWindows', inSignature: '', outSignature: ''}]
};
const PerfHelper = function () {
this._init();
};
PerfHelper.prototype = {
_init: function() {
DBus.session.proxifyObject(this, 'org.gnome.Shell.PerfHelper', '/org/gnome/Shell/PerfHelper');
}
};
DBus.proxifyPrototype(PerfHelper.prototype, PerfHelperIface);
let _perfHelper = null;
function _getPerfHelper() {
if (_perfHelper == null)
_perfHelper = new PerfHelper();
return _perfHelper;
}
/**
* createTestWindow:
* @width: width of window, in pixels
* @height: height of window, in pixels
* @alpha: whether the window should be alpha transparent
* @maximized: whethe the window should be created maximized
*
* Creates a window using gnome-shell-perf-helper for testing purposes.
* While this function can be used with yield in an automation
* script to pause until the D-Bus call to the helper process returns,
* because of the normal X asynchronous mapping process, to actually wait
* until the window has been mapped and exposed, use waitTestWindows().
*/
function createTestWindow(width, height, alpha, maximized) {
let cb;
let perfHelper = _getPerfHelper();
perfHelper.CreateWindowRemote(width, height, alpha, maximized,
function(result, excp) {
if (cb)
cb();
});
return function(callback) {
cb = callback;
};
}
/**
* waitTestWindows:
*
* Used within an automation script to pause until all windows previously
* created with createTestWindow have been mapped and exposed.
*/
function waitTestWindows() {
let cb;
let perfHelper = _getPerfHelper();
perfHelper.WaitWindowsRemote(function(result, excp) {
if (cb)
cb();
});
return function(callback) {
cb = callback;
};
}
/**
* destroyTestWindows:
*
* Destroys all windows previously created with createTestWindow().
* While this function can be used with yield in an automation
* script to pause until the D-Bus call to the helper process returns,
* this doesn't guarantee that Mutter has actually finished the destroy
* process because of normal X asynchronicity.
*/
function destroyTestWindows() {
let cb;
let perfHelper = _getPerfHelper();
perfHelper.DestroyWindowsRemote(function(result, excp) {
if (cb)
cb();
});
return function(callback) {
cb = callback;
};
}
/**
* defineScriptEvent
* @name: The event will be called script.<name>
@ -147,8 +246,8 @@ function _collect(scriptModule, outputFile) {
Shell.write_string_to_stream(out, '"events":\n');
Shell.PerfLog.get_default().dump_events(out);
let monitors = global.get_monitors()
let primary = global.get_primary_monitor()
let monitors = global.get_monitors();
let primary = global.get_primary_monitor();
Shell.write_string_to_stream(out, ',\n"monitors":\n[');
for (let i = 0; i < monitors.length; i++) {
let monitor = monitors[i];
@ -167,7 +266,21 @@ function _collect(scriptModule, outputFile) {
Shell.write_string_to_stream(out, ',\n"metrics":\n[ ');
let first = true;
for (let name in scriptModule.METRICS) {
let metric = scriptModule.METRICS[name];
let metric = scriptModule.METRICS[name];
// Extra checks here because JSON.stringify generates
// invalid JSON for undefined values
if (metric.description == null) {
log("Error: No description found for metric " + name);
continue;
}
if (metric.units == null) {
log("Error: No units found for metric " + name);
continue;
}
if (metric.value == null) {
log("Error: No value found for metric " + name);
continue;
}
if (!first)
Shell.write_string_to_stream(out, ',\n ');

View File

@ -15,8 +15,6 @@ 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.
@ -165,8 +163,9 @@ SearchProvider.prototype = {
* getResultInfo:
* @id: Result identifier string
*
* Return an object with 'id', 'name', (both strings) and 'icon' (Clutter.Texture)
* properties which describe the given search result.
* Return an object with 'id', 'name', (both strings) and 'createIcon'
* (function(size) returning a Clutter.Texture) properties which describe
* the given search result.
*/
getResultMeta: function(id) {
throw new Error('Not implemented');
@ -209,17 +208,6 @@ SearchProvider.prototype = {
*/
activateResult: function(id) {
throw new Error('Not implemented');
},
/**
* expandSearch:
*
* Called when the user clicks on the header for this
* search section. Should typically launch an external program
* displaying search results for that item type.
*/
expandSearch: function(terms) {
throw new Error('Not implemented');
}
};
Signals.addSignalMethods(SearchProvider.prototype);
@ -286,24 +274,18 @@ OpenSearchSystem.prototype = {
},
_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');
}
}
}));
let path = global.datadir + '/search_providers/' + fileName;
let source = Shell.get_file_contents_utf8_sync(path);
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() {

View File

@ -5,6 +5,7 @@ const Lang = imports.lang;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const DND = imports.ui.dnd;
@ -13,7 +14,7 @@ const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Search = imports.ui.search;
const MAX_SEARCH_RESULTS_ROWS = 2;
const MAX_SEARCH_RESULTS_ROWS = 1;
function SearchResult(provider, metaInfo, terms) {
@ -36,9 +37,7 @@ SearchResult.prototype = {
reactive: true,
track_hover: true });
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: Lang.bind(this, function(size) {
return this.metaInfo['icon'];
})});
{ createIcon: this.metaInfo['createIcon'] });
content.set_child(icon.actor);
}
this._content = content;
@ -51,6 +50,10 @@ SearchResult.prototype = {
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
draggable.connect('drag-cancelled',
Lang.bind(this, function() {
Main.overview.cancelledItemDrag(this);
}));
draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
@ -74,11 +77,12 @@ SearchResult.prototype = {
},
getDragActorSource: function() {
return this.metaInfo['icon'];
// not exactly right, but alignment problems are hard to notice
return this._content;
},
getDragActor: function(stageX, stageY) {
return new Clutter.Clone({ source: this.metaInfo['icon'] });
return this.metaInfo['createIcon'](Main.overview.dash.iconSize);
},
shellWorkspaceLaunch: function(params) {
@ -102,8 +106,30 @@ GridSearchResults.prototype = {
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;
this._width = 0;
this.actor.connect('notify::width', Lang.bind(this, function() {
this._width = this.actor.width;
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
this._tryAddResults();
}));
}));
this._notDisplayedResult = [];
this._terms = [];
},
_tryAddResults: function() {
let canDisplay = this._grid.childrenInRow(this._width) * MAX_SEARCH_RESULTS_ROWS
- this._grid.visibleItemsCount();
for (let i = Math.min(this._notDisplayedResult.length, canDisplay); i > 0; i--) {
let result = this._notDisplayedResult.shift();
let meta = this.provider.getResultMeta(result);
let display = new SearchResult(this.provider, meta, this._terms);
this._grid.addItem(display.actor);
}
},
getVisibleResultCount: function() {
@ -111,15 +137,15 @@ GridSearchResults.prototype = {
},
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);
}
// copy the lists
this._notDisplayedResult = results.slice(0);
this._terms = terms.slice(0);
this._tryAddResults();
},
clear: function () {
this._terms = [];
this._notDisplayedResult = [];
this._grid.removeAll();
this.selectionIndex = -1;
},
@ -243,18 +269,9 @@ SearchResults.prototype = {
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 title = new St.Label({ style_class: 'search-section-header',
text: provider.title });
providerBox.add(title);
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
x_fill: true,
@ -267,8 +284,7 @@ SearchResults.prototype = {
resultDisplayBin.set_child(resultDisplay.actor);
this._providerMeta.push({ actor: providerBox,
resultDisplay: resultDisplay,
count: count });
resultDisplay: resultDisplay });
this._content.add(providerBox);
},
@ -322,7 +338,6 @@ SearchResults.prototype = {
let meta = this._metaForProvider(provider);
meta.actor.show();
meta.resultDisplay.renderResults(providerResults, terms);
meta.count.set_text('' + providerResults.length);
}
if (this._selectedOpenSearchButton == -1)
@ -331,10 +346,6 @@ SearchResults.prototype = {
return true;
},
_onHeaderClicked: function(provider) {
provider.expandSearch(this._searchSystem.getTerms());
},
_modifyActorSelection: function(resultDisplay, up) {
let success;
let index = resultDisplay.getSelectionIndex();

View File

@ -25,16 +25,12 @@ const KEY_MOUSE_KEYS_ENABLED = 'mousekeys-enable';
const APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
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';
@ -42,25 +38,10 @@ 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 KEY_TEXT_SCALING_FACTOR = 'text-scaling-factor';
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);
}
@ -85,13 +66,13 @@ ATIndicator.prototype = {
let textZoom = this._buildFontItem();
this.menu.addMenuItem(textZoom);
let screenReader = this._buildItem(_("Screen Reader"), APPLICATIONS_SCHEMA,
'screen-reader-enabled');
this.menu.addMenuItem(screenReader);
// let screenReader = this._buildItem(_("Screen Reader"), APPLICATIONS_SCHEMA,
// 'screen-reader-enabled');
// this.menu.addMenuItem(screenReader);
let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
'screen-keyboard-enabled');
this.menu.addMenuItem(screenKeyboard);
// let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
// 'screen-keyboard-enabled');
// this.menu.addMenuItem(screenKeyboard);
let visualBell = this._buildItemGConf(_("Visual Alerts"), client, KEY_VISUAL_BELL);
this.menu.addMenuItem(visualBell);
@ -110,7 +91,8 @@ ATIndicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Universal Access Settings"), function() {
Util.spawnDesktop('gnome-universal-access-panel');
let app = Shell.AppSystem.get_default().get_app('gnome-universal-access-panel.desktop');
app.activate(-1);
});
},
@ -194,30 +176,23 @@ ATIndicator.prototype = {
},
_buildFontItem: function() {
let settings = new Gio.Settings({ schema: XSETTINGS_SCHEMA });
let settings = new Gio.Settings({ schema: DESKTOP_INTERFACE_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 factor = settings.get_double(KEY_TEXT_SCALING_FACTOR);
let initial_setting = (factor > 1.0);
let widget = this._buildItemExtended(_("Large Text"),
initial_setting,
settings.is_writable(KEY_DPI),
settings.is_writable(KEY_TEXT_SCALING_FACTOR),
function (enabled) {
if (enabled)
settings.set_double(KEY_DPI, DPI_FACTOR_LARGE * default_value);
settings.set_double(KEY_TEXT_SCALING_FACTOR,
DPI_FACTOR_LARGE);
else
settings.set_double(KEY_DPI, default_value);
settings.reset(KEY_TEXT_SCALING_FACTOR);
});
settings.connect('changed::' + KEY_DPI, function() {
let active = on_get();
default_value = active ? x_value : user_value;
settings.connect('changed::' + KEY_TEXT_SCALING_FACTOR, function() {
let factor = settings.get_double(KEY_TEXT_SCALING_FACTOR);
let active = (factor > 1.0);
widget.setToggleState(active);
});
return widget;

View File

@ -93,7 +93,8 @@ Indicator.prototype = {
this._updateFullMenu();
this.menu.addAction(_("Bluetooth Settings"), function() {
GLib.spawn_command_line_async('gnome-control-center bluetooth');
let app = Shell.AppSystem.get_default().get_app('bluetooth-properties.desktop');
app.activate(-1);
});
this._applet.connect('pincode-request', Lang.bind(this, this._pinRequest));
@ -136,6 +137,7 @@ Indicator.prototype = {
_updateDevices: function() {
let devices = this._applet.get_devices();
let newlist = [ ];
for (let i = 0; i < this._deviceItems.length; i++) {
let item = this._deviceItems[i];
let destroy = true;
@ -143,26 +145,20 @@ Indicator.prototype = {
// 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;
if (this._deviceCompare(item._device, devices[j])) {
item.label.text = devices[j].alias;
devices[j]._skip = true;
destroy = false;
break;
}
}
if (destroy) {
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)
else
newlist.push(item);
}
this._deviceItems = newlist;
this._deviceItems = newlist;
this._hasDevices = newlist.length > 0;
for (let i = 0; i < devices.length; i++) {
let d = devices[i];
@ -471,9 +467,15 @@ PinNotification.prototype = {
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
if (this._numeric) {
let num = parseInt(this._entry.text);
if (isNaN(num)) {
// user reply was empty, or was invalid
// cancel the operation
num = -1;
}
this._applet.agent_reply_passkey(this._devicePath, num);
} else
this._applet.agent_reply_pincode(this._devicePath, this._entry.text);
} else {
if (this._numeric)

View File

@ -71,10 +71,11 @@ XKBIndicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Show Keyboard Layout..."), Lang.bind(this, function() {
Util.spawn(['gkbd-keyboard-display', '-g', this._config.get_current_group() + 1]);
Util.spawn(['gkbd-keyboard-display', '-g', String(this._config.get_current_group() + 1)]);
}));
this.menu.addAction(_("Localization Settings"), function() {
Util.spawn(['gnome-control-center', 'region']);
let app = Shell.AppSystem.get_default().get_app('gnome-region-panel.desktop');
app.activate(-1);
});
},

2138
js/ui/status/network.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -49,7 +49,7 @@ const PowerManagerInterface = {
{ name: 'GetPrimaryDevice', inSignature: '', outSignature: '(susbut)' },
],
signals: [
{ name: 'Changed', outSignature: '' },
{ name: 'Changed', inSignature: '' },
],
properties: [
{ name: 'Icon', signature: 's', access: 'read' },
@ -72,7 +72,7 @@ Indicator.prototype = {
this._hasPrimary = false;
this._primaryDeviceId = null;
this._batteryItem = new PopupMenu.PopupMenuItem('');
this._batteryItem = new PopupMenu.PopupMenuItem('', { reactive: false });
this._primaryPercentage = new St.Label();
this._batteryItem.addActor(this._primaryPercentage, { align: St.Align.END });
this.menu.addMenuItem(this._batteryItem);
@ -83,7 +83,8 @@ Indicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Power Settings"),function() {
Util.spawnDesktop('gnome-power-panel');
let app = Shell.AppSystem.get_default().get_app('gnome-power-panel.desktop');
app.activate(-1);
});
this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
@ -104,21 +105,27 @@ Indicator.prototype = {
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");
if (time == 0) {
// 0 is reported when UPower does not have enough data
// to estimate battery life
this._batteryItem.label.text = _("Estimating...");
} else {
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;
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)
@ -130,17 +137,6 @@ Indicator.prototype = {
}
this._primaryDeviceId = device_id;
if (this._primaryDeviceId) {
this._batteryItem.actor.reactive = true;
this._batteryItem.actor.can_focus = true;
this._batteryItem.connect('activate', function(item) {
Util.spawn(['gnome-power-statistics', '--device', device_id]);
});
} else {
// virtual device
this._batteryItem.actor.reactive = false;
this._batteryItem.actor.can_focus = false;
}
}));
},
@ -162,9 +158,6 @@ Indicator.prototype = {
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++;
@ -210,7 +203,7 @@ DeviceItem.prototype = {
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
_init: function(device) {
PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
PopupMenu.PopupBaseMenuItem.prototype._init.call(this, { reactive: false });
let [device_id, device_type, icon, percentage, state, time] = device;

View File

@ -16,7 +16,6 @@ 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 % */
const VOLUME_NOTIFY_ID = 1;
@ -37,6 +36,8 @@ Indicator.prototype = {
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._volumeMax = this._control.get_vol_max_norm();
this._volumeMaxAmplified = this._control.get_vol_max_amplified();
this._output = null;
this._outputVolumeId = 0;
@ -63,7 +64,8 @@ Indicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Sound Settings"), function() {
Util.spawnDesktop('gnome-sound-panel');
let app = Shell.AppSystem.get_default().get_app('gnome-sound-panel.desktop');
app.activate(-1);
});
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
@ -72,9 +74,9 @@ Indicator.prototype = {
_getMaxVolume: function(property) {
if (this[property].get_can_decibel())
return (VOLUME_MAX * 1.5);
return this._volumeMaxAmplified;
else
return VOLUME_MAX;
return this._volumeMax;
},
_onScrollEvent: function(actor, event) {

View File

@ -19,7 +19,8 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'a11y-keyboard': 'a11y',
'kbd-scrolllock': 'keyboard',
'kbd-numlock': 'keyboard',
'kbd-capslock': 'keyboard'
'kbd-capslock': 'keyboard',
'ibus-ui-gtk': 'input-method'
};
function StatusIconDispatcher() {

View File

@ -1,10 +1,13 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gdm = imports.gi.Gdm;
const DBus = imports.dbus;
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 Tp = imports.gi.TelepathyGLib;
const UPowerGlib = imports.gi.UPowerGlib;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
@ -15,6 +18,21 @@ const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const BUS_NAME = 'org.gnome.ScreenSaver';
const OBJECT_PATH = '/org/gnome/ScreenSaver';
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
const ScreenSaverInterface = {
name: BUS_NAME,
methods: [ { name: 'Lock', inSignature: '' } ]
};
let ScreenSaverProxy = DBus.makeProxyClass(ScreenSaverInterface);
// Adapted from gdm/gui/user-switch-applet/applet.c
//
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
@ -32,15 +50,20 @@ StatusMenuButton.prototype = {
let box = new St.BoxLayout({ name: 'panelStatusMenu' });
this.actor.set_child(box);
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
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._session = new GnomeSession.SessionManager();
this._account_mgr = Tp.AccountManager.dup()
this._upClient = new UPowerGlib.Client();
this._screenSaverProxy = new ScreenSaverProxy(DBus.session, BUS_NAME, OBJECT_PATH);
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._iconBox = new St.Bin();
@ -64,6 +87,15 @@ StatusMenuButton.prototype = {
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));
this._lockdownSettings.connect('changed::' + DISABLE_USER_SWITCH_KEY,
Lang.bind(this, this._updateSwitchUser));
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
Lang.bind(this, this._updateLogout));
this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
Lang.bind(this, this._updateLockScreen));
this._updateSwitchUser();
this._updateLogout();
this._updateLockScreen();
this._upClient.connect('notify::can-suspend', Lang.bind(this, this._updateSuspendOrPowerOff));
},
@ -80,11 +112,41 @@ StatusMenuButton.prototype = {
this._name.set_text("");
},
_updateSessionSeparator: function() {
let showSeparator = this._loginScreenItem.actor.visible ||
this._logoutItem.actor.visible ||
this._lockScreenItem.actor.visible;
if (showSeparator)
this._sessionSeparator.actor.show();
else
this._sessionSeparator.actor.hide();
},
_updateSwitchUser: function() {
if (this._gdm.can_switch ())
let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
if (allowSwitch && this._gdm.can_switch ())
this._loginScreenItem.actor.show();
else
this._loginScreenItem.actor.hide();
this._updateSessionSeparator();
},
_updateLogout: function() {
let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
if (allowLogout)
this._logoutItem.actor.show();
else
this._logoutItem.actor.hide();
this._updateSessionSeparator();
},
_updateLockScreen: function() {
let allowLockScreen = !this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
if (allowLockScreen)
this._lockScreenItem.actor.show();
else
this._lockScreenItem.actor.hide();
this._updateSessionSeparator();
},
_updateSuspendOrPowerOff: function() {
@ -98,7 +160,7 @@ StatusMenuButton.prototype = {
if (!this._haveSuspend) {
this._suspendOrPowerOffItem.updateText(_("Power Off..."), null);
} else {
this._suspendOrPowerOffItem.updateText(_("Suspend"), ("Power Off..."));
this._suspendOrPowerOffItem.updateText(_("Suspend"), _("Power Off..."));
}
},
@ -146,6 +208,7 @@ StatusMenuButton.prototype = {
item = new PopupMenu.PopupMenuItem(_("Lock Screen"));
item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
this.menu.addMenuItem(item);
this._lockScreenItem = item;
item = new PopupMenu.PopupMenuItem(_("Switch User"));
item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
@ -155,9 +218,11 @@ StatusMenuButton.prototype = {
item = new PopupMenu.PopupMenuItem(_("Log Out..."));
item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
this.menu.addMenuItem(item);
this._logoutItem = item;
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
this._sessionSeparator = item;
item = new PopupMenu.PopupAlternatingMenuItem(_("Suspend"),
_("Power Off..."));
@ -169,21 +234,25 @@ StatusMenuButton.prototype = {
_setPresenceStatus: function(item, event, status) {
this._presence.setStatus(status);
this._setIMStatus(status);
},
_onMyAccountActivate: function() {
Main.overview.hide();
Util.spawnDesktop('gnome-user-accounts-panel');
let app = Shell.AppSystem.get_default().get_app('gnome-user-accounts-panel.desktop');
app.activate(-1);
},
_onPreferencesActivate: function() {
Main.overview.hide();
Util.spawnDesktop('gnome-control-center');
let app = Shell.AppSystem.get_default().get_app('gnome-control-center.desktop');
app.activate(-1);
},
_onLockScreenActivate: function() {
Main.overview.hide();
Util.spawn(['gnome-screensaver-command', '--lock']);
this._screenSaverProxy.LockRemote();
},
_onLoginScreenActivate: function() {
@ -194,7 +263,7 @@ StatusMenuButton.prototype = {
_onQuitSessionActivate: function() {
Main.overview.hide();
Util.spawn(['gnome-session-save', '--logout-dialog']);
this._session.LogoutRemote(0);
},
_onSuspendOrPowerOffActivate: function() {
@ -202,9 +271,37 @@ StatusMenuButton.prototype = {
if (this._haveSuspend &&
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
this._upClient.suspend_sync(null);
this._screenSaverProxy.LockRemote(Lang.bind(this, function() {
this._upClient.suspend_sync(null);
}));
} else {
Util.spawn(['gnome-session-save', '--shutdown-dialog']);
this._session.ShutdownRemote();
}
},
_setIMStatus: function(session_status) {
let [presence_type, presence_status, msg] = this._account_mgr.get_most_available_presence();
let type, status;
// We change the IM presence only if there are connected accounts
if (presence_type == Tp.ConnectionPresenceType.UNSET ||
presence_type == Tp.ConnectionPresenceType.OFFLINE ||
presence_type == Tp.ConnectionPresenceType.UNKNOWN ||
presence_type == Tp.ConnectionPresenceType.ERROR)
return;
if (session_status == GnomeSession.PresenceStatus.AVAILABLE) {
type = Tp.ConnectionPresenceType.AVAILABLE;
status = "available";
}
else if (session_status == GnomeSession.PresenceStatus.BUSY) {
type = Tp.ConnectionPresenceType.BUSY;
status = "busy";
}
else {
return;
}
this._account_mgr.set_all_requested_presences(type, status, msg);
}
};

View File

@ -7,10 +7,13 @@ const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Tpl = imports.gi.TelepathyLogger;
const Tp = imports.gi.TelepathyGLib;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const C_ = Gettext.pgettext;
const History = imports.misc.history;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
@ -21,6 +24,9 @@ const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes
const SCROLLBACK_RECENT_LENGTH = 20;
const SCROLLBACK_IDLE_LENGTH = 5;
// See Source._displayPendingMessages
const SCROLLBACK_HISTORY_LINES = 10;
const NotificationDirection = {
SENT: 'chat-sent',
RECEIVED: 'chat-received'
@ -35,13 +41,37 @@ let contactFeatures = [Tp.ContactFeature.ALIAS,
// lets us see messages even if they belong to another app (eg,
// Empathy).
function makeMessageFromTpMessage(tpMessage, direction) {
let [text, flags] = tpMessage.to_text();
return {
messageType: tpMessage.get_message_type(),
text: text,
sender: tpMessage.sender.alias,
timestamp: tpMessage.get_received_timestamp(),
direction: direction
};
}
function makeMessageFromTplEvent(event) {
let sent = event.get_sender().get_entity_type() == Tpl.EntityType.SELF;
let direction = sent ? NotificationDirection.SENT : NotificationDirection.RECEIVED;
return {
messageType: event.get_message_type(),
text: event.get_message(),
sender: event.get_sender().get_alias(),
timestamp: event.get_timestamp(),
direction: direction
};
}
function Client() {
this._init();
};
Client.prototype = {
_init : function() {
this._accounts = {};
// channel path -> Source
this._sources = {};
@ -55,7 +85,7 @@ Client.prototype = {
// We only care about single-user text-based chats
let props = {};
props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
props[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.HandleType.CONTACT;
this._observer.add_observer_filter(props);
@ -68,7 +98,22 @@ Client.prototype = {
_observeChannels: function(observer, account, conn, channels,
dispatchOp, requests, context) {
let connPath = conn.get_object_path();
// If the self_contact doesn't have the ALIAS, make sure
// to fetch it before trying to grab the channels.
let self_contact = conn.get_self_contact();
if (self_contact.has_feature(Tp.ContactFeature.ALIAS)) {
this._finishObserveChannels(account, conn, channels, context);
} else {
Shell.get_self_contact_features(conn,
contactFeatures.length, contactFeatures,
Lang.bind(this, function() {
this._finishObserveChannels(account, conn, channels, context);
}));
context.delay();
}
},
_finishObserveChannels: function(account, conn, channels, context) {
let len = channels.length;
for (let i = 0; i < len; i++) {
let channel = channels[i];
@ -91,7 +136,6 @@ Client.prototype = {
}), null);
}
// Allow dbus method to return
context.accept();
},
@ -117,7 +161,7 @@ Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(account, conn, channel, contact) {
MessageTray.Source.prototype._init.call(this, channel.get_identifier());
MessageTray.Source.prototype._init.call(this, contact.get_alias());
this.isChat = true;
@ -128,8 +172,6 @@ Source.prototype = {
this._channel = channel;
this._closedId = this._channel.connect('invalidated', Lang.bind(this, this._channelClosed));
this._updateAlias();
this._notification = new Notification(this);
this._notification.setUrgency(MessageTray.Urgency.HIGH);
@ -144,11 +186,18 @@ Source.prototype = {
this._notifyAvatarId = this._contact.connect('notify::avatar-file', Lang.bind(this, this._updateAvatarIcon));
this._presenceChangedId = this._contact.connect('presence-changed', Lang.bind(this, this._presenceChanged));
this._displayPendingMessages();
// Add ourselves as a source.
Main.messageTray.add(this);
this.pushNotification(this._notification);
this._getLogMessages();
},
_updateAlias: function() {
let oldAlias = this.title;
this.title = this._contact.get_alias();
this._notification.appendAliasChange(oldAlias, this.title);
this.pushNotification(this._notification);
},
createNotificationIcon: function() {
@ -174,7 +223,7 @@ Source.prototype = {
}
},
_notificationClicked: function(notification) {
open: function(notification) {
let props = {};
props[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
[props[Tp.PROP_CHANNEL_TARGET_HANDLE], props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE]] = this._channel.get_handle();
@ -184,13 +233,52 @@ Source.prototype = {
req.ensure_channel_async('', null, null);
},
_displayPendingMessages: function() {
let msgs = this._channel.get_pending_messages();
_getLogMessages: function() {
let logManager = Tpl.LogManager.dup_singleton();
let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT);
Shell.get_contact_events(logManager,
this._account, entity,
SCROLLBACK_HISTORY_LINES,
Lang.bind(this, this._displayPendingMessages));
},
for (let i = 0; i < msgs.length; i++) {
let msg = msgs[i];
this._messageReceived(this._channel, msg);
_displayPendingMessages: function(logManager, result) {
let [success, events] = logManager.get_filtered_events_finish(result);
let logMessages = events.map(makeMessageFromTplEvent);
let pendingTpMessages = this._channel.get_pending_messages();
let pendingMessages = pendingTpMessages.map(function (tpMessage) { return makeMessageFromTpMessage(tpMessage, NotificationDirection.RECEIVED); });
let showTimestamp = false;
for (let i = 0; i < logMessages.length; i++) {
let logMessage = logMessages[i];
let isPending = false;
// Skip any log messages that are also in pendingMessages
for (let j = 0; j < pendingMessages.length; j++) {
let pending = pendingMessages[j];
if (logMessage.timestamp == pending.timestamp && logMessage.text == pending.text) {
isPending = true;
break;
}
}
if (!isPending) {
showTimestamp = true;
this._notification.appendMessage(logMessage, true, ['chat-log-message']);
}
}
if (showTimestamp)
this._notification.appendTimestamp();
for (let i = 0; i < pendingMessages.length; i++)
this._notification.appendMessage(pendingMessages[i], true);
if (pendingMessages.length > 0)
this.notify();
},
_channelClosed: function() {
@ -206,25 +294,32 @@ Source.prototype = {
},
_messageReceived: function(channel, message) {
this._notification.appendMessage(message, NotificationDirection.RECEIVED);
message = makeMessageFromTpMessage(message, NotificationDirection.RECEIVED);
this._notification.appendMessage(message);
this.notify();
},
// This is called for both messages we send from
// our client and other clients as well.
_messageSent: function(channel, message, flags, token) {
this._notification.appendMessage(message, NotificationDirection.SENT);
message = makeMessageFromTpMessage(message, NotificationDirection.SENT);
this._notification.appendMessage(message);
},
notify: function() {
if (!Main.messageTray.contains(this))
Main.messageTray.add(this);
MessageTray.Source.prototype.notify.call(this, this._notification);
},
respond: function(text) {
let msg = Tp.ClientMessage.new_text(Tp.ChannelTextMessageType.NORMAL, text);
let type;
if (text.slice(0, 4) == '/me ') {
type = Tp.ChannelTextMessageType.ACTION;
text = text.slice(4);
} else {
type = Tp.ChannelTextMessageType.NORMAL;
}
let msg = Tp.ClientMessage.new_text(type, text);
this._channel.send_message_async(msg, 0, null);
},
@ -280,19 +375,52 @@ Notification.prototype = {
this._responseEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivated));
this.setActionArea(this._responseEntry);
this._oldMaxScrollAdjustment = 0;
this._createScrollArea();
this._scrollArea.vscroll.adjustment.connect('changed', Lang.bind(this, function(adjustment) {
let currentValue = adjustment.value + adjustment.page_size;
if (currentValue == this._oldMaxScrollAdjustment)
this.scrollTo(St.Side.BOTTOM);
this._oldMaxScrollAdjustment = adjustment.upper;
}));
this._inputHistory = new History.HistoryManager({ entry: this._responseEntry.clutter_text });
this._history = [];
this._timestampTimeoutId = 0;
},
appendMessage: function(message, direction) {
let [text, flags] = message.to_text();
let timestamp = message.get_received_timestamp();
/**
* appendMessage:
* @message: An object with the properties:
* text: the body of the message,
* messageType: a #Tp.ChannelTextMessageType,
* sender: the name of the sender,
* timestamp: the time the message was sent
* direction: a #NotificationDirection
*
* @noTimestamp: Whether to add a timestamp. If %true, no timestamp
* will be added, regardless of the difference since the
* last timestamp
* @styles: A list of CSS class names.
*/
appendMessage: function(message, noTimestamp, styles) {
let messageBody = GLib.markup_escape_text(message.text, -1);
styles = styles || [];
styles.push(message.direction);
this.update(this.source.title, text, { customContent: true });
this._append(text, direction, timestamp);
if (message.messageType == Tp.ChannelTextMessageType.ACTION) {
let senderAlias = GLib.markup_escape_text(message.sender, -1);
messageBody = '<i>%s</i> %s'.format(senderAlias, messageBody);
styles.push('chat-action');
}
this.update(this.source.title, messageBody, { customContent: true, bannerMarkup: true });
this._append(messageBody, styles, message.timestamp, noTimestamp);
},
_append: function(text, style, timestamp) {
_append: function(text, styles, timestamp, noTimestamp) {
let currentTime = (Date.now() / 1000);
if (!timestamp)
timestamp = currentTime;
@ -304,20 +432,22 @@ Notification.prototype = {
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 body = this.addBody(text, true);
for (let i = 0; i < styles.length; i ++)
body.add_style_class_name(styles[i]);
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 (!noTimestamp) {
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
@ -338,15 +468,39 @@ Notification.prototype = {
}
},
_appendTimestamp: function() {
_formatTimestamp: function(date) {
let now = new Date();
var daysAgo = (now.getTime() - date.getTime()) / (24 * 60 * 60 * 1000);
// Show a week day and time if date is in the last week
if (daysAgo < 1 || (daysAgo < 7 && now.getDay() != date.getDay())) {
/* 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
format = _("Sent at %X on %A");
// FIXME: The next two are stolen from calendar.js with the comment to avoid
// a string-freeze break. They should be replaced with better strings
// with 'Sent at', appropriate context and appropriate translator comment.
} else if (date.getYear() == now.getYear()) {
/* Translators: Shown on calendar heading when selected day occurs on current year */
format = C_("calendar heading", "%A, %B %d");
} else {
/* Translators: Shown on calendar heading when selected day occurs on different year */
format = C_("calendar heading", "%A, %B %d, %Y");
}
return date.toLocaleFormat(format);
},
appendTimestamp: function() {
let lastMessageTime = this._history[0].time;
let lastMessageDate = new Date(lastMessageTime * 1000);
/* Translators: this is a time format string followed by a date.
If applicable, replace %X with a strftime format valid for your
locale, without seconds. */
// xgettext:no-c-format
let timeLabel = this.addBody(lastMessageDate.toLocaleFormat(_("Sent at %X on %A")), false, { expand: true, x_fill: false, x_align: St.Align.END });
let timeLabel = this.addBody(this._formatTimestamp(lastMessageDate), 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 });
@ -364,11 +518,28 @@ Notification.prototype = {
this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false});
},
appendAliasChange: function(oldAlias, newAlias) {
// FIXME: uncomment this after 3.0 string freeze ends
// oldAlias = GLib.markup_escape_text(oldAlias, -1);
// newAlias = GLib.markup_escape_text(newAlias, -1);
// /* Translators: this is the other person changing their old IM name to their new
// IM name. */
// let message = '<i>' + _("%s is now known as %s").format(oldAlias, newAlias) + '</i>';
// let label = this.addBody(message, true);
// label.add_style_class_name('chat-meta-message');
// this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false });
// this.update(newAlias, null, { customContent: true });
},
_onEntryActivated: function() {
let text = this._responseEntry.get_text();
if (text == '')
return;
this._inputHistory.addItem(text);
// Telepathy sends out the Sent signal for us.
// see Source._messageSent
this._responseEntry.set_text('');

View File

@ -1,6 +1,7 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Signals = imports.signals;
@ -15,185 +16,12 @@ 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',
/* Translators: this is the text displayed
in the search entry when no search is
active; it should not exceed ~30
characters */
hint_text: _("Type to search..."),
track_hover: true });
this.entry = this.actor.clutter_text;
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-find',
icon_type: St.IconType.SYMBOLIC });
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear',
icon_type: St.IconType.SYMBOLIC });
this.actor.set_secondary_icon(this._inactiveIcon);
this._iconClickedId = 0;
this.actor.clutter_text.connect('text-changed',
Lang.bind(this, this._onTextChanged));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('notify::mapped', Lang.bind(this, this._onMapped));
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);
},
_onMapped: function() {
if (this.actor.mapped) {
// Enable 'find-as-you-type'
this._capturedEventId = global.stage.connect('captured-event',
Lang.bind(this, this._onCapturedEvent));
this.entry.set_cursor_visible(true);
this.entry.set_selection(0, 0);
} else {
// Disable 'find-as-you-type'
if (this._capturedEventId > 0)
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
},
reset: function () {
this.actor.sync_hover();
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);
}
},
_onTextChanged: function() {
if (this.isActive()) {
this.actor.set_secondary_icon(this._activeIcon);
if (this._iconClickedId == 0)
this._iconClickedId = this.actor.connect('secondary-icon-clicked',
Lang.bind(this, function() {
this.reset();
}));
} else {
if (this._iconClickedId > 0)
this.actor.disconnect(this._iconClickedId);
this._iconClickedId = 0;
this.actor.set_secondary_icon(this._inactiveIcon);
}
},
_onDestroy: function() {
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
this._activeIcon = null;
this._inactiveIcon = null;
}
};
Signals.addSignalMethods(SearchEntry.prototype);
function BaseTab(titleActor, pageActor) {
this._init(titleActor, pageActor);
function BaseTab(titleActor, pageActor, name, a11yIcon) {
this._init(titleActor, pageActor, name, a11yIcon);
}
BaseTab.prototype = {
_init: function(titleActor, pageActor) {
_init: function(titleActor, pageActor, name, a11yIcon) {
this.title = titleActor;
this.page = new St.Bin({ child: pageActor,
x_align: St.Align.START,
@ -202,14 +30,25 @@ BaseTab.prototype = {
y_fill: true,
style_class: 'view-tab-page' });
if (this.title.can_focus) {
Main.ctrlAltTabManager.addGroup(this.title, name, a11yIcon);
} else {
Main.ctrlAltTabManager.addGroup(this.page, name, a11yIcon,
{ proxy: this.title,
focusCallback: Lang.bind(this, this._a11yFocus) });
}
this.visible = false;
},
show: function() {
show: function(animate) {
this.visible = true;
this.page.opacity = 0;
this.page.show();
if (!animate)
return;
this.page.opacity = 0;
Tweener.addTween(this.page,
{ opacity: 255,
time: 0.1,
@ -229,6 +68,11 @@ BaseTab.prototype = {
});
},
_a11yFocus: function() {
this._activate();
this.page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
_activate: function() {
this.emit('activated');
}
@ -236,48 +80,70 @@ BaseTab.prototype = {
Signals.addSignalMethods(BaseTab.prototype);
function ViewTab(label, pageActor) {
this._init(label, pageActor);
function ViewTab(id, label, pageActor, a11yIcon) {
this._init(id, label, pageActor, a11yIcon);
}
ViewTab.prototype = {
__proto__: BaseTab.prototype,
_init: function(label, pageActor) {
_init: function(id, label, pageActor, a11yIcon) {
this.id = id;
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);
BaseTab.prototype._init.call(this, titleActor, pageActor, label, a11yIcon);
}
};
function SearchTab(focusBase) {
this._init(focusBase);
function SearchTab() {
this._init();
}
SearchTab.prototype = {
__proto__: BaseTab.prototype,
_init: function(focusBase) {
this._searchActive = false;
_init: function() {
this.active = 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._entry = new St.Entry({ name: 'searchEntry',
/* Translators: this is the text displayed
in the search entry when no search is
active; it should not exceed ~30
characters. */
hint_text: _("Type to search..."),
track_hover: true,
can_focus: true });
this._text = this._entry.clutter_text;
this._text.connect('key-press-event', Lang.bind(this, this._onKeyPress));
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-find',
icon_type: St.IconType.SYMBOLIC });
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear',
icon_type: St.IconType.SYMBOLIC });
this._entry.set_secondary_icon(this._inactiveIcon);
this._iconClickedId = 0;
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) {
this._entry,
this._searchResults.actor,
_("Search"),
'edit-find');
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
this._text.connect('activate', Lang.bind(this, function (se) {
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._doSearch();
@ -285,24 +151,51 @@ SearchTab.prototype = {
this._searchResults.activateSelected();
return true;
}));
},
show: function() {
BaseTab.prototype.show.call(this);
this._entry.connect('secondary-icon-clicked', Lang.bind(this,
function() {
this._reset();
}));
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
if (this._keyPressId == 0)
this._keyPressId = this._searchEntry.entry.connect('key-press-event',
Lang.bind(this, this._onKeyPress));
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
this._capturedEventId = 0;
},
hide: function() {
BaseTab.prototype.hide.call(this);
if (this._keyPressId > 0) {
this._searchEntry.entry.disconnect(this._keyPressId);
this._keyPressId = 0;
this._reset();
},
_reset: function () {
this._text.text = '';
global.stage.set_key_focus(null);
this._text.set_cursor_visible(true);
this._text.set_selection(0, 0);
},
_updateCursorVisibility: function() {
let focus = global.stage.get_key_focus();
this._text.set_cursor_visible(focus == this._text);
},
_onMapped: function() {
if (this._entry.mapped) {
// Enable 'find-as-you-type'
this._capturedEventId = global.stage.connect('captured-event',
Lang.bind(this, this._onCapturedEvent));
this._text.set_cursor_visible(true);
this._text.set_selection(0, 0);
} else {
// Disable 'find-as-you-type'
if (this._capturedEventId > 0)
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
this._searchEntry.reset();
},
addSearchProvider: function(provider) {
@ -310,19 +203,42 @@ SearchTab.prototype = {
this._searchResults.createProviderMeta(provider);
},
startSearch: function(event) {
global.stage.set_key_focus(this._text);
this._text.event(event, false);
},
// the entry does not show the hint
_isActivated: function() {
return this._text.text == this._entry.get_text();
},
_onTextChanged: function (se, prop) {
let searchPreviouslyActive = this._searchActive;
this._searchActive = this._searchEntry.isActive();
this._searchPending = this._searchActive && !searchPreviouslyActive;
let searchPreviouslyActive = this.active;
this.active = this._entry.get_text() != '';
this._searchPending = this.active && !searchPreviouslyActive;
if (this._searchPending) {
this._searchResults.startingSearch();
}
if (this._searchActive) {
if (this.active) {
this._entry.set_secondary_icon(this._activeIcon);
if (this._iconClickedId == 0) {
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
Lang.bind(this, function() {
this.reset();
}));
}
this._activate();
} else {
if (this._iconClickedId > 0)
this._entry.disconnect(this._iconClickedId);
this._iconClickedId = 0;
this._entry.set_secondary_icon(this._inactiveIcon);
this.emit('search-cancelled');
}
if (!this._searchActive) {
if (!this.active) {
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._searchTimeoutId = 0;
@ -337,24 +253,43 @@ SearchTab.prototype = {
_onKeyPress: function(entry, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.Up) {
if (!this._searchActive)
if (!this.active)
return true;
this._searchResults.selectUp(false);
return true;
} else if (symbol == Clutter.Down) {
if (!this._searchActive)
if (!this.active)
return true;
this._searchResults.selectDown(false);
return true;
} else if (symbol == Clutter.Escape) {
if (this._isActivated()) {
this._reset();
return true;
}
}
return false;
},
_onCapturedEvent: function(actor, event) {
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
let source = event.get_source();
if (source != this._text && this._text.text == '') {
// the user clicked outside after activating the entry, but
// with no search term entered - cancel the search
this._reset();
}
}
return false;
},
_doSearch: function () {
this._searchTimeoutId = 0;
let text = this._searchEntry.getText();
let text = this._text.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
this._searchResults.updateSearch(text);
return false;
@ -370,8 +305,6 @@ ViewSelector.prototype = {
_init : function() {
this.actor = new St.BoxLayout({ name: 'viewSelector',
vertical: true });
this.actor.connect('key-press-event',
Lang.bind(this, this._onKeyPress));
// The tab bar is located at the top of the view selector and
// holds both "normal" tab labels and the search entry. The former
@ -405,7 +338,7 @@ ViewSelector.prototype = {
this._tabs = [];
this._activeTab = null;
this._searchTab = new SearchTab(this.actor);
this._searchTab = new SearchTab();
this._searchArea.set_child(this._searchTab.title);
this._addTab(this._searchTab);
@ -416,10 +349,22 @@ ViewSelector.prototype = {
Main.overview.connect('item-drag-begin',
Lang.bind(this, this._switchDefaultTab));
Main.overview.connect('showing',
Lang.bind(this, this._switchDefaultTab));
Main.overview.connect('hiding',
Lang.bind(this, this._switchDefaultTab));
this._stageKeyPressId = 0;
Main.overview.connect('showing', Lang.bind(this,
function () {
this._switchDefaultTab();
this._stageKeyPressId = global.stage.connect('key-press-event',
Lang.bind(this, this._onStageKeyPress));
}));
Main.overview.connect('hiding', Lang.bind(this,
function () {
this._switchDefaultTab();
if (this._stageKeyPressId != 0) {
global.stage.disconnect(this._stageKeyPressId);
this._stageKeyPressId = 0;
}
}));
// Public constraints which may be used to tie actors' height or
// vertical position to the current tab's content; as the content's
@ -443,14 +388,16 @@ ViewSelector.prototype = {
}));
},
addViewTab: function(title, pageActor) {
let viewTab = new ViewTab(title, pageActor);
addViewTab: function(id, title, pageActor, a11yIcon) {
let viewTab = new ViewTab(id, title, pageActor, a11yIcon);
this._tabs.push(viewTab);
this._tabBox.add(viewTab.title);
this._addTab(viewTab);
},
_switchTab: function(tab) {
let firstSwitch = this._activeTab == null;
if (this._activeTab && this._activeTab.visible) {
if (this._activeTab == tab)
return;
@ -466,11 +413,13 @@ ViewSelector.prototype = {
}
}
// Only fade when switching between tabs,
// not when setting the initially selected one.
if (!tab.visible)
tab.show();
tab.show(!firstSwitch);
// Pull a Meg Ryan:
if (Main.overview && Main.overview.workspaces) {
if (!firstSwitch && Main.overview.workspaces) {
if (tab != this._tabs[0]) {
Tweener.addTween(Main.overview.workspaces.actor,
{ opacity: 0,
@ -493,6 +442,14 @@ ViewSelector.prototype = {
}
},
switchTab: function(id) {
for (let i = 0; i < this._tabs.length; i++)
if (this._tabs[i].id == id) {
this._switchTab(this._tabs[i]);
break;
}
},
_switchDefaultTab: function() {
if (this._tabs.length > 0)
this._switchTab(this._tabs[0]);
@ -574,22 +531,25 @@ ViewSelector.prototype = {
}));
},
_onKeyPress: function(actor, event) {
_onStageKeyPress: 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)
if (!this._searchTab.active)
this._prevTab();
return true;
} else if (symbol == Clutter.Page_Down) {
if (!this._searchActive)
if (!this._searchTab.active)
this._nextTab();
return true;
}
} else if (Clutter.keysym_to_unicode(symbol)) {
this._searchTab.startSearch(event);
}
return false;
},

View File

@ -15,12 +15,11 @@ function WindowAttentionHandler() {
WindowAttentionHandler.prototype = {
_init : function() {
this._startupIds = {};
this._sources = {};
this._tracker = Shell.WindowTracker.get_default();
this._tracker.connect('startup-sequence-changed', Lang.bind(this, this._onStartupSequenceChanged));
let display = global.screen.get_display();
display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention));
let tracker = Shell.WindowTracker.get_default();
tracker.connect('startup-sequence-changed', Lang.bind(this, this._onStartupSequenceChanged));
},
_onStartupSequenceChanged : function(tracker) {
@ -57,28 +56,16 @@ WindowAttentionHandler.prototype = {
if (!window || window.has_focus() || window.is_skip_taskbar())
return;
let tracker = Shell.WindowTracker.get_default();
let app = tracker.get_window_app(window);
let appId = app.get_id();
let source = this._sources[appId];
if (source == null) {
source = new Source(app, window);
this._sources[appId] = source;
Main.messageTray.add(source);
source.connect('destroy', Lang.bind(this, function() { delete this._sources[appId]; }));
}
let app = this._tracker.get_window_app(window);
let source = new Source(app, window);
Main.messageTray.add(source);
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));
}));
window.connect('notify::demands-attention', Lang.bind(this, function() { source.destroy(); }));
window.connect('focus', Lang.bind(this, function() { source.destroy(); }));
window.connect('unmanaged', Lang.bind(this, function() { source.destroy(); }));
source.signalIDs.push(window.connect('notify::title', Lang.bind(this, function(win) {
notification.update(this._getTitle(app, win), this._getBanner(app, win));
})));
}
};
@ -94,13 +81,27 @@ Source.prototype = {
this._window = window;
this._app = app;
this._setSummaryIcon(this.createNotificationIcon());
this.signalIDs = [];
this.signalIDs.push(this._window.connect('notify::demands-attention', Lang.bind(this, function() { this.destroy(); })));
this.signalIDs.push(this._window.connect('focus', Lang.bind(this, function() { this.destroy(); })));
this.signalIDs.push(this._window.connect('unmanaged', Lang.bind(this, function() { this.destroy(); })));
this.connect('destroy', Lang.bind(this, this._onDestroy));
},
_onDestroy : function() {
for(let i = 0; i < this.signalIDs.length; i++) {
this._window.disconnect(this.signalIDs[i]);
}
this.signalIDs = [];
},
createNotificationIcon : function() {
return this._app.create_icon_texture(this.ICON_SIZE);
},
_notificationClicked : function(notification) {
open : function(notification) {
Main.activateWindow(this._window);
this.destroy();
}

View File

@ -93,6 +93,8 @@ WindowManager.prototype = {
this._dimmedWindows = [];
this._animationBlockCount = 0;
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) {
@ -117,14 +119,15 @@ WindowManager.prototype = {
this.setKeybindingHandler('switch_to_workspace_down', Lang.bind(this, this._showWorkspaceSwitcher));
this.setKeybindingHandler('switch_windows', Lang.bind(this, this._startAppSwitcher));
this.setKeybindingHandler('switch_group', Lang.bind(this, this._startAppSwitcher));
this.setKeybindingHandler('switch_panels', Lang.bind(this, this._startA11ySwitcher));
Main.overview.connect('showing', Lang.bind(this, function() {
for (let i = 0; i < this._dimmedWindows.length; i++)
this._undimParentWindow(this._dimmedWindows[i], true);
this._undimWindow(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);
this._dimWindow(this._dimmedWindows[i], true);
}));
},
@ -138,8 +141,16 @@ WindowManager.prototype = {
this._shellwm.connect('keybinding::' + keybinding, handler);
},
blockAnimations: function() {
this._animationBlockCount++;
},
unblockAnimations: function() {
this._animationBlockCount = Math.max(0, this._animationBlockCount - 1);
},
_shouldAnimate : function(actor) {
if (Main.overview.visible)
if (Main.overview.visible || this._animationsBlocked > 0)
return false;
if (actor && (actor.meta_window.get_window_type() != Meta.WindowType.NORMAL))
return false;
@ -223,41 +234,39 @@ WindowManager.prototype = {
_unmaximizeWindowDone : function(shellwm, actor) {
},
_parentHasOtherAttachedDialog: function(parent, self) {
_hasAttachedDialogs: function(window, ignoreWindow) {
var count = 0;
parent.foreach_transient(function(win) {
if (win.get_window_type() == Meta.WindowType.MODAL_DIALOG && win != self)
window.foreach_transient(function(win) {
if (win != ignoreWindow && win.get_window_type() == Meta.WindowType.MODAL_DIALOG)
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);
_checkDimming: function(window, ignoreWindow) {
let shouldDim = Meta.prefs_get_attach_modal_dialogs() && this._hasAttachedDialogs(window, ignoreWindow);
if (shouldDim && !window._dimmed) {
window._dimmed = true;
this._dimmedWindows.push(window);
if (!Main.overview.visible)
this._dimWindow(window, true);
} else if (!shouldDim && window._dimmed) {
window._dimmed = false;
this._dimmedWindows = this._dimmedWindows.filter(function(win) {
return win != window;
});
if (!Main.overview.visible)
this._undimWindow(window, true);
}
},
_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)
_dimWindow: function(window, animate) {
let actor = window.get_compositor_private();
if (!actor)
return;
let parentActor = parent.get_compositor_private();
if (!parentActor || this._parentHasOtherAttachedDialog(parent, meta))
return;
let texture = parentActor.get_texture();
let texture = actor.get_texture();
if (animate)
Tweener.addTween(getWindowDimmer(texture),
{ dimFraction: 1.0,
@ -268,15 +277,11 @@ WindowManager.prototype = {
getWindowDimmer(texture).dimFraction = 1.0;
},
_undimParentWindow: function(actor, animate) {
let meta = actor.get_meta_window();
let parent = meta.get_transient_for();
if (!parent)
_undimWindow: function(window, animate) {
let actor = window.get_compositor_private();
if (!actor)
return;
let parentActor = parent.get_compositor_private();
if (!parentActor || this._parentHasOtherAttachedDialog(parent, meta))
return;
let texture = parentActor.get_texture();
let texture = actor.get_texture();
if (animate)
Tweener.addTween(getWindowDimmer(texture),
{ dimFraction: 0.0,
@ -293,17 +298,19 @@ WindowManager.prototype = {
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);
if (type == Meta.WindowType.MODAL_DIALOG ||
actor._windowType == Meta.WindowType.MODAL_DIALOG) {
let parent = actor.get_meta_window().get_transient_for();
if (parent)
this._checkDimming(parent);
}
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);
this._checkDimming(actor.get_meta_window().get_transient_for());
if (this._shouldAnimate()) {
actor.set_scale(1.0, 0.0);
actor.show();
@ -363,14 +370,20 @@ WindowManager.prototype = {
},
_destroyWindow : function(shellwm, actor) {
let parent = actor.meta_window.get_transient_for();
let window = actor.meta_window;
let parent = window.get_transient_for();
if (actor._notifyWindowTypeSignalId) {
actor.meta_window.disconnect(actor._notifyWindowTypeSignalId);
window.disconnect(actor._notifyWindowTypeSignalId);
actor._notifyWindowTypeSignalId = 0;
}
while (actor.meta_window.get_window_type() == Meta.WindowType.MODAL_DIALOG
if (window._dimmed) {
this._dimmedWindows = this._dimmedWindows.filter(function(win) {
return win != window;
});
}
while (window.get_window_type() == Meta.WindowType.MODAL_DIALOG
&& parent) {
this._unmarkParentWindowAsDimmable(actor, true);
this._checkDimming(parent, window);
if (!Meta.prefs_get_attach_modal_dialogs()
|| !this._shouldAnimate())
break;
@ -525,6 +538,10 @@ WindowManager.prototype = {
tabPopup.destroy();
},
_startA11ySwitcher : function(shellwm, binding, window, backwards) {
Main.ctrlAltTabManager.popup(backwards);
},
_showWorkspaceSwitcher : function(shellwm, binding, window, backwards) {
if (global.screen.n_workspaces == 1)
return;

View File

@ -125,6 +125,7 @@ WindowClone.prototype = {
dragActorMaxSize: WINDOW_DND_SIZE,
dragActorOpacity: DRAGGING_WINDOW_OPACITY });
this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
this._draggable.connect('drag-cancelled', Lang.bind(this, this._onDragCancelled));
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
this.inDrag = false;
@ -220,8 +221,15 @@ WindowClone.prototype = {
let [width, height] = this.actor.get_transformed_size();
this.actor.x = _clamp(this.actor.x, 0, global.screen_width - width);
this.actor.y = _clamp(this.actor.y, Panel.PANEL_HEIGHT, global.screen_height - height);
let monitorIndex = this.metaWindow.get_monitor();
let availArea = global.get_monitors()[monitorIndex];
if (monitorIndex == global.get_primary_monitor_index()) {
availArea.y += Main.panel.actor.height;
availArea.height -= Main.panel.actor.height;
}
this.actor.x = _clamp(this.actor.x, availArea.x, availArea.x + availArea.width - width);
this.actor.y = _clamp(this.actor.y, availArea.y, availArea.y + availArea.height - height);
},
_zoomStart : function () {
@ -288,10 +296,16 @@ WindowClone.prototype = {
},
_onDragBegin : function (draggable, time) {
[this.dragOrigX, this.dragOrigY] = this.actor.get_position();
this.dragOrigScale = this.actor.scale_x;
this.inDrag = true;
this.emit('drag-begin');
},
_onDragCancelled : function (draggable, time) {
this.emit('drag-cancelled');
},
_onDragEnd : function (draggable, time, snapback) {
this.inDrag = false;
@ -327,6 +341,7 @@ WindowOverlay.prototype = {
this._windowClone = windowClone;
this._parentActor = parentActor;
this._hidden = false;
let title = new St.Label({ style_class: 'window-caption',
text: metaWindow.title });
@ -372,23 +387,19 @@ WindowOverlay.prototype = {
},
hide: function() {
this._hidden = true;
this.closeButton.hide();
this.title.hide();
},
show: function() {
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) {
this.closeButton.show();
}
this._hidden = false;
this.title.show();
},
fadeIn: function() {
this.show();
this.title.opacity = 0;
this.title.show();
this._parentActor.raise_top();
Tweener.addTween(this.title,
{ opacity: 255,
@ -419,8 +430,13 @@ WindowOverlay.prototype = {
let button = this.closeButton;
let title = this.title;
let buttonX = cloneX + cloneWidth - button._overlap;
let buttonY = cloneY - button.height + button._overlap;
let buttonX;
let buttonY = cloneY - (button.height - button._overlap);
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
buttonX = cloneX - (button.width - button._overlap);
else
buttonX = cloneX + (cloneWidth - button._overlap);
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
if (!title.fullWidth)
@ -475,6 +491,12 @@ WindowOverlay.prototype = {
},
_onEnter: function() {
// We might get enter events on the clone while the overlay is
// hidden, e.g. during animations, we ignore these events,
// as the close button will be shown as needed when the overlays
// are shown again
if (this._hidden)
return;
this._parentActor.raise_top();
this.closeButton.show();
this.emit('show-close-button');
@ -515,44 +537,45 @@ WindowOverlay.prototype = {
Signals.addSignalMethods(WindowOverlay.prototype);
const WindowPositionFlags = {
ZOOM: 1 << 0,
INITIAL: 1 << 0,
ANIMATE: 1 << 1
};
/**
* @metaWorkspace: a #Meta.Workspace
* @metaWorkspace: a #Meta.Workspace, or null
*/
function Workspace(metaWorkspace) {
this._init(metaWorkspace);
function Workspace(metaWorkspace, monitorIndex) {
this._init(metaWorkspace, monitorIndex);
}
Workspace.prototype = {
_init : function(metaWorkspace) {
_init : function(metaWorkspace, monitorIndex) {
// When dragging a window, we use this slot for reserve space.
this._reservedSlot = null;
this.metaWorkspace = metaWorkspace;
this._x = 0;
this._y = 0;
this._width = 0;
this._height = 0;
this.monitorIndex = monitorIndex;
this._monitor = global.get_monitors()[this.monitorIndex];
this._windowOverlaysGroup = new Clutter.Group();
// Without this the drop area will be overlapped.
this._windowOverlaysGroup.set_size(0, 0);
this.actor = new Clutter.Group();
this.actor._delegate = this;
this.actor.set_size(0, 0);
this._dropRect = new Clutter.Rectangle({ opacity: 0 });
this._dropRect._delegate = this;
this.actor.add_actor(this._dropRect);
this.actor.add_actor(this._windowOverlaysGroup);
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
// Items in _windowOverlaysGroup should not be scaled, so we don't
// add them to this.actor, but to its parent whenever it changes
this.actor.connect('parent-set', Lang.bind(this, this._onParentSet));
// Auto-sizing is unreliable in the presence of ClutterClone, so rather than
// implicitly counting on the workspace actor to be sized to the size of the
// included desktop actor clone, set the size explicitly to the screen size.
// See http://bugzilla.openedhand.com/show_bug.cgi?id=1755
this.actor.width = global.screen_width;
this.actor.height = global.screen_height;
this.scale = 1.0;
let windows = Main.getWindowActorsForWorkspace(this.metaWorkspace.index());
let windows = global.get_window_actors().filter(this._isMyWindow, this);
// Create clones for windows that should be
// visible in the Overview
@ -565,15 +588,37 @@ Workspace.prototype = {
}
// Track window changes
this._windowAddedId = this.metaWorkspace.connect('window-added',
Lang.bind(this, this._windowAdded));
this._windowRemovedId = this.metaWorkspace.connect('window-removed',
Lang.bind(this, this._windowRemoved));
if (this.metaWorkspace) {
this._windowAddedId = this.metaWorkspace.connect('window-added',
Lang.bind(this, this._windowAdded));
this._windowRemovedId = this.metaWorkspace.connect('window-removed',
Lang.bind(this, this._windowRemoved));
}
this._windowEnteredMonitorId = global.screen.connect('window-entered-monitor',
Lang.bind(this, this._windowEnteredMonitor));
this._windowLeftMonitorId = global.screen.connect('window-left-monitor',
Lang.bind(this, this._windowLeftMonitor));
this._repositionWindowsId = 0;
this.leavingOverview = false;
},
setGeometry: function(x, y, width, height) {
this._x = x;
this._y = y;
this._width = width;
this._height = height;
// This is sometimes called during allocation, so we do this later
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
function () {
this._dropRect.set_position(x, y);
this._dropRect.set_size(width, height);
return false;
}));
},
_lookupIndex: function (metaWindow) {
for (let i = 0; i < this._windows.length; i++) {
if (this._windows[i].metaWindow == metaWindow) {
@ -583,17 +628,6 @@ Workspace.prototype = {
return -1;
},
_onParentSet: function(actor, old_parent) {
let new_parent = this.actor.get_parent();
if (new_parent == null)
return;
if (old_parent)
this._windowOverlaysGroup.reparent(new_parent);
else
new_parent.add_actor(this._windowOverlaysGroup);
},
containsMetaWindow: function (metaWindow) {
return this._lookupIndex(metaWindow) >= 0;
},
@ -672,10 +706,20 @@ Workspace.prototype = {
let xDelta, yDelta, distanceSquared;
let actorWidth, actorHeight;
actorWidth = actor.width * actor.scale_x;
actorHeight = actor.height * actor.scale_y;
xDelta = actor.x + actorWidth / 2.0 - xCenter * global.screen_width;
yDelta = actor.y + actorHeight / 2.0 - yCenter * global.screen_height;
let x = actor.x;
let y = actor.y;
let scale = actor.scale_x;
if (actor._delegate.inDrag) {
x = actor._delegate.dragOrigX;
y = actor._delegate.dragOrigY;
scale = actor._delegate.dragOrigScale;
}
actorWidth = actor.width * scale;
actorHeight = actor.height * scale;
xDelta = x + actorWidth / 2.0 - xCenter * this._width - this._x;
yDelta = y + actorHeight / 2.0 - yCenter * this._height - this._y;
distanceSquared = xDelta * xDelta + yDelta * yDelta;
return distanceSquared;
@ -700,6 +744,12 @@ Workspace.prototype = {
let delta = this._computeWindowMotion(cloneActor, slot);
motion += delta;
// Bail out early if we're already larger than the
// previous best
if (minimumMotionPermutation != null &&
motion > minimumMotion)
continue;
}
if (minimumMotionPermutation == null || motion < minimumMotion) {
@ -760,38 +810,35 @@ Workspace.prototype = {
},
/**
* _getSlotRelativeGeometry:
* _getSlotGeometry:
* @slot: A layout slot
*
* Returns: the workspace-relative [x, y, width, height]
* Returns: the screen-relative [x, y, width, height]
* of a given window layout slot.
*/
_getSlotRelativeGeometry: function(slot) {
_getSlotGeometry: function(slot) {
let [xCenter, yCenter, fraction] = slot;
let width = global.screen_width * fraction;
let height = global.screen_height * fraction;
let width = this._width * fraction;
let height = this._height * fraction;
let x = xCenter * global.screen_width - width / 2;
let y = yCenter * global.screen_height - height / 2;
let x = this._x + xCenter * this._width - width / 2 ;
let y = this._y + yCenter * this._height - height / 2;
return [x, y, width, height];
},
/**
* _computeWindowRelativeLayout:
* _computeWindowLayout:
* @metaWindow: A #MetaWindow
* @slot: A layout slot
*
* Given a window and slot to fit it in, compute its
* workspace-relative [x, y, scale] where scale applies
* screen-relative [x, y, scale] where scale applies
* to both X and Y directions.
*/
_computeWindowRelativeLayout: function(metaWindow, slot) {
let [xCenter, yCenter, fraction] = slot;
let [x, y, width, height] = this._getSlotRelativeGeometry(slot);
xCenter = xCenter * global.screen_width;
_computeWindowLayout: function(metaWindow, slot) {
let [x, y, width, height] = this._getSlotGeometry(slot);
let rect = metaWindow.get_outer_rect();
let buttonOuterHeight, captionHeight;
@ -799,23 +846,19 @@ Workspace.prototype = {
if (this._windowOverlays[0]) {
[buttonOuterHeight, captionHeight] = this._windowOverlays[0].chromeHeights();
buttonOuterWidth = this._windowOverlays[0].chromeWidth() / this.scale;
buttonOuterWidth = this._windowOverlays[0].chromeWidth();
} else
[buttonOuterHeight, captionHeight] = [0, 0];
buttonOuterHeight /= this.scale;
captionHeight /= this.scale;
let desiredWidth = global.screen_width * fraction;
let desiredHeight = global.screen_height * fraction;
let scale = Math.min((desiredWidth - buttonOuterWidth) / rect.width,
(desiredHeight - buttonOuterHeight - captionHeight) / rect.height,
1.0 / this.scale);
let scale = Math.min((width - buttonOuterWidth) / rect.width,
(height - buttonOuterHeight - captionHeight) / rect.height,
1.0);
x = Math.floor(xCenter - 0.5 * scale * rect.width);
x = Math.floor(x + (width - scale * rect.width) / 2);
// We want to center the window in case we have just one
if (metaWindow.get_workspace().n_windows == 1)
y = Math.floor(yCenter * global.screen_height - 0.5 * scale * rect.height);
y = Math.floor(y + (height - scale * rect.height) / 2);
else
y = Math.floor(y + height - rect.height * scale - captionHeight);
@ -841,7 +884,7 @@ Workspace.prototype = {
/**
* positionWindows:
* @flags:
* ZOOM - workspace is moving at the same time and we need to take that into account.
* INITIAL - this is the initial positioning of the windows.
* ANIMATE - Indicates that we need animate changing position.
*/
positionWindows : function(flags) {
@ -854,7 +897,7 @@ Workspace.prototype = {
if (this._reservedSlot)
clones.push(this._reservedSlot);
let workspaceZooming = flags & WindowPositionFlags.ZOOM;
let initialPositioning = flags & WindowPositionFlags.INITIAL;
let animate = flags & WindowPositionFlags.ANIMATE;
// Start the animations
@ -862,7 +905,7 @@ Workspace.prototype = {
clones = this._orderWindowsByMotionAndStartup(clones, slots);
let currentWorkspace = global.screen.get_active_workspace();
let isOnCurrentWorkspace = this.metaWorkspace == currentWorkspace;
let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
for (let i = 0; i < clones.length; i++) {
let slot = slots[i];
@ -876,7 +919,7 @@ Workspace.prototype = {
if (clone.inDrag)
continue;
let [x, y, scale] = this._computeWindowRelativeLayout(metaWindow, slot);
let [x, y, scale] = this._computeWindowLayout(metaWindow, slot);
if (overlay)
overlay.hide();
@ -885,7 +928,7 @@ Workspace.prototype = {
/* Hidden windows should fade in and grow
* therefore we need to resize them now so they
* can be scaled up later */
if (workspaceZooming) {
if (initialPositioning) {
clone.actor.opacity = 0;
clone.actor.scale_x = 0;
clone.actor.scale_y = 0;
@ -906,7 +949,6 @@ Workspace.prototype = {
y: y,
scale_x: scale,
scale_y: scale,
workspace_relative: workspaceZooming ? this : null,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
@ -929,7 +971,7 @@ Workspace.prototype = {
let clone = clones[i];
let metaWindow = clone.metaWindow;
if (i == 0) {
clone.setStackAbove(null);
clone.setStackAbove(this._dropRect);
} else {
let previousClone = clones[i - 1];
clone.setStackAbove(previousClone.actor);
@ -949,10 +991,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.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;
cloneWidth = clone.actor.scale_x * cloneWidth;
cloneHeight = clone.actor.scale_y * cloneHeight;
if (overlay) {
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
@ -968,7 +1008,8 @@ Workspace.prototype = {
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
let overlay = this._windowOverlays[i];
this._showWindowOverlay(clone, overlay, this.metaWorkspace == currentWorkspace);
this._showWindowOverlay(clone, overlay,
this.metaWorkspace == null || this.metaWorkspace == currentWorkspace);
}
},
@ -977,12 +1018,10 @@ Workspace.prototype = {
return true;
let [x, y, mask] = global.get_pointer();
let wsWidth = this.actor.width * this.scale;
let wsHeight = this.actor.height * this.scale;
let pointerHasMoved = (this._cursorX != x && this._cursorY != y);
let inWorkspace = (this.x < x && x < this.x + wsWidth &&
this.y < y && y < this.y + wsHeight);
let inWorkspace = (this._x < x && x < this._x + this._width &&
this._y < y && y < this._y + this._height);
if (pointerHasMoved && inWorkspace) {
// store current cursor position
@ -1007,7 +1046,7 @@ Workspace.prototype = {
this._windowOverlaysGroup.hide();
},
_windowRemoved : function(metaWorkspace, metaWin) {
_doRemoveWindow : function(metaWin) {
let win = metaWin.get_compositor_private();
// find the position of the window in our list
@ -1016,6 +1055,10 @@ Workspace.prototype = {
if (index == -1)
return;
// Check if window still should be here
if (win && this._isMyWindow(win))
return;
let clone = this._windows[index];
this._windows.splice(index, 1);
@ -1059,7 +1102,7 @@ Workspace.prototype = {
Lang.bind(this, this._delayedWindowRepositioning));
},
_windowAdded : function(metaWorkspace, metaWin) {
_doAddWindow : function(metaWin) {
if (this.leavingOverview)
return;
@ -1071,30 +1114,62 @@ Workspace.prototype = {
Mainloop.idle_add(Lang.bind(this,
function () {
if (this.actor && metaWin.get_compositor_private())
this._windowAdded(metaWorkspace, metaWin);
this._doAddWindow(metaWin);
return false;
}));
return;
}
if (!this._isOverviewWindow(win))
// We might have the window in our list already if it was on all workspaces and
// now was moved to this workspace
if (this._lookupIndex (metaWin) != -1)
return;
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
return;
let clone = this._addWindowClone(win);
if (win._overviewHint) {
let x = (win._overviewHint.x - this.actor.x) / this.scale;
let y = (win._overviewHint.y - this.actor.y) / this.scale;
let scale = win._overviewHint.scale / this.scale;
let x = win._overviewHint.x - this.actor.x;
let y = win._overviewHint.y - this.actor.y;
let scale = win._overviewHint.scale;
delete win._overviewHint;
clone.actor.set_position (x, y);
clone.actor.set_scale (scale, scale);
} else {
// Position new windows at the top corner of the workspace rather
// than where they were placed for real to avoid the window
// being clipped to the workspaceView. Its not really more
// natural for the window to suddenly appear in the overview
// on some seemingly random location anyway.
clone.actor.set_position (this._x, this._y);
}
this.positionWindows(WindowPositionFlags.ANIMATE);
},
_windowAdded : function(metaWorkspace, metaWin) {
this._doAddWindow(metaWin);
},
_windowRemoved : function(metaWorkspace, metaWin) {
this._doRemoveWindow(metaWin);
},
_windowEnteredMonitor : function(metaScreen, monitorIndex, metaWin) {
if (monitorIndex == this.monitorIndex) {
this._doAddWindow(metaWin);
}
},
_windowLeftMonitor : function(metaScreen, monitorIndex, metaWin) {
if (monitorIndex == this.monitorIndex) {
this._doRemoveWindow(metaWin);
}
},
// check for maximized windows on the workspace
hasMaximizedWindows: function() {
for (let i = 0; i < this._windows.length; i++) {
@ -1109,14 +1184,11 @@ Workspace.prototype = {
// Animate the full-screen to Overview transition.
zoomToOverview : function() {
this.actor.set_position(this.x, this.y);
this.actor.set_scale(this.scale, this.scale);
// Position and scale the windows.
if (Main.overview.animationInProgress)
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.ZOOM);
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
else
this.positionWindows(WindowPositionFlags.ZOOM);
this.positionWindows(WindowPositionFlags.INITIAL);
},
// Animates the return from Overview mode
@ -1134,7 +1206,7 @@ Workspace.prototype = {
this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
this._doneLeavingOverview));
if (this._metaWorkspace == currentWorkspace)
if (this.metaWorkspace != null && this.metaWorkspace != currentWorkspace)
return;
// Position and scale the windows.
@ -1149,7 +1221,6 @@ Workspace.prototype = {
y: clone.origY,
scale_x: 1.0,
scale_y: 1.0,
workspace_relative: this,
time: Overview.ANIMATION_TIME,
opacity: 255,
transition: 'easeOutQuad'
@ -1160,7 +1231,6 @@ Workspace.prototype = {
{ scale_x: 0,
scale_y: 0,
opacity: 0,
workspace_relative: this,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad'
});
@ -1180,8 +1250,12 @@ Workspace.prototype = {
}
Tweener.removeTweens(actor);
this.metaWorkspace.disconnect(this._windowAddedId);
this.metaWorkspace.disconnect(this._windowRemovedId);
if (this.metaWorkspace) {
this.metaWorkspace.disconnect(this._windowAddedId);
this.metaWorkspace.disconnect(this._windowRemovedId);
}
global.screen.disconnect(this._windowEnteredMonitorId);
global.screen.disconnect(this._windowLeftMonitorId);
if (this._repositionWindowsId > 0)
Mainloop.source_remove(this._repositionWindowsId);
@ -1200,9 +1274,10 @@ Workspace.prototype = {
this.leavingOverview = false;
},
// Tests if @win belongs to this workspaces
// Tests if @win belongs to this workspaces and monitor
_isMyWindow : function (win) {
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index());
return (this.metaWorkspace == null || Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index())) &&
(!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex);
},
// Tests if @win should be shown in the Overview
@ -1223,6 +1298,10 @@ Workspace.prototype = {
Main.overview.beginWindowDrag();
overlay.hide();
}));
clone.connect('drag-cancelled',
Lang.bind(this, function(clone) {
Main.overview.cancelledWindowDrag();
}));
clone.connect('drag-end',
Lang.bind(this, function(clone) {
Main.overview.endWindowDrag();
@ -1286,8 +1365,10 @@ Workspace.prototype = {
},
_onCloneSelected : function (clone, time) {
Main.activateWindow(clone.metaWindow, time,
this.metaWorkspace.index());
let wsIndex = undefined;
if (this.metaWorkspace)
wsIndex = this.metaWorkspace.index();
Main.activateWindow(clone.metaWindow, time, wsIndex);
},
// Draggable target interface
@ -1315,7 +1396,15 @@ Workspace.prototype = {
};
let metaWindow = win.get_meta_window();
metaWindow.change_workspace_by_index(this.metaWorkspace.index(),
// We need to move the window before changing the workspace, because
// the move itself could cause a workspace change if the window enters
// the primary monitor
if (metaWindow.get_monitor() != this.monitorIndex)
metaWindow.move_to_monitor(this.monitorIndex);
let index = this.metaWorkspace ? this.metaWorkspace.index() : global.screen.get_active_workspace_index();
metaWindow.change_workspace_by_index(index,
false, // don't create workspace
time);
return true;
@ -1330,56 +1419,3 @@ Workspace.prototype = {
};
Signals.addSignalMethods(Workspace.prototype);
// Create a SpecialPropertyModifier to let us move windows in a
// straight line on the screen even though their containing workspace
// is also moving.
Tweener.registerSpecialPropertyModifier('workspace_relative', _workspaceRelativeModifier, _workspaceRelativeGet);
function _workspaceRelativeModifier(workspace) {
let [startX, startY] = Main.overview.getPosition();
let overviewPosX, overviewPosY, overviewScale;
if (!workspace)
return [];
if (workspace.leavingOverview) {
let [zoomedInX, zoomedInY] = Main.overview.getZoomedInPosition();
overviewPosX = { begin: startX, end: zoomedInX };
overviewPosY = { begin: startY, end: zoomedInY };
overviewScale = { begin: Main.overview.getScale(),
end: Main.overview.getZoomedInScale() };
} else {
overviewPosX = { begin: startX, end: 0 };
overviewPosY = { begin: startY, end: 0 };
overviewScale = { begin: Main.overview.getScale(), end: 1 };
}
return [ { name: 'x',
parameters: { workspacePos: workspace.x,
overviewPos: overviewPosX,
overviewScale: overviewScale } },
{ name: 'y',
parameters: { workspacePos: workspace.y,
overviewPos: overviewPosY,
overviewScale: overviewScale } }
];
}
function _workspaceRelativeGet(begin, end, time, params) {
let curOverviewPos = (1 - time) * params.overviewPos.begin +
time * params.overviewPos.end;
let curOverviewScale = (1 - time) * params.overviewScale.begin +
time * params.overviewScale.end;
// Calculate the screen position of the window.
let screen = (1 - time) *
((begin + params.workspacePos) * params.overviewScale.begin +
params.overviewPos.begin) +
time *
((end + params.workspacePos) * params.overviewScale.end +
params.overviewPos.end);
// Return the workspace coordinates.
return (screen - curOverviewPos) / curOverviewScale - params.workspacePos;
}

View File

@ -146,6 +146,7 @@ function WorkspaceThumbnail(metaWorkspace) {
WorkspaceThumbnail.prototype = {
_init : function(metaWorkspace) {
this.metaWorkspace = metaWorkspace;
this.monitorIndex = global.get_primary_monitor_index();
this.actor = new St.Group({ reactive: true,
clip_to_allocation: true,
@ -169,7 +170,8 @@ WorkspaceThumbnail.prototype = {
this._background = new Clutter.Clone({ source: global.background_actor });
this._contents.add_actor(this._background);
this.setPorthole(0, 0, global.screen_width, global.screen_height);
let monitor = global.get_primary_monitor();
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
let windows = global.get_window_actors().filter(this._isMyWindow, this);
@ -186,6 +188,10 @@ WorkspaceThumbnail.prototype = {
Lang.bind(this, this._windowAdded));
this._windowRemovedId = this.metaWorkspace.connect('window-removed',
Lang.bind(this, this._windowRemoved));
this._windowEnteredMonitorId = global.screen.connect('window-entered-monitor',
Lang.bind(this, this._windowEnteredMonitor));
this._windowLeftMonitorId = global.screen.connect('window-left-monitor',
Lang.bind(this, this._windowLeftMonitor));
this.state = ThumbnailState.NORMAL;
this._slidePosition = 0; // Fully slid in
@ -193,6 +199,8 @@ WorkspaceThumbnail.prototype = {
},
setPorthole: function(x, y, width, height) {
this._portholeX = x;
this._portholeY = y;
this.actor.set_size(width, height);
this._contents.set_position(-x, -y);
},
@ -239,7 +247,7 @@ WorkspaceThumbnail.prototype = {
return this._collapseFraction;
},
_windowRemoved : function(metaWorkspace, metaWin) {
_doRemoveWindow : function(metaWin) {
let win = metaWin.get_compositor_private();
// find the position of the window in our list
@ -248,12 +256,16 @@ WorkspaceThumbnail.prototype = {
if (index == -1)
return;
// Check if window still should be here
if (win && this._isMyWindow(win))
return;
let clone = this._windows[index];
this._windows.splice(index, 1);
clone.destroy();
},
_windowAdded : function(metaWorkspace, metaWin) {
_doAddWindow : function(metaWin) {
if (this.leavingOverview)
return;
@ -265,18 +277,43 @@ WorkspaceThumbnail.prototype = {
Mainloop.idle_add(Lang.bind(this,
function () {
if (this.actor && metaWin.get_compositor_private())
this._windowAdded(metaWorkspace, metaWin);
this._doAddWindow(metaWin);
return false;
}));
return;
}
if (!this._isOverviewWindow(win))
// We might have the window in our list already if it was on all workspaces and
// now was moved to this workspace
if (this._lookupIndex (metaWin) != -1)
return;
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
return;
let clone = this._addWindowClone(win);
},
_windowAdded : function(metaWorkspace, metaWin) {
this._doAddWindow(metaWin);
},
_windowRemoved : function(metaWorkspace, metaWin) {
this._doRemoveWindow(metaWin);
},
_windowEnteredMonitor : function(metaScreen, monitorIndex, metaWin) {
if (monitorIndex == this.monitorIndex) {
this._doAddWindow(metaWin);
}
},
_windowLeftMonitor : function(metaScreen, monitorIndex, metaWin) {
if (monitorIndex == this.monitorIndex) {
this._doRemoveWindow(metaWin);
}
},
destroy : function() {
this.actor.destroy();
},
@ -284,15 +321,17 @@ WorkspaceThumbnail.prototype = {
_onDestroy: function(actor) {
this.metaWorkspace.disconnect(this._windowAddedId);
this.metaWorkspace.disconnect(this._windowRemovedId);
global.screen.disconnect(this._windowEnteredMonitorId);
global.screen.disconnect(this._windowLeftMonitorId);
this._windows = [];
this.actor = null;
},
// Tests if @win belongs to this workspaces
// Tests if @win belongs to this workspace and monitor
_isMyWindow : function (win) {
return win.get_workspace() == this.metaWorkspace.index() ||
(win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index()) &&
(!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex);
},
// Tests if @win should be shown in the Overview
@ -340,6 +379,11 @@ WorkspaceThumbnail.prototype = {
// Draggable target interface
handleDragOver : function(source, actor, x, y, time) {
if (source == Main.xdndHandler) {
this.metaWorkspace.activate(time);
return DND.DragMotionResult.CONTINUE;
}
if (this.state > ThumbnailState.NORMAL)
return DND.DragMotionResult.CONTINUE;
@ -361,6 +405,13 @@ WorkspaceThumbnail.prototype = {
return false;
let metaWindow = win.get_meta_window();
// We need to move the window before changing the workspace, because
// the move itself could cause a workspace change if the window enters
// the primary monitor
if (metaWindow.get_monitor() != this.monitorIndex)
metaWindow.move_to_monitor(this.monitorIndex);
metaWindow.change_workspace_by_index(this.metaWorkspace.index(),
false, // don't create workspace
time);
@ -402,10 +453,6 @@ ThumbnailsBox.prototype = {
// for the border and padding of the background actor.
this._background = new St.Bin({ style_class: 'workspace-thumbnails-background' });
// This will eventually be automatic, see https://bugzilla.gnome.org/show_bug.cgi?id=584662
if (St.Widget.get_default_direction () == St.TextDirection.RTL)
this._background.add_style_pseudo_class('rtl');
this.actor.add_actor(this._background);
let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator' });
@ -424,7 +471,7 @@ ThumbnailsBox.prototype = {
this._indicatorY = 0; // only used when _animatingIndicator is true
this._stateCounts = {};
for (key in ThumbnailState)
for (let key in ThumbnailState)
this._stateCounts[ThumbnailState[key]] = 0;
this._thumbnails = [];
@ -441,16 +488,17 @@ ThumbnailsBox.prototype = {
this._stateUpdateQueued = false;
this._stateCounts = {};
for (key in ThumbnailState)
for (let key in ThumbnailState)
this._stateCounts[ThumbnailState[key]] = 0;
// The "porthole" is the portion of the screen that we show in the workspaces
let panelHeight = Main.panel.actor.height;
let monitor = global.get_primary_monitor();
this._porthole = {
x: 0,
y: panelHeight,
width: global.screen_width,
height: global.screen_height - panelHeight
x: monitor.x,
y: monitor.y + panelHeight,
width: monitor.width,
height: monitor.height - panelHeight
};
this.addThumbnails(0, global.screen.n_workspaces);

View File

@ -25,14 +25,13 @@ const MAX_WORKSPACES = 16;
const CONTROLS_POP_IN_TIME = 0.1;
function WorkspacesView(width, height, x, y, workspaces) {
this._init(width, height, x, y, workspaces);
function WorkspacesView(workspaces) {
this._init(workspaces);
}
WorkspacesView.prototype = {
_init: function(width, height, x, y, workspaces) {
_init: function(workspaces) {
this.actor = new St.Group({ style_class: 'workspaces-view' });
this.actor.set_clip(x, y, width, height);
// The actor itself isn't a drop target, so we don't want to pick on its area
this.actor.set_size(0, 0);
@ -43,19 +42,17 @@ WorkspacesView.prototype = {
function() {
let node = this.actor.get_theme_node();
this._spacing = node.get_length('spacing');
this._computeWorkspacePositions();
this._updateWorkspaceActors(false);
}));
this.actor.connect('notify::mapped',
Lang.bind(this, this._onMappedChanged));
this._width = width;
this._height = height;
this._x = x;
this._y = y;
this._zoomScale = 1.0;
this._width = 0;
this._height = 0;
this._x = 0;
this._y = 0;
this._workspaceRatioSpacing = 0;
this._spacing = 0;
this._activeWorkspaceX = 0; // x offset of active ws while dragging
this._activeWorkspaceY = 0; // y offset of active ws while dragging
this._lostWorkspaces = [];
this._animating = false; // tweening
this._scrolling = false; // swipe-scrolling
@ -71,6 +68,18 @@ WorkspacesView.prototype = {
this._workspaces[w].actor.reparent(this.actor);
this._workspaces[activeWorkspaceIndex].actor.raise_top();
this._extraWorkspaces = [];
let monitors = global.get_monitors();
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == global.get_primary_monitor_index())
continue;
let ws = new Workspace.Workspace(null, i);
this._extraWorkspaces[m++] = ws;
ws.setGeometry(monitors[i].x, monitors[i].y, monitors[i].width, monitors[i].height);
global.overlay_group.add_actor(ws.actor);
}
// Position/scale the desktop windows and their children after the
// workspaces have been created. This cannot be done first because
// window movement depends on the Workspaces object being accessible
@ -80,6 +89,13 @@ WorkspacesView.prototype = {
Lang.bind(this, function() {
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomToOverview();
for (let w = 0; w < this._extraWorkspaces.length; w++)
this._extraWorkspaces[w].zoomToOverview();
}));
this._overviewShownId =
Main.overview.connect('shown',
Lang.bind(this, function() {
this.actor.set_clip(this._x, this._y, this._width, this._height);
}));
this._scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
@ -109,30 +125,18 @@ WorkspacesView.prototype = {
this._swipeScrollEndId = 0;
},
setZoomScale: function(zoomScale) {
if (zoomScale == this._zoomScale)
return;
setGeometry: function(x, y, width, height, spacing) {
if (this._x == x && this._y == y &&
this._width == width && this._height == height)
return;
this._width = width;
this._height = height;
this._x = x;
this._y = y;
this._workspaceRatioSpacing = spacing;
this._zoomScale = zoomScale;
if (this._zoomOut) {
// If we are already zoomed out, then we have to reposition.
// Note that when shown initially zoomOut is false, so we
// won't trigger this.
// setZoomScale can be invoked when the workspaces view is
// reallocated. Since we just want to animate things to the
// new position it seems OK to call updateWorkspaceActors
// immediately - adding a tween doesn't immediately cause
// a new allocation. But hide/show of the window overlays we
// do around animation does, so we need to do it later.
// This can be removed when we fix things to not hide/show
// the window overlay.
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
Lang.bind(this, function() {
this._computeWorkspacePositions();
this._updateWorkspaceActors(true);
}));
}
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setGeometry(x, y, width, height);
},
_lookupWorkspaceForMetaWindow: function (metaWindow) {
@ -154,101 +158,41 @@ WorkspacesView.prototype = {
activeWorkspace.actor.raise_top();
this.actor.remove_clip(this._x, this._y, this._width, this._height);
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomFromOverview();
for (let w = 0; w < this._extraWorkspaces.length; w++)
this._extraWorkspaces[w].zoomFromOverview();
},
destroy: function() {
this.actor.destroy();
},
getScale: function() {
return this._workspaces[0].scale;
},
syncStacking: function(stackIndices) {
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].syncStacking(stackIndices);
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].syncStacking(stackIndices);
},
// Get the grid position of the active workspace.
getActiveWorkspacePosition: function() {
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
return [activeWorkspace.x, activeWorkspace.y];
},
zoomOut: function() {
if (this._zoomOut)
return;
this._zoomOut = true;
this._computeWorkspacePositions();
this._updateWorkspaceActors(true);
},
zoomIn: function() {
if (!this._zoomOut)
return;
this._zoomOut = false;
this._computeWorkspacePositions();
this._updateWorkspaceActors(true);
},
// Compute the position, scale and opacity of the workspaces, but don't
// actually change the actors to match
_computeWorkspacePositions: function() {
let active = global.screen.get_active_workspace_index();
let zoomScale = this._zoomOut ? this._zoomScale : 1;
let scale = zoomScale * this._width / global.screen_width;
let _width = this._workspaces[0].actor.width * scale;
let _height = this._workspaces[0].actor.height * scale;
this._activeWorkspaceX = (this._width - _width) / 2;
this._activeWorkspaceY = (this._height - _height) / 2;
for (let w = 0; w < this._workspaces.length; w++) {
let workspace = this._workspaces[w];
workspace.opacity = (this._inDrag && w != active) ? 200 : 255;
workspace.scale = scale;
workspace.x = this._x + this._activeWorkspaceX;
// We adjust the center because the zoomScale is to leave space for
// the expanded workspace control so we want to zoom to either the
// left part of the area or the right part of the area
let offset = 0.5 * (1 - this._zoomScale) * this._width;
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
if (this._zoomOut)
workspace.x += rtl ? offset : - offset;
// We divide by zoomScale so that adjacent workspaces are always offscreen
// except when we are switching between workspaces
workspace.y = this._y + this._activeWorkspaceY
+ (w - active) * (_height + this._spacing) / zoomScale;
}
updateWindowPositions: function() {
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].positionWindows(Workspace.WindowPositionFlags.ANIMATE);
},
_scrollToActive: function(showAnimation) {
let active = global.screen.get_active_workspace_index();
this._computeWorkspacePositions();
this._updateWorkspaceActors(showAnimation);
this._updateScrollAdjustment(active, showAnimation);
},
// Update workspace actors parameters to the values calculated in
// _computeWorkspacePositions()
// Update workspace actors parameters
// @showAnimation: iff %true, transition between states
_updateWorkspaceActors: function(showAnimation) {
let active = global.screen.get_active_workspace_index();
let targetWorkspaceNewY = this._y + this._activeWorkspaceY;
let targetWorkspaceCurrentY = this._workspaces[active].y;
let dy = targetWorkspaceNewY - targetWorkspaceCurrentY;
this._animating = showAnimation;
@ -257,14 +201,12 @@ WorkspacesView.prototype = {
Tweener.removeTweens(workspace.actor);
workspace.y += dy;
let opacity = (this._inDrag && w != active) ? 200 : 255;
let y = (w - active) * (this._height + this._spacing + this._workspaceRatioSpacing);
if (showAnimation) {
let params = { x: workspace.x,
y: workspace.y,
scale_x: workspace.scale,
scale_y: workspace.scale,
opacity: workspace.opacity,
let params = { y: y,
opacity: opacity,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad'
};
@ -281,9 +223,8 @@ WorkspacesView.prototype = {
}
Tweener.addTween(workspace.actor, params);
} else {
workspace.actor.set_scale(workspace.scale, workspace.scale);
workspace.actor.set_position(workspace.x, workspace.y);
workspace.actor.opacity = workspace.opacity;
workspace.actor.set_position(0, y);
workspace.actor.opacity = opacity;
if (w == 0)
this._updateVisibility();
}
@ -294,7 +235,6 @@ WorkspacesView.prototype = {
Tweener.removeTweens(workspace.actor);
workspace.y += dy;
workspace.actor.show();
workspace.hideWindowsOverlays();
@ -338,7 +278,6 @@ WorkspacesView.prototype = {
this._lostWorkspaces[l].destroy();
this._lostWorkspaces = [];
this._computeWorkspacePositions();
this._updateWorkspaceActors(false);
},
@ -380,7 +319,6 @@ WorkspacesView.prototype = {
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++)
this.actor.add_actor(this._workspaces[w].actor);
this._computeWorkspacePositions();
this._updateWorkspaceActors(false);
} else {
this._lostWorkspaces = lostWorkspaces;
@ -397,10 +335,16 @@ WorkspacesView.prototype = {
},
_onDestroy: function() {
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].destroy();
this._scrollAdjustment.run_dispose();
Main.overview.disconnect(this._overviewShowingId);
Main.overview.disconnect(this._overviewShownId);
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
if (this._inDrag)
this._dragEnd();
if (this._timeoutId) {
Mainloop.source_remove(this._timeoutId);
this._timeoutId = 0;
@ -443,6 +387,7 @@ WorkspacesView.prototype = {
return;
this._inDrag = true;
this._firstDragMotion = true;
this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion)
@ -454,6 +399,14 @@ WorkspacesView.prototype = {
if (Main.overview.animationInProgress)
return DND.DragMotionResult.CONTINUE;
if (this._firstDragMotion) {
this._firstDragMotion = false;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
}
let primary = global.get_primary_monitor();
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
@ -467,7 +420,6 @@ WorkspacesView.prototype = {
let switchTop = (dragEvent.y <= topEdge && topWorkspace);
if (switchTop && this._dragOverLastY != topEdge) {
topWorkspace.metaWorkspace.activate(global.get_current_time());
topWorkspace.setReservedSlot(dragEvent.dragActor._delegate);
this._dragOverLastY = topEdge;
return DND.DragMotionResult.CONTINUE;
@ -476,7 +428,6 @@ WorkspacesView.prototype = {
let switchBottom = (dragEvent.y >= bottomEdge && bottomWorkspace);
if (switchBottom && this._dragOverLastY != bottomEdge) {
bottomWorkspace.metaWorkspace.activate(global.get_current_time());
bottomWorkspace.setReservedSlot(dragEvent.dragActor._delegate);
this._dragOverLastY = bottomEdge;
return DND.DragMotionResult.CONTINUE;
@ -511,7 +462,6 @@ WorkspacesView.prototype = {
this._timeoutId = Mainloop.timeout_add_seconds(1,
Lang.bind(this, function() {
hoverWorkspace.metaWorkspace.activate(global.get_current_time());
hoverWorkspace.setReservedSlot(dragEvent.dragActor._delegate);
return false;
}));
} else {
@ -534,6 +484,8 @@ WorkspacesView.prototype = {
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(null);
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].setReservedSlot(null);
},
_swipeScrollBegin: function() {
@ -557,12 +509,6 @@ WorkspacesView.prototype = {
Main.overview.hide();
}
if (result == Overview.SwipeScrollResult.SWIPE)
// The active workspace has changed; while swipe-scrolling
// has already taken care of the positioning, the cached
// positions need to be updated
this._computeWorkspacePositions();
// Make sure title captions etc are shown as necessary
this._updateVisibility();
},
@ -590,7 +536,7 @@ WorkspacesView.prototype = {
return;
let currentY = firstWorkspaceY;
let newY = this._y - adj.value / (adj.upper - 1) * workspacesHeight;
let newY = - adj.value / (adj.upper - 1) * workspacesHeight;
let dy = newY - currentY;
@ -618,6 +564,7 @@ WorkspacesDisplay.prototype = {
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.actor.set_clip_to_allocation(true);
let controls = new St.Bin({ style_class: 'workspace-controls',
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT,
@ -633,6 +580,8 @@ WorkspacesDisplay.prototype = {
controls.connect('scroll-event',
Lang.bind(this, this._onScrollEvent));
this._monitorIndex = global.get_primary_monitor_index();
this._monitor = global.get_monitors()[this._monitorIndex];
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
controls.add_actor(this._thumbnailsBox.actor);
@ -640,65 +589,53 @@ WorkspacesDisplay.prototype = {
this.workspacesView = null;
this._inDrag = false;
this._cancelledDrag = false;
this._alwaysZoomOut = false;
this._zoomOut = false;
this._zoomFraction = 0;
this._updateAlwaysZoom();
global.screen.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
this._alwaysZoomOut = true;
}));
Main.xdndHandler.connect('drag-end', Lang.bind(this, function(){
this._alwaysZoomOut = false;
this._updateAlwaysZoom();
}));
this._nWorkspacesNotifyId = 0;
this._switchWorkspaceNotifyId = 0;
this._itemDragBeginId = 0;
this._itemDragCancelledId = 0;
this._itemDragEndId = 0;
this._windowDragBeginId = 0;
this._windowDragCancelledId = 0;
this._windowDragEndId = 0;
},
show: function() {
this._zoomOut = this._alwaysZoomOut;
this._zoomFraction = this._alwaysZoomOut ? 1 : 0;
this._updateZoom();
this._controls.show();
this._thumbnailsBox.show();
this._workspaces = [];
for (let i = 0; i < global.screen.n_workspaces; i++) {
let metaWorkspace = global.screen.get_workspace_by_index(i);
this._workspaces[i] = new Workspace.Workspace(metaWorkspace);
this._workspaces[i] = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
}
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
let totalAllocation = this.actor.allocation;
let totalWidth = totalAllocation.x2 - totalAllocation.x1;
let totalHeight = totalAllocation.y2 - totalAllocation.y1;
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
totalWidth -= controlsVisible;
// Workspaces expect to have the same ratio as the screen, so take
// this into account when fitting the workspace into the available space
let width, height;
let totalRatio = totalWidth / totalHeight;
let wsRatio = global.screen_width / global.screen_height;
if (wsRatio > totalRatio) {
width = totalWidth;
height = Math.floor(totalWidth / wsRatio);
} else {
width = Math.floor(totalHeight * wsRatio);
height = totalHeight;
}
// Position workspaces in the available space
let [x, y] = this.actor.get_transformed_position();
x = Math.floor(x + Math.abs(totalWidth - width) / 2);
y = Math.floor(y + Math.abs(totalHeight - height) / 2);
if (rtl)
x += controlsVisible;
let newView = new WorkspacesView(width, height, x, y, this._workspaces);
this._updateZoomScale();
if (this.workspacesView)
this.workspacesView.destroy();
this.workspacesView = newView;
this.workspacesView = new WorkspacesView(this._workspaces);
this._updateWorkspacesGeometry();
this._nWorkspacesNotifyId =
global.screen.connect('notify::n-workspaces',
@ -711,20 +648,23 @@ WorkspacesDisplay.prototype = {
if (this._itemDragBeginId == 0)
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
Lang.bind(this, this._dragBegin));
if (this._itemDragCancelledId == 0)
this._itemDragCancelledId = Main.overview.connect('item-drag-cancelled',
Lang.bind(this, this._dragCancelled));
if (this._itemDragEndId == 0)
this._itemDragEndId = Main.overview.connect('item-drag-end',
Lang.bind(this, this._dragEnd));
if (this._windowDragBeginId == 0)
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
Lang.bind(this, this._dragBegin));
if (this._windowDragCancelledId == 0)
this._windowDragCancelledId = Main.overview.connect('window-drag-cancelled',
Lang.bind(this, this._dragCancelled));
if (this._windowDragEndId == 0)
this._windowDragEndId = Main.overview.connect('window-drag-end',
Lang.bind(this, this._dragEnd));
this._onRestacked();
this._zoomOut = false;
this._zoomFraction = 0;
this._updateZoom();
},
hide: function() {
@ -743,7 +683,11 @@ WorkspacesDisplay.prototype = {
Main.overview.disconnect(this._itemDragBeginId);
this._itemDragBeginId = 0;
}
if (this._itemEndBeginId > 0) {
if (this._itemDragCancelledId > 0) {
Main.overview.disconnect(this._itemDragCancelledId);
this._itemDragCancelledId = 0;
}
if (this._itemDragEndId > 0) {
Main.overview.disconnect(this._itemDragEndId);
this._itemDragEndId = 0;
}
@ -751,6 +695,10 @@ WorkspacesDisplay.prototype = {
Main.overview.disconnect(this._windowDragBeginId);
this._windowDragBeginId = 0;
}
if (this._windowDragCancelledId > 0) {
Main.overview.disconnect(this._windowDragCancelledId);
this._windowDragCancelledId = 0;
}
if (this._windowDragEndId > 0) {
Main.overview.disconnect(this._windowDragEndId);
this._windowDragEndId = 0;
@ -774,6 +722,23 @@ WorkspacesDisplay.prototype = {
return this._zoomFraction;
},
_updateAlwaysZoom: function() {
this._alwaysZoomOut = false;
let monitors = global.get_monitors();
let primary = global.get_primary_monitor();
/* Look for any monitor to the right of the primary, if there is
* one, we always keep zoom out, otherwise its hard to reach
* the thumbnail area without passing into the next monitor. */
for (let i = 0; i < monitors.length; i++) {
if (monitors[i].x >= primary.x + primary.width) {
this._alwaysZoomOut = true;
break;
}
}
},
_getPreferredWidth: function (actor, forHeight, alloc) {
// pass through the call in case the child needs it, but report 0x0
this._controls.get_preferred_width(forHeight);
@ -809,22 +774,41 @@ WorkspacesDisplay.prototype = {
childBox.y2 = box.y2- box.y1;
this._controls.allocate(childBox, flags);
this._updateZoomScale();
this._updateWorkspacesGeometry();
},
_updateZoomScale: function() {
_updateWorkspacesGeometry: function() {
if (!this.workspacesView)
return;
let totalAllocation = this.actor.allocation;
let totalWidth = totalAllocation.x2 - totalAllocation.x1;
let totalHeight = totalAllocation.y2 - totalAllocation.y1;
let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
let fullHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(totalHeight);
let width = fullWidth;
let height = fullHeight;
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(height);
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
let zoomScale = (totalWidth - controlsNatural) / (totalWidth - controlsVisible);
this.workspacesView.setZoomScale(zoomScale);
let [x, y] = this.actor.get_transformed_position();
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
if (this._zoomOut) {
width -= controlsNatural;
if (rtl)
x += controlsNatural;
} else {
width -= controlsVisible;
if (rtl)
x += controlsVisible;
}
height = (fullHeight / fullWidth) * width;
let difference = fullHeight - height;
y += difference / 2;
this.workspacesView.setGeometry(x, y, width, height, difference);
},
_onRestacked: function() {
@ -853,7 +837,7 @@ WorkspacesDisplay.prototype = {
// Assume workspaces are only added at the end
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
this._workspaces[w] = new Workspace.Workspace(metaWorkspace);
this._workspaces[w] = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
}
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
@ -890,9 +874,10 @@ WorkspacesDisplay.prototype = {
if (Main.overview.animationInProgress)
return;
let shouldZoom = this._controls.hover || this._inDrag;
let shouldZoom = this._alwaysZoomOut || this._controls.hover || (this._inDrag && !this._cancelledDrag);
if (shouldZoom != this._zoomOut) {
this._zoomOut = shouldZoom;
this._updateWorkspacesGeometry();
if (!this.workspacesView)
return;
@ -902,10 +887,7 @@ WorkspacesDisplay.prototype = {
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad' });
if (shouldZoom)
this.workspacesView.zoomOut();
else
this.workspacesView.zoomIn();
this.workspacesView.updateWindowPositions();
}
},
@ -915,6 +897,12 @@ WorkspacesDisplay.prototype = {
_dragBegin: function() {
this._inDrag = true;
this._cancelledDrag = false;
this._updateZoom();
},
_dragCancelled: function() {
this._cancelledDrag = true;
this._updateZoom();
},

View File

@ -4,7 +4,6 @@ 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() {
@ -41,9 +40,14 @@ XdndHandler.prototype = {
// Called when the user cancels the drag (i.e release the button)
_onLeave: function() {
if (this._windowGroupVisibilityHandlerId != 0) {
Mainloop.source_remove(this._windowGroupVisibilityHandlerId);
global.window_group.disconnect(this._windowGroupVisibilityHandlerId);
this._windowGroupVisibilityHandlerId = 0;
}
if (this._cursorWindowClone) {
this._cursorWindowClone.destroy();
this._cursorWindowClone = null;
}
this.emit('drag-end');
},
@ -77,8 +81,7 @@ XdndHandler.prototype = {
// Make sure that the clone has the same position as the source
this._cursorWindowClone.add_constraint(constraint_position);
} else {
if (this._cursorWindowClone)
{
if (this._cursorWindowClone) {
this._cursorWindowClone.destroy();
this._cursorWindowClone = null;
}

View File

@ -1,5 +1,8 @@
af
ar
bg
bn
bn_IN
ca
cs
da
@ -8,6 +11,7 @@ el
en_GB
es
et
eu
fa
fi
fr
@ -15,6 +19,7 @@ ga
gl
gu
he
hi
hu
id
it
@ -22,6 +27,8 @@ ja
ko
kn
lt
lv
mr
nb
nl
nn

View File

@ -13,6 +13,7 @@ js/ui/messageTray.js
js/ui/overview.js
js/ui/panel.js
js/ui/placeDisplay.js
js/ui/polkitAuthenticationAgent.js
js/ui/popupMenu.js
js/ui/runDialog.js
js/ui/searchDisplay.js
@ -20,6 +21,7 @@ js/ui/statusMenu.js
js/ui/status/accessibility.js
js/ui/status/bluetooth.js
js/ui/status/keyboard.js
js/ui/status/network.js
js/ui/status/power.js
js/ui/status/volume.js
js/ui/telepathyClient.js
@ -28,7 +30,11 @@ js/ui/windowAttentionHandler.js
js/ui/workspacesView.js
src/gvc/gvc-mixer-control.c
src/gdmuser/gdm-user.c
src/main.c
src/shell-app.c
src/shell-app-system.c
src/shell-global.c
src/shell-mobile-providers.c
src/shell-polkit-authentication-agent.c
src/shell-util.c

1102
po/af.po Normal file

File diff suppressed because it is too large Load Diff

609
po/ar.po

File diff suppressed because it is too large Load Diff

1167
po/bg.po

File diff suppressed because it is too large Load Diff

1202
po/bn.po Normal file

File diff suppressed because it is too large Load Diff

1189
po/bn_IN.po Normal file

File diff suppressed because it is too large Load Diff

1437
po/ca.po

File diff suppressed because it is too large Load Diff

683
po/cs.po

File diff suppressed because it is too large Load Diff

1317
po/da.po

File diff suppressed because it is too large Load Diff

1223
po/de.po

File diff suppressed because it is too large Load Diff

824
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

669
po/es.po

File diff suppressed because it is too large Load Diff

552
po/et.po
View File

@ -12,21 +12,21 @@ 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-02-04 22:28+0000\n"
"PO-Revision-Date: 2011-02-06 08:43+0200\n"
"Last-Translator: Ivar Smolin <okul@linux.ee>\n"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2011-03-30 17:13+0000\n"
"PO-Revision-Date: 2011-03-30 23:56+0300\n"
"Last-Translator: Mattias Põldaru <mahfiaz@gmail.com>\n"
"Language-Team: Estonian <gnome-et@linux.ee>\n"
"Language: et\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"
msgstr "GNOME Shell"
msgid "Window management and application launching"
msgstr "Aknahaldur ja rakenduste käivitaja"
@ -58,6 +58,10 @@ msgstr ""
msgid "History for command (Alt-F2) dialog"
msgstr "Käsudialoogi (Alt-F2) ajalugu"
# suurendusklaasidialoog? miks ka mitte :)
msgid "History for the looking glass dialog"
msgstr "Otsingudialoogi 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."
@ -83,6 +87,16 @@ msgid ""
"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 ""
"Määrab GStreameri toru, mida kasutatakse lindistuste kodeerimiseks. See peab "
"vastama gst-launch'i süntaksile. Torul peaks olema vaba plokk (pad), kuhu "
"lindistatav video salvestatakse. Tavaliselt on vaba plokk olemas; selle "
"ploki väljund kirjutatakse väljundfaili. Toru võib hoolitseda ka enda "
"väljundi eest - seda võib kasutada väljundi saatmiseks icecast serverisse "
"shout2send või sarnase tehnoloogia abil. Kui see on määramata või väärtus on "
"tühi, kasutatakse vaikimisi toru. See on praegu 'videorate ! vp8enc "
"quality=10 speed=2 threads=%T ! queue ! webmmux' ning lindistab WEBM "
"vormingusse VP8 koodekiga. %T asendatakse süsteemi oletatava optimaalseima "
"lõimede (thread) arvuga."
msgid "Show date in clock"
msgstr "Kell näitab kuupäeva"
@ -96,7 +110,7 @@ msgstr "Kellaaega näidatakse sekunditega"
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
msgstr "Nendele tunnustele vastavaid rakendusi kuvatakse lemmikutes."
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
@ -112,9 +126,10 @@ msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
msgstr ""
"GNOME Shelli lindistatava ekraanivideo kaadrisagedus (kaadrit sekundis)."
msgid "The gstreamer pipeline used to encode the screencast"
msgstr ""
msgstr "GStreameri toru, mida ekraanivideo kodeerimiseks kasutatakse"
msgid ""
"The shell normally monitors active applications in order to present the most "
@ -122,125 +137,19 @@ msgid ""
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"Shell tavaliselt seirab aktiivseid rakendusi, et näidata enamkasutatavaid "
"(näiteks käivitajaid). Kuigi neid andmeid hoitakse privaatselt, võid "
"privaatsuse suurendamiseks selle keelata. Selle keelamine siiski ei eemalda "
"juba salvestatud andmeid."
msgid "Uuids of extensions to disable"
msgstr "Keelatavate laienduste UUID-d"
msgid "Whether to collect stats about applications usage"
msgstr ""
msgstr "Kas rakenduste kasutuse kohta kogutakse andmeid"
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"
msgstr "keelatud OpenSearch pakkujad"
msgid "Command not found"
msgstr "Käsku ei leitud"
@ -250,9 +159,6 @@ msgstr "Käsku ei leitud"
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:"
@ -264,8 +170,8 @@ msgstr "Kõik"
msgid "APPLICATIONS"
msgstr "Rakendused"
msgid "PREFERENCES"
msgstr "Eelistused"
msgid "SETTINGS"
msgstr "Seaded"
msgid "New Window"
msgstr "Uus aken"
@ -289,7 +195,7 @@ msgstr "%s eemaldati lemmikutest."
#.
msgctxt "event list time"
msgid "All Day"
msgstr "Kogu päeva"
msgstr "Kogu päev"
#. Translators: Shown in calendar event list, if 24h format
msgctxt "event list time"
@ -382,7 +288,7 @@ msgstr "L"
#. Translators: Text to show if there are no events
msgid "Nothing Scheduled"
msgstr ""
msgstr "Ühtegi sündmust pole plaanitud"
#. Translators: Shown on calendar heading when selected day occurs on current year
msgctxt "calendar heading"
@ -465,6 +371,8 @@ msgstr "Logi välja"
msgid "Click Log Out to quit these applications and log out of the system."
msgstr ""
"Nende rakenduste sulgemiseks ja süsteemist väljalogimiseks klõpsa nupule "
"Logi välja."
#, c-format
msgid "%s will be logged out automatically in %d seconds."
@ -477,17 +385,19 @@ msgstr "Sind logitakse %d sekundi pärast automaatselt välja."
msgid "Logging out of the system."
msgstr "Süsteemist väljalogimine"
msgid "Shut Down"
msgid "Power Off"
msgstr "Lülita välja"
msgid "Click Shut Down to quit these applications and shut down the system."
msgid "Click Power Off to quit these applications and power off the system."
msgstr ""
"Nende rakenduste sulgemiseks ja süsteemi väljalülitamiseks klõpsa nupule "
"Lülita välja."
#, c-format
msgid "The system will shut down automatically in %d seconds."
msgid "The system will power off automatically in %d seconds."
msgstr "%d sekundi pärast lülitub süsteem automaatselt välja."
msgid "Shutting down the system."
msgid "Powering off the system."
msgstr "Süsteemi väljalülitamine."
msgid "Restart"
@ -505,9 +415,6 @@ 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"
@ -534,6 +441,9 @@ msgstr "Kuva lähtekoodi"
msgid "Web Page"
msgstr "Veebileht"
msgid "Open"
msgstr "Ava"
msgid "System Information"
msgstr "Süsteemi andmed"
@ -546,6 +456,11 @@ msgstr "Aknad"
msgid "Applications"
msgstr "Rakendused"
#. Translators: this is the name of the dock/favorites area on
#. the left of the overview
msgid "Dash"
msgstr "Dokk"
#. TODO - _quit() doesn't really work on apps in state STARTING yet
#, c-format
msgid "Quit %s"
@ -556,6 +471,9 @@ msgstr "Lõpeta %s"
msgid "Activities"
msgstr "Tegevused"
msgid "Top Bar"
msgstr "Ülemine riba"
#, c-format
msgid "Failed to unmount '%s'"
msgstr "'%s' lahtihaakimine nurjus"
@ -569,6 +487,25 @@ msgstr "Ühendumine..."
msgid "PLACES & DEVICES"
msgstr "Asukohad ja seadmed"
msgid "Authentication Required"
msgstr "Vajalik on autentimine"
msgid "Administrator"
msgstr "Administraator"
msgid "Authenticate"
msgstr "Autendi"
#. Translators: "that didn't work" refers to the fact that the
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
msgid "Sorry, that didn't work. Please try again."
msgstr "Kahjuks see ei sobinud. Palun proovi uuesti."
msgid "Password:"
msgstr "Parool:"
#. Translators: this MUST be either "toggle-switch-us"
#. (for toggle switches containing the English words
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
@ -580,6 +517,18 @@ msgstr "toggle-switch-intl"
msgid "Please enter a command:"
msgstr "Palun sisesta käsk:"
msgid "Searching..."
msgstr "Otsimine..."
msgid "No matching results."
msgstr "Tulemused puuduvad."
msgid "Power Off..."
msgstr "Lülita välja..."
msgid "Suspend"
msgstr "Uinak"
msgid "Available"
msgstr "Saadaval"
@ -601,24 +550,15 @@ msgstr "Vaheta kasutajat"
msgid "Log Out..."
msgstr "Logi välja..."
#. This is temporarily removed, see
#. http://bugzilla.gnome.org/show_bug.cgi?id=636680
#. for details.
#. item = new PopupMenu.PopupMenuItem(_("Suspend..."));
#. item.connect('activate', Lang.bind(this, this._onShutDownActivate));
#. this.menu.addMenuItem(item);
msgid "Shut Down..."
msgstr "Lülita välja..."
msgid "Zoom"
msgstr ""
msgid "Screen Reader"
msgstr "Ekraanilugeja"
msgid "Screen Keyboard"
msgstr "Ekraaniklaviatuur"
msgstr "Suurendus"
#. let screenReader = this._buildItem(_("Screen Reader"), APPLICATIONS_SCHEMA,
#. 'screen-reader-enabled');
#. this.menu.addMenuItem(screenReader);
#. let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
#. 'screen-keyboard-enabled');
#. this.menu.addMenuItem(screenKeyboard);
msgid "Visual Alerts"
msgstr "Visuaalsed märguanded"
@ -638,10 +578,10 @@ msgid "Universal Access Settings"
msgstr "Universaalse ligipääsu sätted"
msgid "High Contrast"
msgstr ""
msgstr "Kõrgkontrastne"
msgid "Large Text"
msgstr ""
msgstr "Suur tekst"
msgid "Bluetooth"
msgstr "Bluetooth"
@ -653,7 +593,7 @@ msgid "Send Files to Device..."
msgstr "Failide saatmine seadmesse..."
msgid "Setup a New Device..."
msgstr ""
msgstr "Uue seadme häälestamine..."
msgid "Bluetooth Settings"
msgstr "Bluetoothi sätted"
@ -672,7 +612,7 @@ msgstr "Viga seadme sirvimisel"
#, c-format
msgid "The requested device cannot be browsed, error is '%s'"
msgstr ""
msgstr "Küsitud seadet pole võimalik sirvida, viga on '%s'"
msgid "Keyboard Settings"
msgstr "Klaviatuurisätted"
@ -683,9 +623,6 @@ 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"
@ -731,12 +668,126 @@ msgstr "Palun sisesta seadme poolt öeldav PIN-kood."
msgid "OK"
msgstr "Olgu"
msgid "Show Keyboard Layout..."
msgstr "Klaviatuuripaigutuse kuvamine..."
msgid "Localization Settings"
msgstr "Lokaliseerimissätted"
msgid "<unknown>"
msgstr "<tundmatu>"
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
msgid "disabled"
msgstr "keelatud"
msgid "connecting..."
msgstr "ühendumine..."
#. Translators: this is for network connections that require some kind of key or password
msgid "authentication required"
msgstr "vajalik on autentimine"
#. Translators: this is for devices that require some kind of firmware or kernel
#. module, which is missing
msgid "firmware missing"
msgstr "püsivara puudub"
#. Translators: this is for wired network devices that are physically disconnected
msgid "cable unplugged"
msgstr "juhe eemaldatud"
#. Translators: this is for a network device that cannot be activated (for example it
#. is disabled by rfkill, or it has no coverage
msgid "unavailable"
msgstr "pole saadaval"
msgid "connection failed"
msgstr "ühendumine nurjus"
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
#. and we cannot access its settings (including the name)
msgid "Connected (private)"
msgstr "Ühendatud (privaatne)"
msgid "Auto Ethernet"
msgstr "Automaatne ethernet"
msgid "Auto broadband"
msgstr "Automaatne lairibaühendus"
msgid "Auto dial-up"
msgstr "Automaatne sissehelistamine"
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
#, c-format
msgid "Auto %s"
msgstr "Automaatne %s"
msgid "Auto bluetooth"
msgstr "Automaatne bluetooth"
msgid "Auto wireless"
msgstr "Automaatne juhtmeta ühendus"
msgid "More..."
msgstr "Veel..."
msgid "Enable networking"
msgstr "Luba võrguühendused"
msgid "Wired"
msgstr "Juhtmega"
msgid "Wireless"
msgstr "Juhtmeta"
msgid "Mobile broadband"
msgstr "Mobiiliühendus"
msgid "VPN Connections"
msgstr "VPN-ühendused"
msgid "Network Settings"
msgstr "Võrgusätted"
#, c-format
msgid "You're now connected to mobile broadband connection '%s'"
msgstr "Loodi mobiiliühendus '%s'"
#, c-format
msgid "You're now connected to wireless network '%s'"
msgstr "Loodi ühendus juhtmeta võrguga '%s'"
#, c-format
msgid "You're now connected to wired network '%s'"
msgstr "Loodi ühendus juhtmega võrguga '%s'"
#, c-format
msgid "You're now connected to VPN network '%s'"
msgstr "Loodi ühendus VPN-võrguga '%s'"
#, c-format
msgid "You're now connected to '%s'"
msgstr "Loodi võrguühendus '%s' kaudu"
msgid "Connection established"
msgstr "Ühendus loodud"
msgid "Networking is disabled"
msgstr "Võrguühendused on keelatud"
msgid "Network Manager"
msgstr "Võrguhaldur"
msgid "Power Settings"
msgstr "Toitesätted..."
#. 0 is reported when UPower does not have enough data
#. to estimate battery life
msgid "Estimating..."
msgstr "Andmete kogumine..."
#, c-format
msgid "%d hour remaining"
msgid_plural "%d hours remaining"
@ -829,8 +880,15 @@ msgstr "%s on hõivatud."
msgid "Sent at %X on %A"
msgstr "Saadetud: %a, kell %X"
msgid "Search your computer"
msgstr ""
#. Translators: this is the text displayed
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
msgid "Type to search..."
msgstr "Otsing..."
msgid "Search"
msgstr "Otsing"
#, c-format
msgid "%s has finished starting"
@ -840,32 +898,32 @@ msgstr "%s läks käima"
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] ""
msgstr[0] "%u väljund"
msgstr[1] "%u väljundit"
#. translators:
#. * The number of sound inputs on a particular device
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%u sisend"
msgstr[1] "%u sisendit"
msgid "System Sounds"
msgstr "Süsteemi helid"
msgid "Print version"
msgstr "Printimise versioon"
#, c-format
msgid "Failed to launch '%s'"
msgstr "'%s' käivitamine nurjus"
msgid "Less than a minute ago"
msgstr "Vähem kui minuti eest"
@ -893,6 +951,15 @@ msgid_plural "%d weeks ago"
msgstr[0] "%d nädal tagasi"
msgstr[1] "%d nädalat tagasi"
msgid "United Kingdom"
msgstr "Suurbritannia"
msgid "Default"
msgstr "Vaikimisi"
msgid "Authentication dialog was dismissed by the user"
msgstr "Kasutaja katkestas autentimisdialoogi"
msgid "Home Folder"
msgstr "Kodukaust"
@ -901,9 +968,6 @@ msgstr "Kodukaust"
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
@ -913,8 +977,140 @@ msgstr "Otsing"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Suspend..."
#~ msgstr "Peata..."
#~ msgid "Shut Down"
#~ msgstr "Lülita välja"
#~ msgid "Click Shut Down to quit these applications and shut down the system."
#~ msgstr ""
#~ "Nende rakenduste sulgemiseks ja süsteemi väljalülitamiseks klõpsa nupule "
#~ "Logi välja."
#~ msgid "The system will shut down automatically in %d seconds."
#~ msgstr "%d sekundi pärast lülitub süsteem automaatselt välja."
#~ msgid "Shutting down the system."
#~ msgstr "Süsteemi väljalülitamine."
#~ msgid "Confirm"
#~ msgstr "Kinnita"
#~ msgid "Panel"
#~ msgstr "Paneel"
#~ msgid "No such application"
#~ msgstr "Sellist rakendust ei ole"
#~ msgid "Screen Reader"
#~ msgstr "Ekraanilugeja"
#~ msgid "Screen Keyboard"
#~ msgstr "Ekraaniklaviatuur"
#~ msgid "Clip the crosshairs at the center"
#~ msgstr "Niitristi keskel on auk"
#~ msgid "Color of the crosshairs"
#~ msgstr "Niitristi värvus"
#~ 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 "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"
#~ msgid "PREFERENCES"
#~ msgstr "Eelistused"
#~ msgid "Shut Down..."
#~ msgstr "Lülita välja..."
#~ msgid "Bluetooth Agent"
#~ msgstr "Bluetoothi agent"
#~ 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."
#~ msgid "Clock"
#~ msgstr "Kell"
@ -958,11 +1154,5 @@ msgstr "%1$s: %2$s"
#~ msgid "Find"
#~ msgstr "Otsi"
#~ msgid "Searching..."
#~ msgstr "Otsimine..."
#~ msgid "No matching results."
#~ msgstr "Tulemused puuduvad."
#~ msgid "Invisible"
#~ msgstr "Nähtamatu"

1232
po/eu.po Normal file

File diff suppressed because it is too large Load Diff

1251
po/fi.po

File diff suppressed because it is too large Load Diff

1170
po/fr.po

File diff suppressed because it is too large Load Diff

990
po/gl.po

File diff suppressed because it is too large Load Diff

801
po/gu.po

File diff suppressed because it is too large Load Diff

607
po/he.po

File diff suppressed because it is too large Load Diff

1185
po/hi.po Normal file

File diff suppressed because it is too large Load Diff

1172
po/hu.po

File diff suppressed because it is too large Load Diff

1190
po/id.po

File diff suppressed because it is too large Load Diff

644
po/it.po

File diff suppressed because it is too large Load Diff

1486
po/ja.po

File diff suppressed because it is too large Load Diff

279
po/kn.po
View File

@ -9,7 +9,7 @@ msgstr ""
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug."
"cgi?product=gnome-shell&component=general\n"
"POT-Creation-Date: 2011-02-21 01:21+0000\n"
"PO-Revision-Date: 2011-02-21 12:52+0530\n"
"PO-Revision-Date: 2011-03-09 09:36+0530\n"
"Last-Translator: Shankar Prasad <svenkate@redhat.com>\n"
"Language-Team: Kannada <kn@li.org>\n"
"MIME-Version: 1.0\n"
@ -20,59 +20,65 @@ msgstr ""
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr ""
msgstr "GNOME ಶೆಲ್‌"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr ""
msgstr "ವಿಂಡೊ ನಿರ್ವಹಣೆ ಹಾಗು ಅನ್ವಯವನ್ನು ಆರಂಭಿಸುವಿಕೆ"
#: ../data/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 "Enable internal tools useful for developers and testers from Alt-F2"
msgstr ""
"Alt-F2 ಇಂದ ವಿಕಸನೆಗಾರರಿಗೆ ಹಾಗು ಪರೀಕ್ಷಕರಿಗೆ ಉಪಯುಕ್ತವಾಗುವ ಆಂತರಿಕ ಉಪಕರಣಗಳನ್ನು "
"ಶಕ್ತಗೊಳಿಸುತ್ತದೆ"
#: ../data/org.gnome.shell.gschema.xml.in.h:3
msgid "File extension used for storing the screencast"
msgstr ""
msgstr "ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟುಗಳನ್ನು ಶೇಖರಿಸಿಡಲು ಬಳಸಲಾಗುವ ಕಡತ ವಿಸ್ತರಣೆಗಳು"
#: ../data/org.gnome.shell.gschema.xml.in.h:4
msgid "Framerate used for recording screencasts."
msgstr ""
msgstr "ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟುಗಳನ್ನು ರೆಕಾರ್ಡು ಮಾಡಲು ಬಳಸಲಾಗುವ ಫ್ರೇಮ್‌ದರಗಳು."
#: ../data/org.gnome.shell.gschema.xml.in.h:5
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:6
msgid "History for command (Alt-F2) dialog"
msgstr ""
msgstr "ಆಜ್ಞೆಯ ಇತಿಹಾಸ (Alt-F2) ಸಂವಾದಚೌಕ"
#: ../data/org.gnome.shell.gschema.xml.in.h:7
msgid "History for the looking glass dialog"
msgstr ""
msgstr "ನೋಡುವ ಗಾಜಿನ ಸಂವಾದ ಚೌಕಕ್ಕಾಗಿನ ಇತಿಹಾಸ"
#: ../data/org.gnome.shell.gschema.xml.in.h:8
msgid "If true, display date in the clock, in addition to time."
msgstr ""
msgstr "true ಆದಲ್ಲಿ, ದಿನಾಂಕವನ್ನು ಸಮಯದ ಜೊತೆಗೆ ಗಡಿಯಾರದಲ್ಲಿ ತೋರಿಸಲಾಗುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.h:9
msgid "If true, display seconds in time."
msgstr ""
msgstr "true ಆದಲ್ಲಿ, ಸಮಯದಲ್ಲಿ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸಲಾಗುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.h:10
msgid "If true, display the ISO week date in the calendar."
msgstr ""
msgstr "true ಆದಲ್ಲಿ, ಕ್ಯಾಲೆಂಡರಿನಲ್ಲಿ ISO ವಾರದ ದಿನವನ್ನು ತೋರಿಸುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.h:11
msgid "List of desktop file IDs for favorite applications"
msgstr ""
msgstr "ಮೆಚ್ಚಿನ ಅನ್ವಯಗಳಿಗಾಗಿನ ಗಣಕತೆರೆ ಕಡತ IDಗಳ ಪಟ್ಟಿ"
#: ../data/org.gnome.shell.gschema.xml.in.h:13
#, no-c-format
@ -91,21 +97,22 @@ msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:14
msgid "Show date in clock"
msgstr ""
msgstr "ಗಡಿಯಾರದಲ್ಲಿ ದಿನಾಂಕವನ್ನು ತೋರಿಸು"
#: ../data/org.gnome.shell.gschema.xml.in.h:15
msgid "Show the week date in the calendar"
msgstr ""
msgstr "ಕ್ಯಾಲೆಂಡರಿನಲ್ಲಿ ವಾರದ ದಿನವನ್ನು ತೋರಿಸು"
#: ../data/org.gnome.shell.gschema.xml.in.h:16
msgid "Show time with seconds"
msgstr ""
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 ""
@ -113,16 +120,21 @@ msgid ""
"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 ""
"ಪ್ರತಿ ಸೆಕೆಂಡಿನ ಫ್ರೇಮ್‌ಗಳಲ್ಲಿನ GNOME ಶೆಲ್‌ನ ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟ್‍ ರೆಕಾರ್ಡರಿನಿಂದ "
"ರೆಕಾರ್ಡು ಮಾಡಲಾದ ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟಿನ ಫ್ರೇಮ್‌ದರ. "
#: ../data/org.gnome.shell.gschema.xml.in.h:20
msgid "The gstreamer pipeline used to encode the screencast"
msgstr ""
msgstr "ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟ್‍ ಅನ್ನು ಎನ್ಕೋಡ್ ಮಾಡಲು ಬಳಸಲಾಗುವ gstreamer ಪೈಪ್‌ಲೈನ್"
#: ../data/org.gnome.shell.gschema.xml.in.h:21
msgid ""
@ -134,43 +146,43 @@ msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.h:22
msgid "Uuids of extensions to disable"
msgstr ""
msgstr "ಅಶಕ್ತಗೊಳಿಸಬೇಕಿರುವ Uuidಗಳ ವಿಸ್ತರಣೆಗಳು"
#: ../data/org.gnome.shell.gschema.xml.in.h:23
msgid "Whether to collect stats about applications usage"
msgstr ""
msgstr "ಅನ್ವಯದ ಬಳಕೆಯ ಬಗೆಗಿನ ಅಂಕಿಅಂಶಗಳನ್ನು ಸಂಗ್ರಹಿಸಬೇಕೆ"
#: ../data/org.gnome.shell.gschema.xml.in.h:24
msgid "disabled OpenSearch providers"
msgstr ""
msgstr "ಅಶಕ್ತಗೊಳಿಸಲಾದ OpenSearch ಒದಗಿಸುವವರು"
#: ../js/misc/util.js:86
msgid "Command not found"
msgstr ""
msgstr "ಆಜ್ಞೆಯು ಕಂಡು ಬಂದಿಲ್ಲ"
#. Replace "Error invoking GLib.shell_parse_argv: " with
#. something nicer
#: ../js/misc/util.js:113
msgid "Could not parse command:"
msgstr ""
msgstr "ಆಜ್ಞೆಯನ್ನು ಪಾರ್ಸ್ ಮಾಡಲಾಗಿಲ್ಲ:"
#: ../js/misc/util.js:135
msgid "No such application"
msgstr ""
msgstr "ಅಂತಹ ಯಾವುದೆ ಅನ್ವಯವಿಲ್ಲ"
#: ../js/misc/util.js:148
#, c-format
msgid "Execution of '%s' failed:"
msgstr ""
msgstr "'%s' ಅನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವಲ್ಲಿ ವಿಫಲಗೊಂಡಿದೆ:"
#. Translators: Filter to display all applications
#: ../js/ui/appDisplay.js:174
msgid "All"
msgstr ""
msgstr "ಎಲ್ಲಾ"
#: ../js/ui/appDisplay.js:261
msgid "APPLICATIONS"
msgstr ""
msgstr "APPLICATIONS"
#: ../js/ui/appDisplay.js:291
msgid "PREFERENCES"
@ -182,21 +194,21 @@ msgstr "ಹೊಸ ವಿಂಡೊ"
#: ../js/ui/appDisplay.js:555
msgid "Remove from Favorites"
msgstr ""
msgstr "ಎಲ್ಲಾ ಅಚ್ಚುಮೆಚ್ಚಿನವುಗಳನ್ನು ತೆಗೆದುಹಾಕು"
#: ../js/ui/appDisplay.js:556
msgid "Add to Favorites"
msgstr ""
msgstr "ಅಚ್ಚುಮೆಚ್ಚಿನವುಗಳಿಗೆ ಸೇರಿಸು"
#: ../js/ui/appFavorites.js:91
#, c-format
msgid "%s has been added to your favorites."
msgstr ""
msgstr "%s ಅನ್ನು ನಿಮ್ಮ ಅಚ್ಚುಮೆಚ್ಚಿನವುಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ."
#: ../js/ui/appFavorites.js:122
#, c-format
msgid "%s has been removed from your favorites."
msgstr ""
msgstr "%s ಅನ್ನು ನಿಮ್ಮ ಅಚ್ಚುಮೆಚ್ಚಿನವುಗಳಿಂದ ತೆಗೆದುಹಾಕಲಾಗಿದೆ."
#. Translators: Shown in calendar event list for all day events
#. * Keep it short, best if you can use less then 10 characters
@ -314,7 +326,7 @@ msgstr "ಶ"
#. Translators: Text to show if there are no events
#: ../js/ui/calendar.js:701
msgid "Nothing Scheduled"
msgstr ""
msgstr "ಯಾವುದೂ ಅನುಸೂಚಿತಗೊಂಡಿಲ್ಲ"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:717
@ -350,11 +362,11 @@ msgstr "ತೆಗೆದು ಹಾಕು"
#: ../js/ui/dateMenu.js:93
msgid "Date and Time Settings"
msgstr ""
msgstr "ದಿನಾಂಕ ಹಾಗು ಸಮಯದ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/dateMenu.js:112
msgid "Open Calendar"
msgstr ""
msgstr "ಕ್ಯಾಲೆಂಡರನ್ನು ತೆರೆ"
#. Translators: This is the time format with date used
#. in 24-hour mode.
@ -405,72 +417,76 @@ msgstr "%A %B %e, %Y"
#: ../js/ui/docDisplay.js:19
msgid "RECENT ITEMS"
msgstr ""
msgstr "RECENT ITEMS"
#: ../js/ui/endSessionDialog.js:63
#, c-format
msgid "Log Out %s"
msgstr ""
msgstr "%s ಇಂದ ನಿರ್ಗಮಿಸಿ"
#: ../js/ui/endSessionDialog.js:64 ../js/ui/endSessionDialog.js:69
msgid "Log Out"
msgstr ""
msgstr "ನಿರ್ಗಮಿಸಿ"
#: ../js/ui/endSessionDialog.js:65
msgid "Click Log Out to quit these applications and log out of the system."
msgstr ""
"ಈ ಅನ್ವಯದಿಂದ ನಿರ್ಗಮಿಸಿ ನಂತರ ವ್ಯವಸ್ಥೆಯಿಂದ ನಿರ್ಗಮಿಸಲು ನಿರ್ಗಮಿಸು ಅನ್ನು ಒತ್ತಿ."
#: ../js/ui/endSessionDialog.js:66
#, c-format
msgid "%s will be logged out automatically in %d seconds."
msgstr ""
msgstr "%s ರವರು %d ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನಿರ್ಗಮಿಸಲ್ಪಡುತ್ತಾರೆ."
#: ../js/ui/endSessionDialog.js:67
#, c-format
msgid "You will be logged out automatically in %d seconds."
msgstr ""
msgstr "ನೀವು %d ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನಿರ್ಗಮಿಸಲ್ಪಡುತ್ತಾರೆ."
#: ../js/ui/endSessionDialog.js:68
msgid "Logging out of the system."
msgstr ""
msgstr "ವ್ಯವಸ್ಥೆಯಿಂದ ನಿರ್ಗಮಿಸಲಾಗುತ್ತಿದೆ."
#: ../js/ui/endSessionDialog.js:74 ../js/ui/endSessionDialog.js:78
msgid "Shut Down"
msgstr ""
msgstr "ಸ್ಥಗಿತಗೊಳಿಸು"
#: ../js/ui/endSessionDialog.js:75
msgid "Click Shut Down to quit these applications and shut down the system."
msgstr ""
"ಈ ಅನ್ವಯದಿಂದ ನಿರ್ಗಮಿಸಿ ನಂತರ ವ್ಯವಸ್ಥೆಯನ್ನು ಸ್ಥಗಿತಗೊಳಿಲು ಸ್ಥಗಿತಗೊಳಿಸು ಅನ್ನು "
"ಒತ್ತಿ."
#: ../js/ui/endSessionDialog.js:76
#, c-format
msgid "The system will shut down automatically in %d seconds."
msgstr ""
msgstr "ವ್ಯವಸ್ಥೆಯು %d ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸ್ಥಗಿತಗೊಳ್ಳುತ್ತದೆ."
#: ../js/ui/endSessionDialog.js:77
msgid "Shutting down the system."
msgstr ""
msgstr "ವ್ಯವಸ್ಥೆಯನ್ನು ಸ್ಥಗಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ."
#: ../js/ui/endSessionDialog.js:84 ../js/ui/endSessionDialog.js:88
msgid "Restart"
msgstr ""
msgstr "ಮರಳಿ ಆರಂಭಿಸು"
#: ../js/ui/endSessionDialog.js:85
msgid "Click Restart to quit these applications and restart the system."
msgstr ""
"ಈ ಅನ್ವಯದಿಂದ ನಿರ್ಗಮಿಸಿ ಗಣಕವನ್ನು ಮರಳಿ ಅರಂಭಿಸಲು ಮರಳಿ ಆರಂಭಿಸು ಅನ್ನು ಕ್ಲಿಕ್ ಮಾಡಿ."
#: ../js/ui/endSessionDialog.js:86
#, c-format
msgid "The system will restart automatically in %d seconds."
msgstr ""
msgstr "ವ್ಯವಸ್ಥೆಯು %d ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಮರಳಿ ಆರಂಭಗೊಳ್ಳುತ್ತದೆ."
#: ../js/ui/endSessionDialog.js:87
msgid "Restarting the system."
msgstr ""
msgstr "ನಿಮ್ಮ ವ್ಯವಸ್ಥೆಯನ್ನು ಮರಳಿ ಆರಂಭಿಸಲಾಗುತ್ತಿದೆ."
#: ../js/ui/endSessionDialog.js:395
msgid "Confirm"
msgstr ""
msgstr "ಖಚಿತಪಡಿಸಿ"
#: ../js/ui/endSessionDialog.js:400 ../js/ui/status/bluetooth.js:470
msgid "Cancel"
@ -478,17 +494,17 @@ msgstr "ರದ್ದು ಮಾಡು"
#: ../js/ui/lookingGlass.js:587
msgid "No extensions installed"
msgstr ""
msgstr "ಯಾವುದು ವಿಸ್ತರಣೆಗಳನ್ನು ಅನುಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"
#: ../js/ui/lookingGlass.js:624
msgid "Enabled"
msgstr ""
msgstr "ಶಕ್ತಗೊಳಿಸಲಾಗಿದೆ"
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:626 ../src/gvc/gvc-mixer-control.c:1087
msgid "Disabled"
msgstr ""
msgstr "ಅಶಕ್ತಗೊಳಿಸಲಾಗಿದೆ"
#: ../js/ui/lookingGlass.js:628
msgid "Error"
@ -496,11 +512,11 @@ msgstr "ದೋಷ"
#: ../js/ui/lookingGlass.js:630
msgid "Out of date"
msgstr ""
msgstr "ಹಳೆಯದಾಗಿದೆ"
#: ../js/ui/lookingGlass.js:655
msgid "View Source"
msgstr ""
msgstr "ಆಕರವನ್ನು ನೋಡಿ"
#: ../js/ui/lookingGlass.js:661
msgid "Web Page"
@ -526,26 +542,26 @@ msgstr "ಅನ್ವಯಗಳು"
#: ../js/ui/panel.js:478
#, c-format
msgid "Quit %s"
msgstr ""
msgstr "%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:612
msgid "Activities"
msgstr ""
msgstr "ಚಟುವಟಿಕೆಗಳು"
#: ../js/ui/placeDisplay.js:122
#, c-format
msgid "Failed to unmount '%s'"
msgstr ""
msgstr "'%s' ಅನ್ನು ಅವರೋಹಿಸಲು ಸಾಧ್ಯವಾಗಿಲ್ಲ"
#: ../js/ui/placeDisplay.js:125
msgid "Retry"
msgstr ""
msgstr "ಮರಳಿ ಆರಂಭಿಸು"
#: ../js/ui/placeDisplay.js:165
msgid "Connect to..."
msgstr ""
msgstr "ಇದಕ್ಕೆ ಸಂಪರ್ಕ ಜೋಡಿಸಿ..."
#: ../js/ui/placeDisplay.js:409
msgid "PLACES & DEVICES"
@ -558,7 +574,7 @@ msgstr "PLACES & DEVICES"
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:506
msgid "toggle-switch-us"
msgstr ""
msgstr "toggle-switch-us"
#: ../js/ui/runDialog.js:201
msgid "Please enter a command:"
@ -570,7 +586,7 @@ msgstr "ಹುಡುಕಲಾಗುತ್ತಿದೆ..."
#: ../js/ui/searchDisplay.js:309
msgid "No matching results."
msgstr ""
msgstr "ಯಾವುದೆ ಫಲಿತಾಂಶಗಳು ತಾಳೆಯಾಗಿಲ್ಲ."
#: ../js/ui/statusMenu.js:102
msgid "Available"
@ -590,7 +606,7 @@ msgstr "ವ್ಯವಸ್ಥೆಯ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/statusMenu.js:126
msgid "Lock Screen"
msgstr ""
msgstr "ತೆರೆಯನ್ನು ಲಾಕ್ ಮಾಡಿ"
#: ../js/ui/statusMenu.js:130
msgid "Switch User"
@ -598,7 +614,7 @@ msgstr "ಬಳಕೆದಾರನನ್ನು ಬದಲಿಸು"
#: ../js/ui/statusMenu.js:135
msgid "Log Out..."
msgstr ""
msgstr "ನಿರ್ಗಮಿಸಿ..."
#. This is temporarily removed, see
#. http://bugzilla.gnome.org/show_bug.cgi?id=636680
@ -608,51 +624,51 @@ msgstr ""
#. this.menu.addMenuItem(item);
#: ../js/ui/statusMenu.js:149
msgid "Shut Down..."
msgstr ""
msgstr "ಸ್ಥಗಿತಗೊಳಿಸಿ..."
#: ../js/ui/status/accessibility.js:81
msgid "Zoom"
msgstr ""
msgstr "ಗಾತ್ರ ಬದಲಾವಣೆ"
#: ../js/ui/status/accessibility.js:88
msgid "Screen Reader"
msgstr ""
msgstr "ತೆರೆ ಓದುಗ"
#: ../js/ui/status/accessibility.js:92
msgid "Screen Keyboard"
msgstr ""
msgstr "ತೆರೆ ಕೀಲಿಮಣೆ"
#: ../js/ui/status/accessibility.js:96
msgid "Visual Alerts"
msgstr ""
msgstr "ದೃಶ್ಯರೂಪದ ಎಚ್ಚರಿಕೆಗಳು"
#: ../js/ui/status/accessibility.js:99
msgid "Sticky Keys"
msgstr ""
msgstr "ಸ್ಟಿಕಿ ಕೀಲಿಗಳು"
#: ../js/ui/status/accessibility.js:102
msgid "Slow Keys"
msgstr ""
msgstr "ನಿಧಾನ ಕೀಲಿಗಳು"
#: ../js/ui/status/accessibility.js:105
msgid "Bounce Keys"
msgstr ""
msgstr "ಪುಟಿಯುವ ಕೀಲಿಗಳು"
#: ../js/ui/status/accessibility.js:108
msgid "Mouse Keys"
msgstr ""
msgstr "ಮೌಸ್‌ ಕೀಲಿಗಳು"
#: ../js/ui/status/accessibility.js:112
msgid "Universal Access Settings"
msgstr ""
msgstr "ಜಾಗತಿಕ ನಿಲುಕಣೆ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/status/accessibility.js:164
msgid "High Contrast"
msgstr ""
msgstr "ಅತಿ ಹೆಚ್ಚು ವೈದೃಶ್ಯ"
#: ../js/ui/status/accessibility.js:206
msgid "Large Text"
msgstr ""
msgstr "ದೊಡ್ಡ ಪಠ್ಯ"
#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:241
#: ../js/ui/status/bluetooth.js:337 ../js/ui/status/bluetooth.js:371
@ -666,11 +682,11 @@ msgstr "ಗೋಚರಿಕೆ"
#: ../js/ui/status/bluetooth.js:69
msgid "Send Files to Device..."
msgstr ""
msgstr "ಸಾಧನಕ್ಕೆ ಕಡತಗಳನ್ನು ಕಳುಹಿಸಿ..."
#: ../js/ui/status/bluetooth.js:70
msgid "Setup a New Device..."
msgstr ""
msgstr "ಒಂದು ಹೊಸ ಸಾಧನವನ್ನು ಸಿದ್ಧಗೊಳಿಸಿ..."
#: ../js/ui/status/bluetooth.js:95
msgid "Bluetooth Settings"
@ -690,12 +706,12 @@ msgstr "ಕಡತಗಳಿಗಾಗಿ ವೀಕ್ಷಿಸು..."
#: ../js/ui/status/bluetooth.js:242
msgid "Error browsing device"
msgstr ""
msgstr "ಸಾಧನವನ್ನು ವೀಕ್ಷಿಸುವಲ್ಲಿ ದೋಷ"
#: ../js/ui/status/bluetooth.js:243
#, c-format
msgid "The requested device cannot be browsed, error is '%s'"
msgstr ""
msgstr "ಮನವಿ ಸಲ್ಲಿಸಲಾದ ಸಾಧನವನ್ನು ವೀಕ್ಷಿಸಲು ಸಾಧ್ಯವಾಗಿಲ್ಲ, ದೋಷವು '%s' ಆಗಿದೆ"
#: ../js/ui/status/bluetooth.js:251
msgid "Keyboard Settings"
@ -712,20 +728,20 @@ msgstr "ಧ್ವನಿಯ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/status/bluetooth.js:372
#, c-format
msgid "Authorization request from %s"
msgstr ""
msgstr "%s ಇಂದ ದೃಢೀಕರಣ ದೋಷ"
#: ../js/ui/status/bluetooth.js:378
#, c-format
msgid "Device %s wants access to the service '%s'"
msgstr ""
msgstr "%s ಎಂಬ ಸಾಧನಕ್ಕಾಗಿ '%s' ಎಂಬ ಸೇವೆಯನ್ನು ನಿಲುಕಿಸಿಕೊಳ್ಳಲು ಬಯಸುತ್ತಿದೆ"
#: ../js/ui/status/bluetooth.js:380
msgid "Always grant access"
msgstr ""
msgstr "ಯಾವಾಗಲೂ ಅನುಮತಿಸು"
#: ../js/ui/status/bluetooth.js:381
msgid "Grant this time only"
msgstr ""
msgstr "ಈ ಬಾರಿ ಮಾತ್ರ ಅನುಮತಿಸು"
#: ../js/ui/status/bluetooth.js:382
msgid "Reject"
@ -734,17 +750,17 @@ msgstr "ತಿರಸ್ಕರಿಸು"
#: ../js/ui/status/bluetooth.js:412
#, c-format
msgid "Pairing confirmation for %s"
msgstr ""
msgstr "%s ಗಾಗಿ ಪೇರಿಂಗ್ ಖಚಿತಪಡಿಕೆ"
#: ../js/ui/status/bluetooth.js:418 ../js/ui/status/bluetooth.js:452
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr ""
msgstr "%s ಎನ್ನುವ ಸಾಧನದೊಂದಿಗೆ ಸಂಪರ್ಕ ಜೋಡಿಸಲು ಬಯಸುತ್ತಿದೆ"
#: ../js/ui/status/bluetooth.js:419
#, c-format
msgid "Please confirm whether the PIN '%s' matches the one on the device."
msgstr ""
msgstr "'%s' ಎನ್ನುವ PIN ಸಾಧನದಲ್ಲಿರುವುದಕ್ಕೆ ತಾಳೆಯಾಗುತ್ತದೆಯೆ ಎಂದು ಖಚಿತಪಡಿಸಿ."
#: ../js/ui/status/bluetooth.js:421
msgid "Matches"
@ -757,11 +773,11 @@ msgstr "ತಾಳೆಯಾಗುತ್ತಿಲ್ಲ"
#: ../js/ui/status/bluetooth.js:445
#, c-format
msgid "Pairing request for %s"
msgstr ""
msgstr "%s ಗಾಗಿ ಪೇರಿಂಗ್ ಮನವಿ"
#: ../js/ui/status/bluetooth.js:453
msgid "Please enter the PIN mentioned on the device."
msgstr ""
msgstr "ದಯವಿಟ್ಟು ಸಾಧನದಲ್ಲಿ ಸೂಚಿಸಿರುವ PIN ಅನ್ನು ನಮೂದಿಸಿ."
#: ../js/ui/status/bluetooth.js:469
msgid "OK"
@ -769,51 +785,51 @@ msgstr "ಸರಿ"
#: ../js/ui/status/keyboard.js:72
msgid "Localization Settings"
msgstr ""
msgstr "ಲೋಕಲೈಸೇಶನ್ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/status/power.js:85
msgid "Power Settings"
msgstr ""
msgstr "ವಿದ್ಯುಚ್ಛಕ್ತಿ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/status/power.js:112
#, c-format
msgid "%d hour remaining"
msgid_plural "%d hours remaining"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d ಗಂಟೆ ಬಾಕಿ ಇದೆ"
msgstr[1] "%d ಗಂಟೆಗಳು ಬಾಕಿ ಇವೆ"
#. TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining"
#: ../js/ui/status/power.js:115
#, c-format
msgid "%d %s %d %s remaining"
msgstr ""
msgstr "%d %s %d %s ಬಾಕಿ ಇದೆ"
#: ../js/ui/status/power.js:117
msgid "hour"
msgid_plural "hours"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "ಗಂಟೆ"
msgstr[1] "ಗಂಟೆಗಳು"
#: ../js/ui/status/power.js:117
msgid "minute"
msgid_plural "minutes"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "ನಿಮಿಷ"
msgstr[1] "ನಿಮಿಷಗಳು"
#: ../js/ui/status/power.js:120
#, c-format
msgid "%d minute remaining"
msgid_plural "%d minutes remaining"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d ನಿಮಿಷ ಬಾಕಿ ಇದೆ"
msgstr[1] "%d ನಿಮಿಷಗಳು ಬಾಕಿ ಇವೆ"
#: ../js/ui/status/power.js:235
msgid "AC adapter"
msgstr ""
msgstr "AC ಅಡಾಪ್ಟರ್"
#: ../js/ui/status/power.js:237
msgid "Laptop battery"
msgstr ""
msgstr "ಲ್ಯಾಪ್‌ಟಾಪ್ ಬ್ಯಾಟರಿ"
#: ../js/ui/status/power.js:239
msgid "UPS"
@ -821,15 +837,15 @@ msgstr "UPS"
#: ../js/ui/status/power.js:241
msgid "Monitor"
msgstr ""
msgstr "ತೆರೆ"
#: ../js/ui/status/power.js:243
msgid "Mouse"
msgstr ""
msgstr "ಮೌಸ್"
#: ../js/ui/status/power.js:245
msgid "Keyboard"
msgstr ""
msgstr "ಕೀಲಿಮಣೆ"
#: ../js/ui/status/power.js:247
msgid "PDA"
@ -837,51 +853,51 @@ msgstr "PDA"
#: ../js/ui/status/power.js:249
msgid "Cell phone"
msgstr ""
msgstr "ಸೆಲ್ ಫೋನ್"
#: ../js/ui/status/power.js:251
msgid "Media player"
msgstr ""
msgstr "ಮೀಡಿಯ ಪ್ಲೇಯರ್"
#: ../js/ui/status/power.js:253
msgid "Tablet"
msgstr ""
msgstr "ಟ್ಯಾಬ್ಲೆಟ್"
#: ../js/ui/status/power.js:255
msgid "Computer"
msgstr ""
msgstr "ಗಣಕ"
#: ../js/ui/status/power.js:257 ../src/shell-app-system.c:1013
msgid "Unknown"
msgstr ""
msgstr "ಗೊತ್ತಿರದ"
#: ../js/ui/status/volume.js:44
msgid "Volume"
msgstr ""
msgstr "ಧ್ವನಿ ಪ್ರಮಾಣ"
#: ../js/ui/status/volume.js:57
msgid "Microphone"
msgstr ""
msgstr "ಮೈಕ್ರೊಫೋನ್"
#: ../js/ui/telepathyClient.js:240
#, c-format
msgid "%s is online."
msgstr ""
msgstr "%s ಆನ್‌ಲೈನ್‌ನಲ್ಲಿದ್ದಾರೆ."
#: ../js/ui/telepathyClient.js:245
#, c-format
msgid "%s is offline."
msgstr ""
msgstr "%s ಆಫ್‌ಲೈನ್‌ನಲ್ಲಿದ್ದಾರೆ."
#: ../js/ui/telepathyClient.js:248
#, c-format
msgid "%s is away."
msgstr ""
msgstr "%s ಆಚೆ ಹೋಗಿದ್ದಾರೆ."
#: ../js/ui/telepathyClient.js:251
#, c-format
msgid "%s is busy."
msgstr ""
msgstr "%s\" ಕಾರ್ಯನಿರತವಾಗಿದ್ದಾರೆ."
#. Translators: this is a time format string followed by a date.
#. If applicable, replace %X with a strftime format valid for your
@ -889,7 +905,7 @@ msgstr ""
#: ../js/ui/telepathyClient.js:349
#, no-c-format
msgid "Sent at %X on %A"
msgstr ""
msgstr "%X ಕ್ಕೆ %A ರಂದು ಕಳುಹಿಸಲಾಗಿದೆ"
#. Translators: this is the text displayed
#. in the search entry when no search is
@ -897,17 +913,17 @@ msgstr ""
#. characters
#: ../js/ui/viewSelector.js:30
msgid "Type to search..."
msgstr ""
msgstr "ಹುಡುಕಲು ನಮೂದಿಸು..."
#: ../js/ui/windowAttentionHandler.js:43
#, c-format
msgid "%s has finished starting"
msgstr ""
msgstr "ಆರಂಭಗೊಳಿಸುವುದನ್ನು %s ಪೂರ್ಣಗೊಳಿಸಿದ್ದಾರೆ"
#: ../js/ui/windowAttentionHandler.js:45
#, c-format
msgid "'%s' is ready"
msgstr ""
msgstr "'%s' ಸಿದ್ಧಗೊಂಡಿದೆ"
#. translators:
#. * The number of sound outputs on a particular device
@ -915,8 +931,8 @@ msgstr ""
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%u ಔಟ್‌ಪುಟ್"
msgstr[1] "%u ಔಟ್‌ಪುಟ್‌ಗಳು"
#. translators:
#. * The number of sound inputs on a particular device
@ -924,58 +940,58 @@ msgstr[1] ""
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%u ಇನ್‌ಪುಟ್"
msgstr[1] "%u ಇನ್‌ಪುಟ್‌ಗಳು"
#: ../src/gvc/gvc-mixer-control.c:1402
msgid "System Sounds"
msgstr ""
msgstr "ವ್ಯವಸ್ಥೆಯ ಧ್ವನಿಗಳು"
#: ../src/shell-global.c:1363
msgid "Less than a minute ago"
msgstr ""
msgstr "ಒಂದು ನಿಮಿಷಕ್ಕೂ ಹಿಂದೆ"
#: ../src/shell-global.c:1367
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d ನಿಮಿಷದ ಹಿಂದೆ"
msgstr[1] "%d ನಿಮಿಷಗಳ ಹಿಂದೆ"
#: ../src/shell-global.c:1372
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d ಗಂಟೆಯ ಹಿಂದೆ"
msgstr[1] "%d ಗಂಟೆಗಳ ಹಿಂದೆ"
#: ../src/shell-global.c:1377
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d ದಿನದ ಹಿಂದೆ"
msgstr[1] "%d ದಿನಗಳ ಹಿಂದೆ"
#: ../src/shell-global.c:1382
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d ವಾರದ ಹಿಂದೆ"
msgstr[1] "%d ವಾರಗಳ ಹಿಂದೆ"
#: ../src/shell-util.c:89
msgid "Home Folder"
msgstr ""
msgstr "ನೆಲೆ ಕಡತಕೋಶ"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-util.c:104
msgid "File System"
msgstr ""
msgstr "ಕಡತ ವ್ಯವಸ್ಥೆ"
#: ../src/shell-util.c:250
msgid "Search"
msgstr ""
msgstr "ಹುಡುಕು"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
@ -987,3 +1003,4 @@ msgstr ""
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

684
po/ko.po

File diff suppressed because it is too large Load Diff

1289
po/lt.po

File diff suppressed because it is too large Load Diff

1244
po/lv.po Normal file

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