Compare commits

...

1073 Commits

Author SHA1 Message Date
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
cd2c0565ad Bump version to 2.91.90 2011-02-22 22:48:38 -05:00
43469de2fe Require Mutter 2.91.90
2.91.90 is needed for MetaWindowActor ::position-changed signal
2011-02-22 22:48:38 -05:00
d1eb2b2b02 Update calendar font style
Now that we are using Cantarell as the default UI font, some clarity
was reduced in using the calendar. Mockups already address this so
change the font styles in CSS to match the mockups.

https://bugzilla.gnome.org/show_bug.cgi?id=642194
2011-02-22 20:34:16 -05:00
682b7ea0b5 gnome-shell.modules: fix dependencies for upower
We don't build dbus-glib so don't make upower depend on that, and
make gnome-shell depend on upower.
2011-02-22 20:12:10 -05:00
e4d9b11685 build: Add libusb dependency
UPower requires libusb-1.0.
2011-02-23 01:58:35 +01:00
89cbb9766b gnome-shell.modules: build upower with introspection
The whole point of building upower is to get the introspection
support, so remove --enable-introspection=no from the autogenargs.
2011-02-22 19:51:43 -05:00
ca4b385916 Remove minimize and maximize buttons from title bar
The minimize and maximize buttons on the titlebar have lost much of their
utility in GNOME 3: the minimize functionality is largely superceded by
the ability to switch windows in the overview and conveniently use
multiple workspaces, while the maximize functionality is available by
drag to the top gesture or double clicking on the title bar.

Removing these buttons significantly cleans up the default appearance
and avoids exposing a half-done implementation of minimization.

http://mail.gnome.org/archives/gnome-shell-list/2011-February/msg00192.html
https://bugzilla.gnome.org/show_bug.cgi?id=604237
2011-02-22 19:37:52 -05:00
26f4e44d6c statusMenu: change how we stop the system
This updates the way we stop the system to
somewhat match the designs here:

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

We suspend by default unless suspend is unavailable, and offer shutdown
as a choice by hold down the alt key.

https://bugzilla.gnome.org/show_bug.cgi?id=636680
2011-02-22 18:46:57 -05:00
610c2b5987 popupMenu: add alternate menu item
This is special menu item that can alternate
between two choices when you hit the alt key.

It will be useful for getting a hybrid
suspend/power off menu item.

https://bugzilla.gnome.org/show_bug.cgi?id=636680
2011-02-22 18:46:57 -05:00
3c66455112 build: Add upower as dependency in moduleset
Now that we use it to suspend, we need to pull it
in during the build process.

https://bugzilla.gnome.org/show_bug.cgi?id=636680
2011-02-22 18:46:57 -05:00
867c9a19ae panel: Defer adding the user status menu to the manager
PopupMenuManager relies on menus being added in the order of the
menu buttons they are attached to, so defer adding the user status
menu until the status icon menus have been added to make the manager
happy.
2011-02-23 00:07:40 +01:00
1496c85bb6 MessageTray: Use status from gnome-session
This patch modifies MessageTray behaviour so that normal (not urgent)
notifications are not shown when the user is Busy (they're sent
immediately to the Summary area). When status is then changed,
notifications still pending are shown again.
Additionally, when status is modified from Idle to anything other than
Busy, the message tray is forced open for 4 seconds, so that summary
icons are visible.

https://bugzilla.gnome.org/show_bug.cgi?id=617225
2011-02-22 23:14:55 +01:00
998ef7d861 build: Bump polkit module
GNOME Shell requires polkit-0.100.
2011-02-22 22:36:08 +01:00
86b925a294 Add a PolicyKit authentication agent
A PolicyKit Authentication Agent is a construct used to authenticate
one or more identities. See the PolicyKit documentation for more
details on authentication agents and how PolicyKit works:

    http://hal.freedesktop.org/docs/polkit/

Since gjs does not support subclassing a GObject class from Javascript
code, we bring in a native class to bridge the VFuncs to GObject
signals. Additionally, this native class also queues up authentication
requests so the user of the native class only has to deal with a
single outstanding request at any one time.

The file js/ui/polkitAuthenticationAgent.js introduces a singleton
that listens for authentication requests via the native class. This
singleton uses the PolkitAgent machinery to do the actual heavy-weight
lifting required for authentication (essentially a PAM conversation).

We currently don't allow the user to pick the identity to be
authenticated.

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

Signed-off-by: David Zeuthen <davidz@redhat.com>
2011-02-22 15:13:56 -05:00
1fcfadd53c Updated Spanish translation 2011-02-22 20:48:39 +01:00
192d3a94ed tweener: remove tweens when target.actor is destroyed
We already remove tweens automatically when a Clutter actor is destroyed;
do the same when the target is a JS delegate with an actor property.

https://bugzilla.gnome.org/show_bug.cgi?id=642925
2011-02-22 12:36:25 -05:00
5683bb9b8e ShellWindowTracker: fix a reference counting bug
When retrieving a ShellApp from the GHashTable of child processes,
we need to take an extra reference, that the GHashTable of windows
to apps will own.
Also add some documentation to avoid repeating this bug in the future.

https://bugzilla.gnome.org/show_bug.cgi?id=642699
2011-02-22 16:34:08 +01:00
1cf4cb3de5 Updated Hebrew translation. 2011-02-22 08:14:33 +02:00
d1548aeee1 search-entry: Make the icon slightly smaller
Set the icon size in the search entry to 1em on designers' request.
2011-02-22 00:06:39 +01:00
fb800f3d8b panel: Fix corner positions for multi-monitors
The corner positions were only based on the panel's dimensions, its
position needs to be taken into account as well.
2011-02-21 23:59:48 +01:00
21cc6a07f5 Updated Italian translation 2011-02-21 22:52:05 +01:00
8a22ea948f shell_global: Use clutter_event_get_time rather then get_current_event_time
Using clutter_get_current_event_time can result into too old timestamps
when there is no current Clutter or Mutter event, since
clutter_get_current_event_time() returns the timestamp of the last event
delivered to Clutter. This can result in, for example, grabs failing. Use
the event time of the current event (if any) and CurrentTime otherwise.

https://bugzilla.gnome.org/show_bug.cgi?id=642188
2011-02-21 22:44:39 +01:00
b5cea80b54 Updated Arabic translation 2011-02-21 23:40:07 +02:00
5fc4d1751c Adjust padding of sources in summary
Make the right padding bigger and the left padding smaller, so that the
boundaries that trigger the accordion effect are more closely associated
with corresponding icons. Also slightly decrease the overall padding between
sources.
2011-02-21 16:29:54 -05:00
75dbe4fdb9 workspaces: Remove the unused '_removeSelf' method
https://bugzilla.gnome.org/show_bug.cgi?id=640363
2011-02-21 21:31:07 +01:00
c692fa4687 StWidget: unset hover when unmapped
This ensures that the hover property doesn't return true after
the widget is unmapped while being hovered over.

https://bugzilla.gnome.org/show_bug.cgi?id=642726
2011-02-21 13:59:18 -05:00
f34ce9271c PopupMenu: introduce PopupMenuSection
Complex popup menus require the ability to manager sequences of items
as "sections", to which you can add and and remove items, as well
as hide and show.
PopupMenuSection does exactly that, leveraging the existing machinery
for submenus, but without being exposed as a submenu to the user.
Also, make getMenuItems() private, since it is used for different things
now and may change semantics in the future.

https://bugzilla.gnome.org/show_bug.cgi?id=621707
2011-02-21 19:54:10 +01:00
6e236546ea PopupMenu: make parameters overridable in items
Make all subclasses of PopupMenuBase accept a params argument, which
can be used to make the item non reactive, not responsive to hover
and, as a new feature, with a different style class.

https://bugzilla.gnome.org/show_bug.cgi?id=621707
2011-02-21 19:54:10 +01:00
3fd908d92c workspaces: Remove obsolete comment
https://bugzilla.gnome.org/show_bug.cgi?id=640361
2011-02-21 19:23:34 +01:00
a4d3a57a1c A11yStatus: fix resetting the GTK and icon themes
If the Shell is started with HighContrast enabled, it will never
see another value for the GSettings keys. In that case, we just
reset to the default.

https://bugzilla.gnome.org/show_bug.cgi?id=642641
2011-02-21 18:50:35 +01:00
0064ca3582 KeyboardStatus: add "Show layout" item
Add a menu item that opens a dialog showing the current keyboard
layout. Uses the new utility in libgnomekbd.

https://bugzilla.gnome.org/show_bug.cgi?id=641415
2011-02-21 18:49:19 +01:00
9c4cee7875 overview: avoid round-off errors when sizing and positioning view selector
We need the view selector to extend all the way to the right edge of the
monitor, so size and position the view selector in a way that the sum of
its X position and its width add up to the primary monitor width.

https://bugzilla.gnome.org/show_bug.cgi?id=642834
2011-02-21 12:20:38 -05:00
4a21dc954a calendar: Update style
The style used to highlight today's date should follow the style
of active panel buttons, so update it to reflect the new panel
style.

https://bugzilla.gnome.org/show_bug.cgi?id=642697
2011-02-21 17:38:48 +01:00
526384320e panel-buttons: Remove transitions for corner buttons
So far transitions do not work for the custom drawn corners, so to
avoid a visible glitch when transitioning a button in the panel corner
while updating the style of the apparently attached corner instantly,
remove transition of those panel buttons until we make it work for the
custom drawn parts as well.

https://bugzilla.gnome.org/show_bug.cgi?id=642697
2011-02-21 17:38:47 +01:00
977f45cdb9 panel: Add rounded corners
Current mockups show the panel curving downwards at the edges to
frame the work area and look awesome. Implement those as separate
actors to not affect the struts set by the panel, and synchronize
their state with the corresponding panel buttons so they blend in
with the panel. It might be worth considering whether the corners
should be hidden with maximized windows on the current workspace,
though this might affect the illusion of them being part of the
panel. As the corners don't affect the input region, the small
overlap with windows might not be too bad after all.

https://bugzilla.gnome.org/show_bug.cgi?id=642697
2011-02-21 17:38:47 +01:00
0a94c01f83 panel: Adjust CSS for RTL locales
The groups at the panel sides use different left/right padding, so
a slightly different CSS is required for RTL locales. Add :rtl
pseudo classes as necessary and adjust the CSS.

https://bugzilla.gnome.org/show_bug.cgi?id=642697
2011-02-21 17:38:47 +01:00
473dad0c3e appMenu: Clip app icon when the button is active
We now use a border image on active panel buttons to underline the
button's content. As the property does not affect the content's
allocation, the app icon ends up being drawn on top of the border
image. To prevent this, use a custom property to clip the bottom of
the app icon when the button is active.

https://bugzilla.gnome.org/show_bug.cgi?id=642697
2011-02-21 17:38:47 +01:00
a5aa7d4bd6 panel: Update style
Update the style of the panel to match the latest mockups.

 - add a subtle border at the bottom of the panel
 - use a highlight of active panel buttons similar to the one
   used for running applications in the dash/app view
 - shadow the buttons' label/icon when highlighted

https://bugzilla.gnome.org/show_bug.cgi?id=642697
2011-02-21 17:38:47 +01:00
4dec1bc846 panel: Move statusmenu initialization in the constructor
While related to the status area, the user status button is clearly
not a status icon, and it does not make too much sense in
startStatusArea(), which is about filling the status area with
icons. Also, the status icon container is added to the panel in
the constructor, in fact, the user status button is the only "toplevel"
panel element which is initialized elsewhere. Not a crucial change,
but makes for a nice read anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=642697
2011-02-21 17:38:47 +01:00
9925264410 search-entry: Update style
Update the style of the search entry to match the latest mockups[0].

 - use a (non-reactive) loupe icon when no search is active
 - use themed symbolic icons
 - make the entry rounder
 - tweak gradient colors
 - use an inset shadow

[0] http://git.gnome.org/browse/gnome-shell-design/plain/mockups/static/searchbox.png

https://bugzilla.gnome.org/show_bug.cgi?id=642335
2011-02-21 17:38:47 +01:00
51bfbca2f1 tests: Add a box-shadow test
The original support for CSS based shadows has been extended with
support for an optional spread radius and the 'inset' keyword,
so with the additional complexity a dedicated test case looks
appropriate.

https://bugzilla.gnome.org/show_bug.cgi?id=642334
2011-02-21 17:38:47 +01:00
a3a6650e66 st-theme-node: Add support for inset box-shadows
Implement inset box-shadows as in the CSS3 draft[0]. As the shadow
should appear beneath the node's border, we pick the slow cairo based
rendering path (though a cogl based path could be added in case the
node has a solid background with no borders).

[0] http://www.w3.org/TR/css3-background/#box-shadow

https://bugzilla.gnome.org/show_bug.cgi?id=642334
2011-02-21 17:38:33 +01:00
2b90be77b3 st-shadow: Parse the 'inset' keyword
The box-shadow property in the CSS3 draft[0] supports the optional
'inset' keyword for inner shadows cast onto the background. Add
support for the keyword to the shadow parsing code.

[0] http://www.w3.org/TR/css3-background/#box-shadow

https://bugzilla.gnome.org/show_bug.cgi?id=642334
2011-02-21 17:35:23 +01:00
794c986b10 theme-node-drawing: Rename render_background_with_border()
As more cases are added where we pick the slower cairo based
fallback path, use a more generic name.

https://bugzilla.gnome.org/show_bug.cgi?id=642334
2011-02-21 17:35:23 +01:00
bffe796413 st-entry: Add API to set an actor as primary/secondary icon
Currently an entry's primary/secondary icon can only be set by
filename. In order to allow using themed icons, add API to set
a generic ClutterActor as icon.

https://bugzilla.gnome.org/show_bug.cgi?id=642333
2011-02-21 17:35:23 +01:00
6b4c497800 Increase padding of sources in summary
Makes it feel less cramped and makes the targets larger and
easier to use.
2011-02-21 10:28:55 -05:00
063038bc41 Updated Hebrew translation. 2011-02-21 09:26:42 +02:00
932a95fa25 updated kn translations 2011-02-21 12:53:13 +05:30
9ce439e406 Added kn.po and updated LINGUAS file 2011-02-21 12:44:44 +05:30
ca2bffcdb0 Update Czech translation 2011-02-21 02:20:45 +01:00
01097ac954 Fix cursor when dragging a window over its current workspace
When we are dragging a window over its current workspace or workspace
thumbnail, we show show "no drop possible" feedback instead
of "move here" feedback.

https://bugzilla.gnome.org/show_bug.cgi?id=642329
2011-02-20 12:38:10 -05:00
45fe44da85 workspaceThumbnail: forbid manipulations of removed workspaces
Don't allow dragging onto a removed workspace or activating it.

https://bugzilla.gnome.org/show_bug.cgi?id=642329
2011-02-20 12:38:10 -05:00
89cc6807e0 workspaceThumbnail: fix stacking for newly added actors
We don't necessarily get a syncStacking call when an actor is added
at the top of the workspace, so make sure to set the stackAbove value
for it correctly.

https://bugzilla.gnome.org/show_bug.cgi?id=642329
2011-02-20 12:38:10 -05:00
9af03194b9 Updated Spanish translation 2011-02-20 15:18:14 +01:00
3056c772c2 Updated Norwegian bokmål translation. 2011-02-20 12:24:21 +01:00
136ed3623b search-entry: Update hint text
'Search your computer' is problematic for various reasons:
 - it specifies the kind of device
 - it focuses on local search (while we also do web search)
 - it does not advertise the instant search functionality

Change the hint text to 'Type to search' as proposed by Allan Day.

https://bugzilla.gnome.org/show_bug.cgi?id=642287
2011-02-20 00:36:56 +01:00
4bedbca66f lookingGlass: use new history manager implementation
This starts saving lookingGlass history in gsettings, and also adds
the ability to clear the text field by pressing 'down' on the last
entry, like the run dialog and readline allow.

https://bugzilla.gnome.org/show_bug.cgi?id=642237
2011-02-19 13:28:17 -05:00
30da70a09e runDialog: use new history manager implementation
https://bugzilla.gnome.org/show_bug.cgi?id=642237
2011-02-19 13:28:16 -05:00
cf3c631cde Add a history manager
runDialog and lookingGlass both implement a home-made history
manager, each working slightly differently than each other in
behavior and implementation.

Extract the behavior and implementation from runDialog, which
reads and saves to GSettings.

https://bugzilla.gnome.org/show_bug.cgi?id=642237
2011-02-19 13:28:16 -05:00
530604d1ad Added UG translation 2011-02-19 15:32:48 +01:00
edc0cd36c5 date-menu: Adjust boxpointer position for RTL locales
We try to position the boxpointer centered above the calendar,
which swaps position with the events list when using a RTL locale,
so make the menu alignment dependent on the text direction.

https://bugzilla.gnome.org/show_bug.cgi?id=642721
2011-02-19 11:19:19 +01:00
5261304231 dash: Adjust CSS in RTL locales
As the dash uses different widths and radii for left and right
borders, we need to use different CSS when it is positioned at
the right of the screen.

https://bugzilla.gnome.org/show_bug.cgi?id=642721
2011-02-19 11:19:19 +01:00
a1c0b85819 workspace-thumbnails: Update style
For consistency, adjust background and border colors to match the
ones used by the dash.
2011-02-18 19:01:51 +01:00
1b4cff7cdc workspaceThumbnails: Allow mousewheel scrolling
Allow the user to switch the active workspace by using
the mousewheel over the workspace thumbnails.

https://bugzilla.gnome.org/show_bug.cgi?id=642303
2011-02-18 18:12:18 +01:00
ef983480c0 Be more careful with workspace thumbnail scale
- When tweening a workspace to collapse it, round the multiplied
  height so that we don't change other workspace sizes via rounding
  differences.
- Use separate horizontal and vertical scales, so that every thumbnail
  has the same horizontal scale.

https://bugzilla.gnome.org/show_bug.cgi?id=641881
2011-02-18 11:36:33 -05:00
bff027c1f7 Fix workspace thumbnails in RTL locales
We need slightly different CSS and positioning logic for
the workspace thumbnails list when it is on the left side of the
screen.

https://bugzilla.gnome.org/show_bug.cgi?id=642672
2011-02-18 11:36:33 -05:00
1473a66862 Omit the panel area from the previewed workspaces
Allow defining a "porthole" that is the visible area of a workspace
thumbnail, and use this to clip the portion under the panel off the
workspace thumbnails. (This is wrong for fullscreen windows, but not
very wrong, and hopefullly the few missing pixels will be
unnoticeable.)

https://bugzilla.gnome.org/show_bug.cgi?id=641880
2011-02-18 11:36:33 -05:00
53516733f7 Fix position of indicator while tweening
Because the overall parent allocation width immediately when the workspace
count changes, we were sometimes drawing the indicator in the wrong place
in the indicator animation that proceeded the remove-workspace animation.
Fix this by tweening only the Y position of the indicator and computing
the X position and size in our allocate() method. This also is considerably
simpler than switching the indicator between fixed position and geometry
managed.

https://bugzilla.gnome.org/show_bug.cgi?id=641881
2011-02-18 11:36:33 -05:00
e9a45190e4 Animate workspace indicator before adding/removing workspaces
Rather than killing the workspace indicator indicator when we remove
workspaces because the source and target locations might have changed,
do it as a separate first step. This provides a better explanation
than doing it simultaneously with the addition/removal or not at all
and also keeps our computations simple.

https://bugzilla.gnome.org/show_bug.cgi?id=641881
2011-02-18 11:36:33 -05:00
649ed3332f Fix background to animate with thumbnails
When we animating the scale for the thumbnails, the border and
background should wrap around the current size of the thumbails.
The technique that we are using to animate the scale breaks that
since we don't animate the overall size of the thumbnails box -
we just animate our child actors within the allocation.

To fix this, switch from drawing the background by packing in another
container to drawing the background with a separate actor that
is under the other actors and allocated by our custom logic.

https://bugzilla.gnome.org/show_bug.cgi?id=641881
2011-02-18 11:36:33 -05:00
7598fd4581 Slide workspace thumbnails in when added and out when removed
To explain to the user what is happening, instead of abruptly changing
updating the workspace thumbnail list, slide thubmnails in and out
as they are added and removed.

To implement this, we track a state for each thumbnail and when things
change go through a process of first sliding removed thumbnails out,
then ollapsing the left-over spaces and rescaling the thumbnails, then
finally sliding newly added thumbnails in.

https://bugzilla.gnome.org/show_bug.cgi?id=641881
2011-02-18 11:36:33 -05:00
aaf94ea8f9 Animate scale changes to workspace thumbnails
When we change the overall scale of the workspace thumbnail container, instead of
doing it abruptly, animate the transition.

https://bugzilla.gnome.org/show_bug.cgi?id=641881
2011-02-18 11:36:33 -05:00
1a639f0b17 StEntry: remove special redundant hover tracking
For historical reasons, StEntry always did hover tracking when you had
visible hint_text, even if track_hover was FALSE. Remove that special
case, and make entries track hover just like all other widgets do.

If we actually needed to distinguish hovered-with-hint-text from
hovered-without-hint-text (which, at the moment, we don't), we could
do that by setting separate CSS for :hover and :hover:indeterminate.

https://bugzilla.gnome.org/show_bug.cgi?id=642483
2011-02-18 09:50:14 -05:00
1bc1a0dbf0 a11y: Adjust schemas for screen keyboard
The setting in org.gnome.desktop.default-applications.at
has been removed, use the corresponding setting in
org.gnome.desktop.a11y.applications instead.
2011-02-17 20:46:16 +01:00
537ce60599 a11y: Adjust schema for screen reader
The setting in org.gnome.desktop.default-applications.at
has been removed, use the corresponding setting in
org.gnome.desktop.a11y.applications instead.
2011-02-17 18:51:27 +01:00
0ee5a05e00 shell-a11y: Adjust for renamed 'accessibility' key
The key in org.gnome.desktop.interface has been renamed to
'toolkit-accessibility'.
2011-02-17 18:51:27 +01:00
bdd805a3ee volume: Increase maximum by 50% for outputs with decibel support
Volume should go up to 150% if the sound card used as output has
decibel volume support.

https://bugzilla.gnome.org/show_bug.cgi?id=641886
2011-02-17 18:09:58 +01:00
43961aaca5 panel: fix app menu visibility after quick overview visit
If you left the overview immediately after entering it (either
intentionally or due to a bug), the app menu would mistakenly end up
hidden due to flaky interaction between its show() and hide() methods.

Based on a patch by Dan Winship <danw@gnome.org>

https://bugzilla.gnome.org/show_bug.cgi?id=641117
2011-02-17 11:36:35 -05:00
0ef3f999d2 Scale thumbnails to fit in the vertical space
When we have more thumbnails than can fit in the vertical space, scale
them down. This is implemented by using a generic container so we can
compute positions and sizes on the fly and do the appropriate
width-for-height behavior.

The usage of clutter constraints to position the indicator is droppped
since it less complicated to just position the indicator in the right
place ourselves.

https://bugzilla.gnome.org/show_bug.cgi?id=641879
2011-02-17 11:34:30 -05:00
fb8f3f19f7 workspacesView: Update zoom scale when controls are reallocated
The scale we zoom to in the "zoomed out" mode depends on the width of the
controls area. Once we rescale the workspaces dynamically, we'll need to
update the zoom scale as we add and remove workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=641879
2011-02-17 11:34:30 -05:00
85ecd1864f Use a fixed width for visible portion of workspace thumbnails
We will change the workspace thumbnail size as we get more thumbnails; it doesn't
really make sense to always show 1/5 of the thumbnails how big or small they are,
so instead show a CSS-configurable length.

https://bugzilla.gnome.org/show_bug.cgi?id=641879
2011-02-17 11:34:30 -05:00
630f0f0ac8 Improve allocation of workspace controls
Fix a bug in the computation of the zoomed-out scale and use a StBin
instead of an unnecessary StBoxLayout. Using the StBin will allow
correct width-for-height behavior for the controls.

https://bugzilla.gnome.org/show_bug.cgi?id=641879
2011-02-17 11:34:30 -05:00
ae5131f902 Make a separate class for workspace thumbnails box
Add WorkspaceThumbnail.ThumbnailsBox to handle managing the array
of workspace thumbnails; the logic will get more complex as we add
scaling and animation.

https://bugzilla.gnome.org/show_bug.cgi?id=641879
2011-02-17 11:34:30 -05:00
493e82e37d gnome_shell_plugin_start: fix bluetooth g_log muting
gnome-bluetooth changed its G_LOG_DOMAIN, so it was escaping our
filters. Fix that.
2011-02-17 10:54:30 -05:00
804b51fa95 Revert "a11y: Adjust schemas for screen reader and keyboard"
This reverts commit 4f23f32fc1.
2011-02-17 16:52:34 +01:00
4f23f32fc1 a11y: Adjust schemas for screen reader and keyboard
The settings in org.gnome.desktop.default-applications.at
have been removed, use the corresponding settings in
org.gnome.desktop.a11y.applications instead.
2011-02-17 16:18:32 +01:00
3631983de5 magnifier: Adjust for removal of 'show-magnifier' key
gsettings-desktop-schemas had two conflicting settings for showing
the magnifier: 'show-magnifier' in org.gnome.desktop.a11y.magnifier
and 'screen-magnifier-enabled' in org.gnome.desktop.a11y.applications.
The former has been removed in favor of the latter, so adjust to this
change.
2011-02-17 16:09:07 +01:00
a1e019b41a VolumeStatus: play notification on scroll
Add the machinery to cancel the notification when a new playing a
new one (wrapping ca_context_cancel), then use it when scrolling
the status icon.
Not doing it for the slider because it causes noise, either with the
keyboard, with mouse drag or with mouse wheel.

https://bugzilla.gnome.org/show_bug.cgi?id=633667
2011-02-17 15:35:17 +01:00
a80ed030ad Updated Norwegian bokmål translation. 2011-02-17 14:42:54 +01:00
1779f662b1 telepathyClient: changed default icon for contacts without an avatar
The original icon doesn't exist, which results in empathy summary
items in the tray showing no icons (invisible) at all. With this fix
users can now at least see where the icons are (they are no longer
invisible).

https://bugzilla.gnome.org/show_bug.cgi?id=639468
2011-02-17 08:08:53 -05:00
07bde8248e StScrollViewFade: Make fade-offset a property rather than a hardcoded constant
https://bugzilla.gnome.org/show_bug.cgi?id=642510
2011-02-16 23:07:13 +01:00
bb70be31c0 St: annotate st_adjustment_get_values() 2011-02-16 16:06:31 -05:00
6b429b7f50 view-selector: Remove show/hide functions
As Main.overview is now usable from the view selector's constructor,
move the setup of signal connections there and remove the show/hide
methods which were used as workaround.

https://bugzilla.gnome.org/show_bug.cgi?id=642196
2011-02-16 19:58:21 +01:00
0ae44f4015 search-entry: Handle find-as-you-type activation internally
To enable find-as-you-type when entering the overview and disabling
it when leaving, we used a chain of functions calls from ViewSelector
over SearchTab to SearchEntry. As find-as-you-type should be enabled
while the overview is shown, the activation/deactivation can be
handled entirely by the SearchEntry itself by tying it to the entry's
visibility.

https://bugzilla.gnome.org/show_bug.cgi?id=642196
2011-02-16 19:58:21 +01:00
f1c279765b dash: Remove show/hide functions
As Main.overview is now usable from the dash's constructor, move
the setup of signal connections there and remove the show/hide
methods which were used as workaround.

https://bugzilla.gnome.org/show_bug.cgi?id=642196
2011-02-16 19:58:21 +01:00
f39e693324 overview: Split a public init() function out of the constructor
The Overview does not only hold the different elements visible in
the overview, but is also a central point to manage drag signals.
As objects which are constructed in the overview constructor cannot
access Main.overview (as its constructor has not finished yet), we
use misnamed show/hide methods to work around this limitation, which
are called when entering/leaving the overview.
A better way to handle this problem is to remove the limitation
altogether by splitting the overview constructor between internals,
which remain in the constructor, and more complex objects which
need to access Main.overview, and whose initialization is moved
to a public init() function which is called by main.js after the
overview has been constructed.

https://bugzilla.gnome.org/show_bug.cgi?id=642196
2011-02-16 19:58:17 +01:00
e3e16586b8 Try to center the calendar arrow on the grid
Using the fixed percentage aligment, try to align the arrow of calendar
boxpointer on the center of the calendar grid

https://bugzilla.gnome.org/show_bug.cgi?id=642031
2011-02-16 10:19:43 -05:00
8f3376ce62 Add "precision" to boxpointer alignment
Allows the boxpointer arrow to be at a fixed percentage of the bubble

https://bugzilla.gnome.org/show_bug.cgi?id=642031
2011-02-16 10:19:39 -05:00
140022aaf2 gnome-shell.modules: add --disable-Werror to tp-glib build
telepathy-glib doesn't currently build warning-free with gcc 4.6,
(https://bugs.freedesktop.org/show_bug.cgi?id=34337) so disable
-Werror for now.
2011-02-16 09:50:23 -05:00
ccd2fec890 factor out _createSource 2011-02-16 10:10:26 +01:00
02bcce07bd index Source objects using the associated channel path 2011-02-16 10:10:26 +01:00
dc51a84cec remove our own Telepathy implementation
We rely only on telepathy-glib now (#620416).
2011-02-16 10:10:26 +01:00
2b91ef7833 use TpTextChannel 2011-02-16 10:10:26 +01:00
0285e62516 remove unused ContactManager 2011-02-16 10:10:26 +01:00
4ef1923573 get presence changes from TpContact 2011-02-16 10:10:25 +01:00
370c596fbf use TpContact to get the avatar 2011-02-16 10:09:43 +01:00
e97c15e01e pass a TpContact object to Source
This is based on a patch from Morten Mjelva.
2011-02-16 10:09:43 +01:00
69d3aad080 use TpAccountChannelRequest to re-ensure the channel 2011-02-16 10:09:43 +01:00
2fd5371de7 Source: store proper Telepathy objects 2011-02-16 10:09:43 +01:00
b750dde05b stop looking for existing channels manually
Mission-control will give them to you as we have Recover=True on the Observer.
2011-02-16 10:09:42 +01:00
9f310b6773 use constants from tp-glib 2011-02-16 10:09:41 +01:00
067e3f2075 Use TpSimpleObserver rather than our own Observer implementation 2011-02-16 10:08:41 +01:00
1938a5bcb0 Wrap tp_connection_get_contacts_by_handle
GArray support is broken in Gjs. This commit wraps
tp_connection_get_contacts_by_handle so we can retrieve TpContact objects.
2011-02-16 10:08:41 +01:00
36a624aafd Add telepathy-glib as a dependency
We'll be refactoring the Telepathy client to use telepathy-glib, so we need to
build it.
2011-02-16 10:08:41 +01:00
8c80a58fa4 StThemeNodeDrawing: clear out node interior before filling pattern
If we aren't going to fill the content area of the node with a solid
background color, then we need to clear it of any artifacts left over
from drawing the border.

https://bugzilla.gnome.org/show_bug.cgi?id=640465
2011-02-15 19:57:52 -05:00
740a946e72 Revert "StThemeNodeDrawing: fill background behind translucent gradients"
This reverts commit b4ec342d06.

The alpha > 0 checks should actually be alpha < 255 for the commit to
make sense as designed. The design isn't right either, though,
since we need to preserve the translucency in translucent gradients,
not block it with a solid color fill.

https://bugzilla.gnome.org/show_bug.cgi?id=640465
2011-02-15 19:57:52 -05:00
1aba99336a MessageTray: fix showing and hiding summary notifications when summary items are clicked
This patch fixes the summary notification reappearing if you click on the
summary item to hide it and hover away. It also ensures that when you click
on any summary item which doesn't correspond to the summary notification
being shown, a new summary notification will replace it right away.

What used to happen is that we'd unset the clicked item in _unlock() that
was called when the focus was ungrabbed because the user clicked outside
of the summary notification, but then would have this._clickedSummaryItem
be null in _onSummaryItemClicked() , and set it to the clicked item all
over again. This patch ensures that we unset the clicked item only when
it is necessary.

We also needed to add the code to call _updateState() again to show a new
summary notification when a previous one was hidden, but
this._clickedSummaryItem was set.

https://bugzilla.gnome.org/show_bug.cgi?id=642005
2011-02-15 18:37:33 -05:00
37d307c80e panel: remove some leftover code from the old calendar 2011-02-15 17:12:47 -05:00
294490f77b altTab: Properly query the themenode's color when painting the arrows 2011-02-15 20:58:21 +01:00
1bc805206b altTab: use keybinding actions instead of clutter keysym comparison
Use keybinding actions instead of clutter keysym comparisons to select
next/prev application and next/prev window.

https://bugzilla.gnome.org/show_bug.cgi?id=639341
2011-02-15 13:43:35 -05:00
a047132a2f altTab: enable the switch_group keybinding action
Allows the user to bring up the Alt+Tab popup with the current application's
window thumbnails selected.

https://bugzilla.gnome.org/show_bug.cgi?id=639341
2011-02-15 13:43:32 -05:00
c2ae95f912 AppWellMenu: Remove window filtering
Don't filter and highlight windows when opening the menu
as this turned out to be distracting and confusing.

https://bugzilla.gnome.org/show_bug.cgi?id=642189
2011-02-14 23:07:27 +01:00
ed6af523cb telepathyClient: Support markup in the title of presence changes
Follow-up to commit 09717aae58 so
title changes also support markup instead of the ugly "<i></i>"
status.

Additionally, make sure to escape the contact's title as that
may accidentally contain unsafe markup or characters.

https://bugzilla.gnome.org/show_bug.cgi?id=642209
2011-02-14 12:12:14 -05:00
1224e959b6 StThemeNode: use (out caller-allocates) on ClutterColor-returning methods
Properly annotate the themenode methods that return ClutterColors, and
update their JS callers to take advantage of that.

https://bugzilla.gnome.org/show_bug.cgi?id=642295
2011-02-14 10:49:26 -05:00
688b9697c8 shell-drawing: remove
Remove shell-drawing.[ch], which now only contained
shell_draw_clock(), which hadn't been used since the sidebar went
away.

https://bugzilla.gnome.org/show_bug.cgi?id=642059
2011-02-14 09:38:27 -05:00
0c0e2cc689 shell-drawing: remove shell_draw_box_pointer()
This was originally done in C because it used cairo, but that can be
done from JS now. Since it was only used by altTab.js, move it there.

https://bugzilla.gnome.org/show_bug.cgi?id=642059
2011-02-14 09:38:27 -05:00
f211681d6c Improve time format for Chinese (China). 2011-02-14 22:06:45 +08:00
eaa7b83979 Update Chinese (China) translations. 2011-02-14 19:50:53 +08:00
1c320d1f8a Update Chinese (China) translations. 2011-02-14 19:44:25 +08:00
216be33fb9 StWidget: Be more verbose when aborting in get_theme_node
Give some context to make it easier to track down the offender.
2011-02-13 22:59:27 +01:00
b23989871e placeDisplay: Fix another typo preventing place launching
https://bugzilla.gnome.org/show_bug.cgi?id=642207
2011-02-13 14:55:33 -05:00
fb5a0f8fa5 search: return an empty list instead of null
Make SearchSystem.updateSearch be consistent and always return a list,
avoiding an exception in SearchResults.updateSearch.

https://bugzilla.gnome.org/show_bug.cgi?id=642208
2011-02-13 11:56:24 -05:00
83883fafbb Updated Korean translation 2011-02-13 23:54:08 +09:00
09717aae58 telepathyClient: allow pango markup in presence changes
We were adding pango markup to the message in ContactManager.setPresence,
but weren't correctly marking the message as containing pango markup,
allowing for uglyness such as "User is <i>away</i>." being shown to the
user.

https://bugzilla.gnome.org/show_bug.cgi?id=642209
2011-02-13 08:44:18 -05:00
03729a71f4 placeDisplay: Fix typo preventing places from being launched
0d32017ffc accidentally introduced
a typo when launching places.

https://bugzilla.gnome.org/show_bug.cgi?id=642207
2011-02-13 08:44:14 -05:00
6bf2dd9138 ExtensionSystem: pass the metadata object to extensions
This allows using metadata.json as a configuration point (for
example for installation prefix).

https://bugzilla.gnome.org/show_bug.cgi?id=621017
2011-02-13 13:57:36 +01:00
7810db6b9f Load extensions before the status area is started
Defer starting the status area until all extensions are loaded, so
they can add themselves as status icons.

https://bugzilla.gnome.org/show_bug.cgi?id=621017
2011-02-13 13:55:32 +01:00
4c2d9ca16e magnifier: crosshairs opacity is now a double
The type of the opacity has been changed in
gsettings-desktop-schemas, and a range was added for it.

See also bug 642032

https://bugzilla.gnome.org/show_bug.cgi?id=642175
2011-02-13 02:23:53 +00:00
b0efe684fc app-icon: Use the dash's icon size for dragged icons
As the dash is one of the primary drop targets for dragging application
launchers, it's reasonable to use the dash icon size for app icons'
drag actors, especially with the larger size now used in the application
view.

https://bugzilla.gnome.org/show_bug.cgi?id=639428
2011-02-12 23:32:57 +01:00
2f3e47b586 overview: Make the dash public
In order to enable components other than Overview to read the
dash's iconSize, make the dash a public property of the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=639428
2011-02-12 23:32:57 +01:00
1d77914316 dash: Make iconSize property public
As elements in the dash are scaled to accommodate a growing number
of items, the icon size used may end up rather small. In that case,
dragging items to the dash which are significantly larger than items
in the dash is getting clumsy, so it makes sense for some components
to synchronize the size of drag actors with the currently used icon
size in the dash. To enable other components to do this, make the icon
size a public property.

https://bugzilla.gnome.org/show_bug.cgi?id=639428
2011-02-12 23:32:57 +01:00
aad3560ccb app-view: Use larger icons
According to the mockups[0], launcher icons in the app view should
be larger. Leave icons in search results at their current size,
until the designers decide what's appropriate there.

[0] http://live.gnome.org/GnomeShell/Design/Whiteboards/Launchers

https://bugzilla.gnome.org/show_bug.cgi?id=639428
2011-02-12 23:32:57 +01:00
69d25c975c StThemeNode: Add (out caller-annotates) annotations
Mark the ClutterActorBox return for a number of functions so we can use
them from Javascript.

https://bugzilla.gnome.org/show_bug.cgi?id=642192
2011-02-12 17:29:10 -05:00
64c4bb86c6 Updated Slovenian translation 2011-02-12 20:37:54 +01:00
eadd3691a6 Updated Arabic translation 2011-02-12 01:05:31 +02:00
20aec4bb55 Updated Dutch translation by Wouter Bolsterlee 2011-02-11 23:09:28 +01:00
01b646169c Fix fuzziness for application icons
- Center the icon texture in the area allocated for it, and always give
  the nominal size - avoid off-by-one scaling if the parent allocated
  a little less or more size than we wanted.
- Use Math.floor() when centering horizontally to avoid allocation
  at a half pixel.

https://bugzilla.gnome.org/show_bug.cgi?id=642124
2011-02-11 16:21:11 -05:00
e5130877e7 Avoid relayout when not changing the workspace reserved slot
Make calling workspace.setReservedSlot(null) do nothing if the slot was
already null; this improves efficiency and more importantly chills out some
weird reentrancy at the end of drag and drop that removes a window from
a workspace.
2011-02-11 12:34:15 -05:00
75f771d736 dnd: Fix bug in computation of snap-back position
We were properly accounting for the fact that an ancestor of the
parent could be scaled rather than the parent itself when computing
the snap-back scale, but directly using parent.scale_x for the
snap-back location.

https://bugzilla.gnome.org/show_bug.cgi?id=642117
2011-02-11 12:34:15 -05:00
914e5d30c7 workpaceThumbnail: Fix accidental propagation of button releases
A right click was propagating through to the parent actor meaning
that a right click would activate the workspace twice and leave the
overview instead of just switching to it.

https://bugzilla.gnome.org/show_bug.cgi?id=641973
2011-02-11 12:14:27 -05:00
2d716041f1 Make clicking on the active workspace thumbnail go to the main view
If you want to select a workspace and go there, having to go back to
the main part of the window selector and click on a window is annoying,
so make a second click on the active workspace go to the main view.

https://bugzilla.gnome.org/show_bug.cgi?id=641973
2011-02-11 12:13:35 -05:00
cd56de85d0 Move magnifier schemas to gsettings-desktop-schemas
Move the magnifier schemas to gsettings-desktop-schemas to allow them to be
shared between gnome-shell and other applications.

https://bugzilla.gnome.org/show_bug.cgi?id=642034
2011-02-11 16:52:45 +00:00
47e66ffc01 Uploaded Ukranian 2011-02-11 06:53:26 +02:00
b4ec342d06 StThemeNodeDrawing: fill background behind translucent gradients
If a background gradient isn't fully opaque, then we need to first
fill in the background color so the border color doesn't leak into
the interior.

https://bugzilla.gnome.org/show_bug.cgi?id=640465
2011-02-10 18:24:30 -05:00
0e23ec394e StThemeNodeDrawing: Ignore border fill in interior
We need to be careful to ignore any preexisting color information
in the interior of the node when filling it with the background color,
since the border color may have leaked into the interior and the
background color may be translucent.

https://bugzilla.gnome.org/show_bug.cgi?id=640465
2011-02-10 18:24:30 -05:00
7d77802ba1 tests: show off translucent gradients
Right now border color is leaking through.
Demonstrate that.

https://bugzilla.gnome.org/show_bug.cgi?id=640465
2011-02-10 18:24:29 -05:00
ce91d85bc0 Require gtk+3 3.0.0 and drop checks for minor versions. 2011-02-10 17:37:36 -05:00
aba6a85c56 workspace: don't show WindowOverlay during zoomFromOverview
https://bugzilla.gnome.org/show_bug.cgi?id=641533
2011-02-11 00:43:22 +03:00
475c36048b lookingGlass: fix red border drawing in the inspector, port to JS
Some recent painting-efficiency fix broke the inspector, which
accidentally depended on things getting repainted too often, and so
was failing to highlight things properly now. A simple queue_redraw()
fixes this, but while I was there, I decided to port the drawing hook
to JS as well, since all the necessary parts of cogl work fine from
JS.

https://bugzilla.gnome.org/show_bug.cgi?id=642058
2011-02-10 16:04:16 -05:00
ea4c68bd8e Uploaded Ukranian 2011-02-10 21:51:13 +02:00
ac3c9f8475 Updated Arabic translation 2011-02-10 20:49:30 +02:00
de3ae87199 MessageTray: factor out focus grabbing from Notification into a separate class
That way it can be used when other components of the message tray need to
grab focus, such as the summary bubble with multiple notifications or the
summary item's right click menu.

https://bugzilla.gnome.org/show_bug.cgi?id=641810
2011-02-10 11:50:29 -05:00
e752aae669 gnome-shell: remove Xephyr support
Built-in Xephyr support was an important debugging/development feature
for a while, but it is no longer especially useful (and has been
mostly broken since Clutter 1.4 anyway).

https://bugzilla.gnome.org/show_bug.cgi?id=610818
2011-02-10 10:38:27 -05:00
8f7d5cde90 app-display: Only reset filters when they have been initialized
The view might get mapped before the filters have been added, so
trying to reset to the "All" filter will throw an exception. Fix
by only do the reset if the filters have been initialized.
2011-02-10 16:34:23 +01:00
d90c98130e app-display: Always select "All" filter on switch
When switching to the app view, it is unlikely that a user is
going to select an application from the same filter list as the
last time the view was used, so reset the view to the "All" filter
on switch.

https://bugzilla.gnome.org/show_bug.cgi?id=641987
2011-02-10 01:23:01 +01:00
af3883905b app-view: Reset scroll position on switch
When switching to the application view, the view is still scrolled
to the position it had when left previously. Given that it is rather
unlikely that the application the user wants to select is located close
to that position, it appears beneficial to start at a predictable
position, so make sure that the scroll position is always reset to
the top.

https://bugzilla.gnome.org/show_bug.cgi?id=641987
2011-02-10 01:23:01 +01:00
a4e53953a9 workspaceSwitcher: Initially hide after creation
The default state of the switcher is constructed but not visible,
so create it that way.

This fixes a bug where if we created the switcher but didn't show it
or use it we'd end up with an empty, odd looking switcher.
2011-02-10 00:16:32 +01:00
165f4e38b7 dash: Don't unnecessarily animate icon size changes
We already skip animations for item additions/removals while the
overview is hidden or when initially filling the dash (to avoid
an odd zoom effect when showing), apply the same logic to animations
of icon size changes.
2011-02-10 00:09:02 +01:00
7372308270 dash: Increase the maximum icon size
With the labels removed from dash items, we can potentially use
a larger icon size, so add 64 to the list of icon sizes and use
it by default.
2011-02-09 23:51:46 +01:00
c239d3bb1b dash: Update style so running apps keep the highlight on hover
Using "background" for the hover state overwrites the "background-image"
property of running apps. Use "background-color" in hover instead, so
the background image is kept during hover. Apply the same fix to the
selection indicator for search results.
2011-02-09 23:22:58 +01:00
940f06fb32 bluetooth: remove weird "Agent" word from notification (close #637687)
Agents are an implementation detail of Bluetooth on Linux (it's actually
a D-Bus "agent", not a Bluetooth one anyway). Only "Bluetooth" is fine.
2011-02-09 23:08:02 +01:00
026f598c37 dash: Skip animations while the overview is hidden
If a window is closed, the list of running applications may change
while the overview is hidden. Animating dash changes is pointless
in this case, so update the dash without animations in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 22:16:45 +01:00
d33958ceee dash: Minor style fixes
- 1px border rather than 2
 - less padding around launchers
 - icon prelight was too bright, bring it down a notch

Based on an original patch by Jakub Steiner.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 22:16:45 +01:00
9bbf293898 dash: Avoid "zoom" effect when first shown
The dash is created empty and the initial set of items is added
before it's shown for the first time. As the additions of items
is now animated, this results in a slightly odd effect when all
items zoom in at once. So special-case the first time _redisplay()
is called and skip animations in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 22:16:45 +01:00
d6020f1402 dash: Animate item and size changes
In general, all changes in the shell interface should be backed
by animations to give the interface a more natural feel and provide
feedback of what's happening. Currently the dash violates that
principle, as items simply appear/disappear or change size abruptly,
so add animations for application list and icon size changes.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 22:16:45 +01:00
29e97a5f88 dash: Wrap items in a scale-aware container
Clutter containers only take their children's size into account, but
not their scale. As we want the dash to change its size smoothly
when zooming items in/out, we wrap each item in a custom container
which does consider the child's scale.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 22:16:45 +01:00
2b84554d91 dash: Don't empty dash on changes
When the list of applications in the dash changes, all items are
removed and new ones added. While this approach is nice and simple,
it does not work if we want to animate changes. So rather than
replacing the old list of applications with the new one, figure
out the changes and only apply those.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 22:16:40 +01:00
a0584b9c30 dash: Take remove target into account for icon size
Previously the icon size was only adjusted due to changes in the list
of application icons displayed, not when showing or hiding the remove
target. As a result, the remove target could end up cut off, so take
this case into account and adjust the icon size when showing or hiding
the remove target.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 21:36:55 +01:00
5aab878e75 dash: Calculate icon size changes without reallocation
The current approach to adjust the icon size of dash items is rather
expensive: the size of each item is changed from largest to smallest,
until the height of the dash fits the maximum available height, so
quite some ClutterTextures are created and disposed.
A better approach is to calculate the required size beforehand and
only change the icon size when necessary.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 21:36:55 +01:00
4d474e2f9c dash: Hide item labels
With the current dash layout of a single column, nearly every icon
label ends up ellipsized, even at the largest allowed icon size.
Not showing any labels appears to be the cleanest approach in this
case, so disable them in the dash.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 21:36:55 +01:00
8cf9b5e5d2 base-icon: Add an option to not show the label
Currently there is a serious problem with ellipsization in various
parts of the overview. While wrapping the label or giving it more
space may be appropriate approaches for the application view, neither
works very well for the dash - possibly the best option there is to
not show the label at all.
So add a constructor parameter to BaseIcon to allow hiding the
label.

https://bugzilla.gnome.org/show_bug.cgi?id=636156
2011-02-09 21:36:54 +01:00
a52ec8f286 appSwitcher: Don't create thumbnails for destroyed windows 2011-02-09 20:54:37 +01:00
739399eb2e Disable left/right workspace switching in the overview
Make the overview match the main view so only up/down can be used
to switch workspaces (matching the visuals), and not left/right
as well.

https://bugzilla.gnome.org/show_bug.cgi?id=641887
2011-02-09 14:08:41 -05:00
ef8c9e0abb workspace-switcher: Switch to vertical orientation
With workspaces now being stacked vertically, the horizontal
indicators in the workspace switcher are rather odd. There are
some designs for an improved workspace switch animation, but
it may take a while to implement them, so for now just change
the orientation of the existing switcher.

https://bugzilla.gnome.org/show_bug.cgi?id=641931
2011-02-09 20:02:51 +01:00
c705b64d67 boxpointer: Use the right source center for the arrow pointing
Point the arrow to the center of the sourceActor's content box, rather
than its allocation, in case it has asymmetric padding (as the
rightmost message tray summary item does).

https://bugzilla.gnome.org/show_bug.cgi?id=641728
2011-02-09 12:49:07 -05:00
70dd9c9d3d boxpointer: Change the alternate drawing of boxpointer arrows
To avoid some "jumping" of the arrow, draw it diagonally when needed.
It makes animations smoother.

https://bugzilla.gnome.org/show_bug.cgi?id=641726
2011-02-09 12:49:07 -05:00
4450385458 panel-button: Set ':active' pseudo class when menu is open
Commit c86a977564 removed :pressed from the list of styles which
highlight panel buttons, so the button highlight is now lost when
mousing over menu items. This is not the behavior we want, the
buttons should keep their highlight while being "active". Rather
than adding back the pseudo class to the CSS, let buttons use the
:active pseudo class when the menu is open, which makes more sense
than :pressed anyway.
2011-02-09 18:10:25 +01:00
1f154f6638 Fix press/release confusion when synthesizing clutter key events
We were generating presses for releases and vice-versa.

https://bugzilla.gnome.org/show_bug.cgi?id=641896
2011-02-09 12:01:53 -05:00
881a1d5cbc Updated Gujarati Translations & Added gu in LINGUAS 2011-02-09 12:53:06 +05:30
11064c0e35 kbd-status: Remove support for disabling the indicator
The status icon should always be visible if more than two layouts
are configured. The settings key which was used to enforce hiding
the icon in this case as well has already been removed from the
g-s-d schema, causing an error on startup.
2011-02-09 02:34:53 +01:00
7496a7ff3b Handle changes in window position for workspace thumbnails
Connect to the 'position-set' signal of MetaWindowActor and move
actors when the source windows move.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:21 -05:00
fb71250dce Improve workspace controls slide-in positioning
Intead of using a St.Group and tweening the position of the controls
actor, use a St.GenericLayout and tween a Javascript property. This
allows us to more reliably track the height of the overall workspace
display and propagate it to the controls actor.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:21 -05:00
0d32017ffc Don't switch to a workspace when dragging it to launch on that workspace
With workspace thumbnails, we don't switch workspaces when dragging windows
between workspaces or adding new workspaces, so we also shouldn't switch
on launch.

 * Add workspace parameters to shell_doc_system_open(),
   shell_app_activate, shell_app_open_new_window()

 * Pass a 'params' object when activating items in the overview with
   two currently defined parameters: workspace and timestamp. (timestamp
   is only implemented where it is easy and doesn't require interface
   changes - using the global current timestamp for the shell is almost
   always right or at least good enough.)

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:21 -05:00
1b8bfda3b4 Avoid popping the workspace controls in and out at the end of DND
At the end of a drag operation, we would invoke the code to slide the
controls in (because we were no longer DND'ing and not hovering) and
then immediately afterwards invoke the code to slide it back out when
we got the ENTER event from the end of DND. While the immediately
overridden tween probably won't have any visible effect it's better
to avoid this, so wait to update the zoom state until BEFORE_REDRAW.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:21 -05:00
f038ce1c69 Remove now unnecessary workspace controls
With automatic workspace management, explicit controls to add and
remove workspaces are no longer necessary. We also can remove the
use of addWorkspace for middle-button-click on a launcher since
launching on the last empty workspace will do the right thing.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:20 -05:00
e6938ed06c Add automatic workspace management
Automatically add and remove workspaces so that the last workspace is
always empty and no workspaces are empty other than that workspace.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:20 -05:00
2d5133ad51 Don't activate newly added workspaces
With workspace thumbnails, we want to make workspace switching
something that happens largely under the users control, so don't
switch to newly added workspaces in the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:20 -05:00
6514bc845f Add workspace thumbnails to the overview
Add workspace thumbnails to the workspace controls area. The user can
click on the thumbnail to switch workspaces and can also drag windows
out of the thumbnail to other workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:20 -05:00
eda12542c0 Move restacking handling from WorkspacesView to WorkspacesDisplay
Moving the base tracking of restacking to WorkspacesDisplay will allow
us to use it to update stacking in the workspace thumbnails as well as
in the main workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:20 -05:00
7c2aee3ac0 Use a single "zoomed out" view for both workspace controls hover and DND
Instead of having a separation between popping the controls out on hover
and zooming out for DND, always do both at once. This is necessary because
when we added workspace thumbnails the controls will get bigger, so we need
to make sure we zoom out far enough so that the windows don't overlap the
controls.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:20 -05:00
3c593fc056 Don't check for Workspaces.WindowClone for window drops
When checking the type of a DND source, instead of checking
'instanceof Workspaces.WindowClone' accept any actor with realWindow
and metaWindow properties. This will be useful to support a separate
type of actor dragged from workspace thumbnails.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:20 -05:00
9748cc264a Remove workspace indicators
Once we have workspace thumbnails in the overview, workspace indicators
will no longer be needed.

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:20 -05:00
295d286161 Switch to a vertical layout for workspaces
The new plans for a row of workspace thumbnails on the right side of the
overview means that the mental model we present to the user will be
vertical, so switch the Metacity workspace layout to be vertical and
adjust the keybinding handling, animations, and workspace layout in
the overview to match.

(This commit does not change the workspace switching indicator pending
finalization of what we want to do with that - it still shows workspaces
arranged vertically.)

https://bugzilla.gnome.org/show_bug.cgi?id=640996
2011-02-08 19:43:20 -05:00
6011dd6bc9 Updated Arabic translation 2011-02-09 01:10:45 +02:00
5eb28e162f popupMenu: minor code rearrangement
Move the Switch class to right before PopupSwitchMenuItem (and add
some missing semicolons).
2011-02-08 16:08:50 -05:00
2792ad1cf4 chrome: try find fullscreen windows only on current workspace
https://bugzilla.gnome.org/show_bug.cgi?id=641677
2011-02-08 23:43:35 +03:00
95e6eae23b Fixes for previous ShellAppSystem patch a138f59c
Wasn't amended by mistake.
2011-02-08 14:38:24 -05:00
9ec2d5d609 Add mouseButtonClicked argument to the callback for St.Button 'clicked' signal in Notification
St.Button 'clicked' signal now has two arguments, and because we are also
passing an action id as an argument to the _onActionInvoked() callback,
we need to have the number of the signal arguments reflected accurately in
the function arguments.

https://bugzilla.gnome.org/show_bug.cgi?id=641809
2011-02-08 11:22:51 -05:00
a138f59cb0 Use new GLib application API for launching
Launch child processes more directly; we retrieve the PID, and
use it to keep track of the .desktop file we launched.

Now, when we get a window, since the X window has a PID, we
have a pretty strong association.

.desktop file <-> PID <-> window

And can thus map window back to .desktop file.

https://bugzilla.gnome.org/show_bug.cgi?id=637745
2011-02-08 10:43:39 -05:00
d3e223c217 build: include libxklavier (cvs) in moduleset (bug #641605)
Also change setup script in order to fetch iso-codes and cvs
2011-02-07 20:54:28 +01:00
5437a3be4b Only animate the message tray items on a hover of a new item or when the tray is left
This makes the animation feel more stable and keeps the left-most item expanded
when you move the mouse to the left in the tray.

The following behavior details are implemented by this patch:
  - we wait to collapse an expanded item till after the tray is hidden if
    we are hiding the tray
  - we don't collapse an expanded item if the summary notification associated
    with it is being shown, unless a different summary item is hovered over
  - we don't consider the mouse hovering over a summary notification as
    hovering over the tray, which allows us to collapse an expanded summary
    item if it is not associated with the summary notification being shown

https://bugzilla.gnome.org/show_bug.cgi?id=636930
2011-02-07 13:17:34 -05:00
c86a977564 St: drop StClickable, add some functionality to StButton
For historical reasons, we had both StClickable and StButton, which
were nearly identical. StButton was more widely-used, so keep that and
port all StClickable users to that.

https://bugzilla.gnome.org/show_bug.cgi?id=640583
2011-02-07 12:45:48 -05:00
c256fa9b9f AppIcon: right-click menu should appear on press, not click
https://bugzilla.gnome.org/show_bug.cgi?id=640583
2011-02-07 12:45:48 -05:00
ab80c5080a theme-node: Fix box-shadows for prerendered textures
The material of prerendered backgrounds is now painted in the
rectangle determined by st_theme_node_get_paint_box(). As the
ClutterActorBox returned from that function includes the space
needed to draw the box shadow, the background ends up occluding
the shadow.
As the box shadow is not part of the background, factor out a new
helper function which excludes the box shadow, and use it to
prerender and place the background material.

https://bugzilla.gnome.org/show_bug.cgi?id=641522
2011-02-07 18:22:33 +01:00
acf04d33ef gitignore: ignore *.sw? files 2011-02-07 16:32:16 +01:00
bd04107593 tray: fix so that trayicons using symbolic icons get the right colors
The tray protocol only allows setting a single set of colors for all
symbolic trayicons; we use the message-tray's theme node to set that.

https://bugzilla.gnome.org/show_bug.cgi?id=641060
2011-02-07 10:01:12 -05:00
e208c7e3dd tray: re-sync from panel, including _NET_SYSTEM_TRAY_COLORS support
https://bugzilla.gnome.org/show_bug.cgi?id=641060
2011-02-07 10:00:54 -05:00
fc313b198a Updated Norwegian bokmål translation. 2011-02-06 19:36:40 +01:00
b6749f4b60 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
2011-02-06 12:11:04 +01:00
ad27b9eda5 VolumeStatus: change the definition of high/medium/low
Do it the same way as gnome-settings-daemon, so that OSD does not
look "out-of-sync" with the status icon.

https://bugzilla.gnome.org/show_bug.cgi?id=641538
2011-02-06 12:03:12 +01:00
fd8572d44a [l10n] Updated Estonian translation 2011-02-06 10:09:16 +02:00
32d59861a0 shell_global_maybe_gc: Call gjs_context_maybe_gc instead of JS_MaybeGC
This handles native glibc memory allocations better see:
https://bugzilla.gnome.org/show_bug.cgi?id=640790

Also bump the minimum gjs version to 0.7.11

https://bugzilla.gnome.org/show_bug.cgi?id=640781
2011-02-06 00:25:45 +01:00
5bd40ff416 Updated Galician translations 2011-02-06 00:15:24 +01:00
d1c3d8cadc Updated Italian translation 2011-02-05 16:36:57 +01:00
49f270b02b l10n: add searchDisplay.js to POTFILES.in 2011-02-05 16:32:08 +01:00
9148dfba34 Updated Hebrew translation. 2011-02-05 16:55:08 +02:00
ff89090a09 Updated Hebrew translation. 2011-02-05 16:49:54 +02:00
ca7b03852d Updated Hebrew translation. 2011-02-05 14:11:44 +02:00
9735e40e24 [l10n] Updated Estonian translation 2011-02-05 13:10:07 +02:00
40d8758aae Updated Spanish translation 2011-02-05 10:09:01 +01:00
73bd499d97 update Translation for Punjabi 2011-02-05 08:07:08 +05:30
59191bc4b7 statusMenu: temporarily drop Suspend menu item
It doesn't currently work, so hide it for now.

It's not clear it's going to stay around long term,
anyway. If it doesn't we can delete the code, then.
Otherwise, we can add the code back when we have
something that works.

https://bugzilla.gnome.org/show_bug.cgi?id=636680
2011-02-04 17:25:20 -05:00
3173401cc2 css: don't hard code search entry height
When commit 961fdd861f landed
text in the overview search entry field started getting clipped.

This is because the default font size changed but the entry is a
hard coded pixel height.

This commit drops the hard coding, so the entry can automatically
size itself to the proper height.

https://bugzilla.gnome.org/show_bug.cgi?id=641537
2011-02-04 15:15:06 -05:00
9c53ae61f4 configure.ac: Require GTK+ 2.99.3 for the tray API changes
https://bugzilla.gnome.org/show_bug.cgi?id=641359
2011-02-04 12:15:22 -06:00
20de1ca772 Updated Hebrew translation. 2011-02-04 09:31:19 +02:00
5259656ce1 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2011-02-04 13:15:03 +08:00
00df20c618 window-clone: Fix signal connections when the window is closed
Commit 91d8a32f25 let WindowClone forward the size-changed signal
of the "real" window, disconnecting the signal handler when the
clone is destroyed. In case the clone was destroyed due to the
MetaWindowActor being closed, this results in a warning
(gsignal.c:2392: instance `0x2a3fac0' has no handler with id `2955').

Handle the case where the original window is destroyed before its
clone.
2011-02-03 19:38:57 +01:00
7637afe7dc Updated Arabic translation 2011-02-03 17:36:16 +02:00
b864f68c19 build: Fix Ubuntu/Debian build dependencies
Some more packages are required to satisfy the e-d-s dependency.
2011-02-03 14:10:03 +01:00
0c12f1d2ee Updated Italian translation 2011-02-03 12:19:36 +01:00
f3e687eac8 calendar: clean up l10n for time format and labels (close bug #641245)
Add translation context and comments in order to be more helpful to translators.
Also mark a couple of strings as translatable.
2011-02-03 12:12:57 +01:00
3653f7c6c1 Updated Galician translations 2011-02-03 10:51:17 +01:00
ac92d0678b update Punjabi Translation by A S Alam 2011-02-03 08:27:11 +05:30
bd9e6a3bdf Updated Norwegian bokmål translation. 2011-02-02 20:34:34 +01:00
2ce93ce39e l10n: add new calendar to POTFILES.in 2011-02-02 13:03:19 +01:00
5b95ccae5f boxpointer: fix multi monitor support
https://bugzilla.gnome.org/show_bug.cgi?id=641195
2011-02-02 02:37:43 +03:00
0310f07eab modalDialog: remove old actions from _actionKeys in setButtons
https://bugzilla.gnome.org/show_bug.cgi?id=640781
2011-02-01 23:41:28 +03:00
e3acaa05be Remove st_container_remove_all & rewrite st_container_destroy_children
1. Both functions leaked the nodes in priv->children
2. st_container_remove_all wasn't properly updating first_child and last_child
3. remove_all() is almost never right since it won't cause signal handlers
   on the children to be removed. In the rare cases where it might be needed
   the caller can simply use clutter_container_remove().
https://bugzilla.gnome.org/show_bug.cgi?id=640781
2011-02-01 23:41:21 +03:00
91d8a32f25 workspace: make WindowClone forward the 'size-changed' event
https://bugzilla.gnome.org/show_bug.cgi?id=640781
2011-02-01 23:41:16 +03:00
457c7adf59 workspacesView: dispose _scrollAdjustment in _onDestroy
https://bugzilla.gnome.org/show_bug.cgi?id=640781
2011-02-01 23:41:11 +03:00
8ebdb7f493 workspacesView: remove duplicate connection to same signal 2011-02-01 23:41:05 +03:00
6c55ca59b0 Group chat sources on the left in the message tray
This will make it easier for users to get back to their chats.

https://bugzilla.gnome.org/show_bug.cgi?id=617234
2011-02-01 15:29:14 -05:00
0e4a47c0aa Enables navigation using arrow keys in notifications with buttons.
Users can now use the keyboard and mouse to navigate with buttons
interchangeably, instead of entirely using only mouse.

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

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

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

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

This was discovered when working on bug 641049:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

This commit adds support for background images to

st_theme_node_render_background_with_border

and changes the code to call that function when appropriate.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Coordination is done over the bus.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Partially based on a patch by Daiki Ueno

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Both commits fix CVE-2010-4000.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Based on the initial patch by Jonathan Matthew.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Based on earlier versions from Jon McCann and Florian Muellner.

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

Other significant changes:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

https://bugzilla.gnome.org/show_bug.cgi?id=635393
2010-11-30 07:14:20 -05:00
278 changed files with 79338 additions and 23433 deletions

17
.gitignore vendored
View File

@ -7,7 +7,6 @@ ChangeLog
INSTALL
Makefile
Makefile.in
NEWS
aclocal.m4
autom4te.cache
config.h
@ -18,13 +17,10 @@ config
configure
data/gnome-shell.desktop
data/gnome-shell.desktop.in
data/gnome-shell-clock-preferences.desktop
data/gnome-shell-clock-preferences.desktop.in
data/gschemas.compiled
data/org.gnome.shell.gschema.xml
data/org.gnome.shell.gschema.valid
data/org.gnome.accessibility.magnifier.gschema.xml
data/org.gnome.accessibility.magnifier.gschema.valid
js/misc/config.js
intltool-extract.in
intltool-merge.in
intltool-update.in
@ -43,16 +39,23 @@ 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-clock-preferences
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
src/test-theme
src/st.h
src/stamp-st.h
src/stamp-st.h.tmp
stamp-h1
tests/run-test.sh
xmldocs.make
*~
*.patch
*.sw?

63
NEWS Normal file
View File

@ -0,0 +1,63 @@
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,11 +1,14 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[2.91.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.0.0],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([config])
AC_SUBST([PACKAGE_NAME], ["$PACKAGE_NAME"])
AC_SUBST([PACKAGE_VERSION], ["$PACKAGE_VERSION"])
AM_INIT_AUTOMAKE([1.10 dist-bzip2 no-dist-gzip foreign])
AM_MAINTAINER_MODE
@ -49,59 +52,104 @@ 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
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.5.8
GOBJECT_INTROSPECTION_MIN_VERSION=0.6.11
GJS_MIN_VERSION=0.7
MUTTER_MIN_VERSION=2.91.0
GTK_MIN_VERSION=2.91.0
CLUTTER_MIN_VERSION=1.5.15
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=0.7.11
MUTTER_MIN_VERSION=3.0.0
GTK_MIN_VERSION=3.0.0
GIO_MIN_VERSION=2.25.9
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
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)
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(TIDY, clutter-1.0)
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 gnome-desktop-3.0 >= 2.90.0)
PKG_CHECK_MODULES(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)
PKG_CHECK_MODULES(JS_TEST, clutter-x11-1.0 gjs-1.0 gobject-introspection-1.0 gtk+-3.0)
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
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)
AC_MSG_CHECKING([for bluetooth support])
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=libdir gnome-bluetooth-1.0`/gnome-bluetooth
BLUETOOTH_LIBS="-L'$BLUETOOTH_DIR' -lgnome-bluetooth-applet"
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])
AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library])
AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
AC_SUBST([HAVE_BLUETOOTH],[1])
AC_MSG_RESULT([yes])],
[AC_DEFINE([HAVE_BLUETOOTH],[0])
AC_SUBST([HAVE_BLUETOOTH],[0])
AC_MSG_RESULT([no])])
# Default to libedataserverui-3.0, but allow falling back to 1.2
PKG_CHECK_EXISTS(libedataserverui-3.0,
[EDS_API=3.0
LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI3_MIN_VERSION],
[EDS_API=1.2
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_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)
@ -150,21 +198,15 @@ if test "$enable_compile_warnings" != no ; then
fi
changequote([,])dnl
AC_PATH_PROG(mutter, [mutter])
AC_SUBST(mutter)
AC_MSG_CHECKING([if mutter was compiled with GTK+-3.0])
if $PKG_CONFIG --libs libmutter-private | grep gtk-x11-3 >/dev/null; then
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
AC_MSG_ERROR([GNOME Shell requires Mutter to be compiled against GTK+-3.0])
fi
AC_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
data/Makefile
js/Makefile
js/misc/config.js
src/Makefile
tests/Makefile
po/Makefile.in

View File

@ -1,5 +1,5 @@
desktopdir=$(datadir)/applications
desktop_DATA = gnome-shell.desktop gnome-shell-clock-preferences.desktop
desktop_DATA = gnome-shell.desktop
# We substitute in bindir so it works as an autostart
# file when built in a non-system prefix
@ -12,27 +12,32 @@ desktop_DATA = gnome-shell.desktop gnome-shell-clock-preferences.desktop
%.desktop:%.desktop.in
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
dist_pkgdata_DATA = clock-preferences.ui
imagesdir = $(pkgdatadir)/images
dist_images_DATA = \
close-black.svg \
magnifier.svg
searchprovidersdir = $(pkgdatadir)/search_providers
dist_searchproviders_DATA = \
search_providers/google.xml \
search_providers/wikipedia.xml
themedir = $(pkgdatadir)/theme
dist_theme_DATA = \
theme/add-workspace.svg \
theme/calendar-arrow-left.svg \
theme/calendar-arrow-right.svg \
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/dialog-error.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/process-working.png \
theme/remove-workspace.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.svg \
theme/running-indicator.svg \
theme/scroll-button-down-hover.png \
theme/scroll-button-down.png \
@ -45,16 +50,15 @@ 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 \
theme/toggle-on-intl.svg \
theme/ws-switch-arrow-left.svg \
theme/ws-switch-arrow-right.svg
theme/ws-switch-arrow-up.svg \
theme/ws-switch-arrow-down.svg
gsettings_SCHEMAS = \
org.gnome.accessibility.magnifier.gschema.xml \
org.gnome.shell.gschema.xml
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
@INTLTOOL_XML_NOMERGE_RULE@
@GSETTINGS_RULES@
@ -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
@ -87,16 +86,13 @@ install-data-local:
EXTRA_DIST = \
gnome-shell.desktop.in.in \
gnome-shell-clock-preferences.desktop.in.in \
$(menu_DATA) \
$(gconfschema_DATA) \
$(shaders_DATA) \
org.gnome.accessibility.magnifier.gschema.xml.in \
org.gnome.shell.gschema.xml.in
CLEANFILES = \
gnome-shell.desktop.in \
gnome-shell-clock-preferences.desktop.in \
$(desktop_DATA) \
$(gsettings_SCHEMAS) \
gschemas.compiled

View File

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

View File

@ -1,66 +0,0 @@
<?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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Foreground"
x="0px"
y="0px"
width="16px"
height="16px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve"
sodipodi:version="0.32"
inkscape:version="0.46+devel"
sodipodi:docname="close-black.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata2399"><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="defs2397"><linearGradient
id="linearGradient3173"><stop
style="stop-color:#c4c4c4;stop-opacity:1;"
offset="0"
id="stop3175" /><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3177" /></linearGradient><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 8 : 1"
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="811"
inkscape:window-width="1272"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showgrid="false"
inkscape:zoom="32.125"
inkscape:cx="8"
inkscape:cy="10.440056"
inkscape:window-x="40"
inkscape:window-y="40"
inkscape:current-layer="Foreground" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10.5,3.5l2,2L10,8l2.5,2.5l-2,2L8,10l-2.5,2.5l-2-2L6,8L3.5,5.5l2-2L8,6L10.5,3.5 z M0,8c0-4.418,3.582-8,8-8s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z"
id="path2394"
style="fill-opacity:1;fill:#545454" />
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

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

View File

@ -7,9 +7,10 @@ X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-shell
X-GNOME-Bugzilla-Component=general
X-GNOME-Bugzilla-Version=@VERSION@
Categories=GNOME;GTK;Utility;Core;
Categories=GNOME;GTK;Core;
OnlyShowIn=GNOME;
NoDisplay=true
X-GNOME-Autostart-Phase=WindowManager
X-GNOME-Provides=panel;windowmanager;
X-GNOME-Autostart-Notify=true
X-GNOME-AutoRestart=true

View File

@ -22,7 +22,7 @@
<applyto>/desktop/gnome/shell/windows/button_layout</applyto>
<owner>gnome-shell</owner>
<type>string</type>
<default>:minimize,maximize,close</default>
<default>:close</default>
<locale name="C">
<short>Arrangement of buttons on the titlebar</short>
<long>
@ -44,19 +44,20 @@
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/windows/side_by_side_tiling</key>
<applyto>/desktop/gnome/shell/windows/side_by_side_tiling</applyto>
<key>/schemas/desktop/gnome/shell/windows/edge_tiling</key>
<applyto>/desktop/gnome/shell/windows/edge_tiling</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>enable side-by-side tiling when dropping windows on screen edges</short>
<short>enable edge tiling when dropping windows on screen edges</short>
<long>
If enabled, dropping windows on screen edges maximizes them
If enabled, dropping windows on vertical screen edges maximizes them
vertically and resizes them horizontally to cover half of the
available area.
available area. Dropping windows on the top screen edge maximizes them
completely.
This key overrides /apps/metacity/general/side_by_side_tiling when
This key overrides /apps/metacity/general/edge_tiling when
running GNOME Shell.
</long>
</locale>
@ -80,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,45 +0,0 @@
<Menu>
<DefaultLayout>
<Menuname>Apps</Menuname>
<Menuname>Games</Menuname>
<Menuname>Tools</Menuname>
</DefaultLayout>
<Name>Applications</Name>
<AppDir>/usr/local/share/applications</AppDir>
<DefaultAppDirs/>
<Menu>
<Name>Games</Name>
<Include>
<And>
<Category>Game</Category>
</And>
</Include>
</Menu>
<Menu>
<Name>Tools</Name>
<Include>
<Category>Development</Category>
<And>
<Category>System</Category>
<Not>
<Category>Settings</Category>
</Not>
</And>
<Category>Utility</Category>
</Include>
</Menu>
<Menu>
<Name>Apps</Name>
<OnlyUnallocated/>
<Include>
<And>
<Or>
<Category>Documentation</Category>
<Not><Category>Core</Category></Not>
</Or>
<Not><Category>Settings</Category></Not>
<Not><Category>Screensaver</Category></Not>
</And>
</Include>
</Menu>
</Menu>

View File

@ -1,80 +0,0 @@
<?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: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="18"
height="18"
viewBox="0 0 18 18"
enable-background="new 0 0 29 18"
xml:space="preserve"
sodipodi:version="0.32"
inkscape:version="0.46+devel"
sodipodi:docname="magnifier.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata16"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs14"><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 9 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="29 : 9 : 1"
inkscape:persp3d-origin="14.5 : 6 : 1"
id="perspective18" /></defs><sodipodi:namedview
inkscape:window-height="728"
inkscape:window-width="1103"
inkscape:pageshadow="2"
inkscape:pageopacity="1"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#000000"
id="base"
showgrid="true"
inkscape:zoom="27.260185"
inkscape:cx="9.5844061"
inkscape:cy="9.4435574"
inkscape:window-x="142"
inkscape:window-y="26"
inkscape:current-layer="Foreground"
inkscape:snap-global="true"
showguides="false"><inkscape:grid
type="xygrid"
id="grid2391"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" /></sodipodi:namedview>
<g
id="g5"
style="fill:#ffffff;fill-opacity:1"
transform="translate(-4,-0.023114)">
<path
d="m 6.246,13.98 c -0.319,-0.319 -0.319,-0.837 0,-1.157 L 9.963,9.106 c 0.319,-0.319 0.837,-0.319 1.157,0 l 0.786,0.787 c 0.32,0.319 0.32,0.837 0,1.157 l -3.717,3.717 c -0.32,0.319 -0.838,0.319 -1.157,0 l -0.786,-0.787 0,0 z"
id="path7"
style="fill:#ffffff;fill-opacity:1" />
<path
d="M 9.076,11.937"
id="path9"
style="fill:#ffffff;fill-opacity:1" />
</g>
<path
clip-rule="evenodd"
d="m 7.25,7.476886 c 0,-1.243 1.007,-2.25 2.2499998,-2.25 1.2430002,0 2.2500002,1.007 2.2500002,2.25 0,1.243 -1.007,2.25 -2.2500002,2.25 C 8.257,9.726886 7.25,8.719886 7.25,7.476886 z m -2.25,0 c 0,-2.485 2.015,-4.5 4.4999998,-4.5 2.4850002,0 4.5000002,2.015 4.5000002,4.5 0,2.4849998 -2.015,4.5 -4.5000002,4.5 C 7.015,11.976886 5,9.9618858 5,7.476886 z"
id="path11"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
</svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,133 +0,0 @@
<schemalist>
<enum id="MouseTrackingMode">
<value nick="none" value="0"/>
<value nick="centered" value="1"/>
<value nick="proportional" value="2"/>
<value nick="push" value="3"/>
</enum>
<enum id="ScreenPosition">
<value nick="none" value="0"/>
<value nick="full-screen" value="1"/>
<value nick="top-half" value="2"/>
<value nick="bottom-half" value="3"/>
<value nick="left-half" value="4"/>
<value nick="right-half" value="5"/>
</enum>
<schema id="org.gnome.accessibility.magnifier"
path="/desktop/gnome/accessibility/magnifier/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="show-magnifier" type="b">
<default>false</default>
<_summary>Show or hide the magnifier</_summary>
<_description>
Show or hide the magnifier and all of its zoom regions.
</_description>
</key>
<key name="mouse-tracking" enum="MouseTrackingMode">
<default>'proportional'</default>
<_summary>Mouse Tracking Mode</_summary>
<_description>
Determines the position of the magnified mouse image within the
magnified view and how it reacts to system mouse movement. The values
are
- none: no mouse tracking;
- centered: the mouse image is
displayed at the center of the zoom region (which also represents
the point under the system mouse) and the magnified contents are
scrolled as the system mouse moves;
- proportional: the position of the magnified mouse in the zoom region
is proportionally the same as the position of the system mouse on screen;
- push: when the magnified mouse intersects a boundary of the zoom
region, the contents are scrolled into view.
</_description>
</key>
<key name="screen-position" enum="ScreenPosition">
<default>'full-screen'</default>
<_summary>Screen position</_summary>
<_description>
The magnified view either fills the entire screen, or occupies the
top-half, bottom-half, left-half, or right-half of the screen.
</_description>
</key>
<key name="mag-factor" type="d">
<default>2.0</default>
<_summary>Magnification factor</_summary>
<_description>
The power of the magnification. A value of 1.0 means no magnification.
A value of 2.0 doubles the size.
</_description>
</key>
<key name="lens-mode" type="b">
<default>false</default>
<_summary>Enable lens mode</_summary>
<_description>
Whether the magnified view should be centered over the location of
the system mouse and move with it.
</_description>
</key>
<key name="scroll-at-edges" type="b">
<default>false</default>
<_summary>
Scroll magnified contents beyond the edges of the desktop
</_summary>
<_description>
For centered mouse tracking, when the system pointer is at or near the
edge of the screen, the magnified contents continue to scroll such that
the screen edge moves into the magnified view.
</_description>
</key>
<!-- Cross-hairs -->
<key name="show-cross-hairs" type="b">
<default>false</default>
<_summary>Show or hide crosshairs</_summary>
<_description>
Enables/disables display of crosshairs centered on the magnified
mouse sprite.
</_description>
</key>
<key name="cross-hairs-thickness" type="i">
<default>8</default>
<_summary>Thickness of the crosshairs</_summary>
<_description>
Width of the vertical and horizontal lines that make up the crosshairs.
</_description>
</key>
<key name="cross-hairs-color" type="s">
<default>'#ff0000'</default>
<_summary>Color of the crosshairs</_summary>
<_description>
The color of the the vertical and horizontal lines that make up
the crosshairs.
</_description>
</key>
<key name="cross-hairs-opacity" type="i">
<default>169</default>
<_summary>Opacity of the crosshairs</_summary>
<_description>
Determines the transparency of the crosshairs, from fully opaque
to fully transparent.
</_description>
</key>
<key name="cross-hairs-length" type="i">
<default>4096</default>
<_summary>Length of the crosshairs</_summary>
<_description>
Determines the length of the vertical and horizontal lines that
make up the crosshairs.
</_description>
</key>
<key name="cross-hairs-clip" type="b">
<default>false</default>
<_summary>Clip the crosshairs at the center</_summary>
<_description>
Determines whether the crosshairs intersect the magnified mouse sprite,
or are clipped such that the ends of the horizontal and vertical lines
surround the mouse image.
</_description>
</key>
</schema>
</schemalist>

View File

@ -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>
@ -30,23 +30,31 @@
</_description>
</key>
<key name="favorite-apps" type="as">
<default>[ 'mozilla-firefox.desktop', 'evolution.desktop', 'openoffice.org-writer.desktop' ]</default>
<default>[ 'mozilla-firefox.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'openoffice.org-writer.desktop', 'nautilus.desktop' ]</default>
<_summary>List of desktop file IDs for favorite applications</_summary>
<_description>
The applications corresponding to these identifiers
will be displayed in the favorites area.
</_description>
</key>
<key name="disabled-open-search-providers" type="as">
<default>[]</default>
<_summary>disabled OpenSearch providers</_summary>
</key>
<key name="command-history" type="as">
<default>[]</default>
<_summary>History for command (Alt-F2) dialog</_summary>
</key>
<key name="looking-glass-history" type="as">
<default>[]</default>
<_summary>History for the looking glass dialog</_summary>
</key>
<child name="clock" schema="org.gnome.shell.clock"/>
<child name="calendar" schema="org.gnome.shell.calendar"/>
<child name="recorder" schema="org.gnome.shell.recorder"/>
</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>
@ -57,58 +65,25 @@
</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="format" type="s">
<default l10n="messages" context="hour_format">
<!-- TRANSLATORS: This is the default hour format, choose ONLY '12-hour' or '24-hour'. -->
"12-hour"
</default>
<_summary>Hour format</_summary>
<_description>
This key specifies the hour format used by the panel clock.
Possible values are "12-hour", "24-hour", "unix" and "custom". If set
to "unix", the clock will display time in seconds since Epoch,
i.e. 1970-01-01. If set to "custom", the clock will display time
according to the format specified in the custom_format key. Note that
if set to either "unix" or "custom", the show_date and show_seconds
keys are ignored.
</_description>
<choices>
<choice value="12-hour"/>
<choice value="24-hour"/>
<choice value="unix"/>
<choice value="custom"/>
</choices>
</key>
<key name="custom-format" type="s">
<default>''</default>
<_summary>Custom format of the clock</_summary>
<_description>
This key specifies the format used by the panel clock when the format
key is set to "custom". You can use conversion specifiers understood
by strftime() to obtain a specific format. See the strftime() manual
for more information.
</_description>
</key>
<key name="show-seconds" type="b">
<default>false</default>
<_summary>Show time with seconds</_summary>
<_description>
If true and format is either "12-hour" or "24-hour", display seconds in time.
If true, display seconds in time.
</_description>
</key>
<key name="show-date" type="b">
<default>false</default>
<_summary>Show date in clock</_summary>
<_description>
If true and format is either "12-hour" or "24-hour",
display date in the clock, in addition to time.
If true, display date in the clock, in addition to time.
</_description>
</key>
</schema>
<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>
@ -130,11 +105,13 @@
take care of its own output - this might be used to send the output
to an icecast server via shout2send or similar. When unset or set
to an empty value, the default pipeline will be used. This is currently
'videorate ! theoraenc ! oggmux' and records to Ogg Theora.
'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux'
and records to WEBM using the VP8 codec. %T is used as a placeholder
for a guess at the optimal thread count on the system.
</_description>
</key>
<key name="file-extension" type="s">
<default>'ogv'</default>
<default>'webm'</default>
<_summary>File extension used for storing the screencast</_summary>
<_description>
The filename for recorded screencasts will be a unique filename

View File

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

View File

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

View File

@ -1,98 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="23"
height="15"
id="svg6375"
version="1.1"
inkscape:version="0.47pre4 r22446"
sodipodi:docname="New document 13">
<defs
id="defs6377">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective6383" />
<inkscape:perspective
id="perspective6366"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.197802"
inkscape:cx="16"
inkscape:cy="16"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1680"
inkscape:window-height="997"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata6380">
<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,-17)">
<g
style="display:inline"
id="g6243"
transform="translate(-986.28859,-658.2796)">
<rect
style="fill:#000000;fill-opacity:0.98770495;stroke:#666666;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
id="rect5318"
width="22"
height="14"
x="986.89801"
y="675.86743"
rx="0.49999979"
ry="0.5" />
<g
id="g5320"
transform="translate(402.77304,-12.882544)">
<path
id="path5322"
d="m 595.125,692.53048 0,6.43903"
style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<path
id="path5324"
d="m 598.34451,695.75 -6.43902,0"
style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

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

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

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

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="28"
height="25"
id="svg10621"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="calendar-today.svg">
<defs
id="defs10623">
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient34508-1-3"
id="radialGradient99561-1"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
cx="51"
cy="30"
fx="51"
fy="30"
r="42" />
<linearGradient
inkscape:collect="always"
id="linearGradient34508-1-3">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop34510-1-9" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop34512-4-5" />
</linearGradient>
<radialGradient
r="42"
fy="30"
fx="51"
cy="30"
cx="51"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
gradientUnits="userSpaceOnUse"
id="radialGradient10592"
xlink:href="#linearGradient34508-1-3"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient34508-1-3"
id="radialGradient3770"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
cx="51"
cy="30"
fx="51"
fy="30"
r="42" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient34508-1-3"
id="radialGradient3001"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
cx="51"
cy="30"
fx="51"
fy="30"
r="42" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient34508-1-3"
id="radialGradient3007"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
cx="51"
cy="30"
fx="51"
fy="30"
r="42" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient34508-1-3"
id="radialGradient3067"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
cx="51"
cy="30"
fx="51"
fy="30"
r="42" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient34508-1-3"
id="radialGradient3072"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
cx="51"
cy="30"
fx="51"
fy="30"
r="42" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient34508-1-3"
id="radialGradient2997"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
cx="51"
cy="30"
fx="51"
fy="30"
r="42" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:cx="8.3750933"
inkscape:cy="8.0837211"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1440"
inkscape:window-height="843"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata10626">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-469.08263,-536.99307)">
<g
id="g3003">
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png"
transform="matrix(0.43692393,0,0,1.3783114,460.60467,517.48289)"
sodipodi:end="6.2831853"
sodipodi:start="3.1415927"
d="M 9,29.999999 C 9.0000011,21.163443 27.804042,14 51.000002,14 74.195961,14 93,21.163444 93,30 l -42,0 z"
sodipodi:ry="16"
sodipodi:rx="42"
sodipodi:cy="30"
sodipodi:cx="51"
id="path34506-3"
style="opacity:0.4625;color:#000000;fill:url(#radialGradient2997);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<rect
y="558.85046"
x="468.96878"
height="3.1425927"
width="28.149134"
id="rect2996"
style="fill:#ffffff;fill-opacity:0.50196078;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

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

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

Before

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -9,23 +9,23 @@
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="23"
height="15"
id="svg5501"
width="10"
height="20"
id="svg10003"
version="1.1"
inkscape:version="0.47pre4 r22446"
sodipodi:docname="add-workspace.svg">
inkscape:version="0.47 r22583"
sodipodi:docname="filter-selected.svg">
<defs
id="defs5503">
id="defs10005">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective5509" />
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective10011" />
<inkscape:perspective
id="perspective5314"
id="perspective9998"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
@ -39,29 +39,27 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.197802"
inkscape:cx="-0.074583208"
inkscape:cy="16"
inkscape:zoom="5.5"
inkscape:cx="32"
inkscape:cy="10.181818"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1680"
inkscape:window-height="997"
inkscape:window-height="994"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1"
inkscape:snap-grids="true"
inkscape:snap-bbox="true" />
inkscape:window-maximized="1" />
<metadata
id="metadata5506">
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>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@ -69,24 +67,15 @@
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,-17)">
<g
style="display:inline"
id="g6239"
transform="translate(-953.97989,-657.32287)">
<rect
style="fill:#000000;fill-opacity:0.98770495;stroke:#666666;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
id="rect5318-6"
width="22"
height="14"
x="954.5"
y="675"
rx="0.49999979"
ry="0.5" />
<path
style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
d="m 968.71951,682 -6.43902,0"
id="path5324-5" />
</g>
transform="translate(0,-44)">
<path
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/app-picker.png"
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="rect34320"
d="m -0.18726572,54.181804 10.55634072,10.55636 10e-6,-21.11269 z"
style="opacity:0.21000001;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
</svg>

Before

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

File diff suppressed because it is too large Load Diff

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

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.1 r9760"
sodipodi:docname="panel-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.6594891"
inkscape:cy="5.7029946"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1440"
inkscape:window-height="843"
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 />
</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="3"
height="2"
x="9"
y="8" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30"
height="25"
id="svg10621"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="panel-button-highlight-narrow.svg">
<defs
id="defs10623">
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient34508-1-3"
id="radialGradient99561-1"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
cx="51"
cy="30"
fx="51"
fy="30"
r="42" />
<linearGradient
inkscape:collect="always"
id="linearGradient34508-1-3">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop34510-1-9" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop34512-4-5" />
</linearGradient>
<radialGradient
r="42"
fy="30"
fx="51"
cy="30"
cx="51"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
gradientUnits="userSpaceOnUse"
id="radialGradient10592"
xlink:href="#linearGradient34508-1-3"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="-171.36384"
inkscape:cy="-53.255157"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1440"
inkscape:window-height="843"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata10626">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-468.08632,-537.03477)">
<path
sodipodi:type="arc"
style="opacity:0.4625;color:#000000;fill:url(#radialGradient10592);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path34506-3"
sodipodi:cx="51"
sodipodi:cy="30"
sodipodi:rx="42"
sodipodi:ry="16"
d="M 9,29.999999 C 9.0000011,21.163443 27.804042,14 51.000002,14 74.195961,14 93,21.163444 93,30 l -42,0 z"
sodipodi:start="3.1415927"
sodipodi:end="6.2831853"
transform="matrix(0.35714286,0,0,1.5625,464.87203,515.15977)"
inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="84"
height="25"
id="svg10621"
version="1.1"
inkscape:version="0.48.0 r9654"
sodipodi:docname="panel-button-highlight-wide.svg">
<defs
id="defs10623">
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient34508-1-3"
id="radialGradient99561-1"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
cx="51"
cy="30"
fx="51"
fy="30"
r="42" />
<linearGradient
inkscape:collect="always"
id="linearGradient34508-1-3">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop34510-1-9" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop34512-4-5" />
</linearGradient>
<radialGradient
r="42"
fy="30"
fx="51"
cy="30"
cx="51"
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
gradientUnits="userSpaceOnUse"
id="radialGradient10592"
xlink:href="#linearGradient34508-1-3"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="-118.50071"
inkscape:cy="27.304508"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1440"
inkscape:window-height="843"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="1" />
<metadata
id="metadata10626">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-441.08632,-537.03477)">
<path
sodipodi:type="arc"
style="opacity:0.4625;color:#000000;fill:url(#radialGradient10592);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path34506-3"
sodipodi:cx="51"
sodipodi:cy="30"
sodipodi:rx="42"
sodipodi:ry="16"
d="M 9,29.999999 C 9.0000011,21.163443 27.804042,14 51.000002,14 74.195961,14 93,21.163444 93,30 l -42,0 z"
sodipodi:start="3.1415927"
sodipodi:end="6.2831853"
transform="matrix(1,0,0,1.5625,432.08632,515.15977)"
inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/motion/textures/panel.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

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

@ -5,8 +5,8 @@
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="74.01342"
height="74.006706"
width="119.97824"
height="119.97824"
id="svg7355"
version="1.1">
<defs
@ -66,7 +66,7 @@
</defs>
<g
id="layer1"
transform="translate(-266.21629,-168.11809)">
transform="matrix(1.6213276,0,0,1.6213276,-431.6347,-272.5745)">
<g
style="display:inline"
id="g30864"
@ -83,7 +83,8 @@
<path
id="rect34520"
d="m 84.506708,167.95508 c 6e-6,1.96759 -1.584022,3.55162 -3.551629,3.55163 l -65.910146,0 c -1.967608,-1e-5 -3.551648,-1.58402 -3.551643,-3.55164"
style="opacity:0.2;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1" />
style="opacity:0.2;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

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

@ -2,13 +2,51 @@
<!-- 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"
version="1.1"
width="96"
height="96"
id="svg25070">
id="svg25070"
inkscape:version="0.48.0 r9654"
sodipodi:docname="ws-switch-arrow-down.svg">
<metadata
id="metadata3353">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="718"
inkscape:window-height="480"
id="namedview3351"
showgrid="false"
inkscape:zoom="2.6979167"
inkscape:cx="48"
inkscape:cy="48"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="0"
inkscape:current-layer="svg25070" />
<defs
id="defs25072">
<linearGradient
@ -288,7 +326,7 @@
</filter>
</defs>
<g
transform="translate(0,48)"
transform="matrix(0,1,-1,0,48.0003,4.1307112e-7)"
id="layer1">
<g
transform="matrix(-2,0,0,2,-97.2497,-374.967)"
@ -297,35 +335,42 @@
<path
d="m -72.5,173.5 -14,14 14,14"
id="path3165-7-3"
style="color:#000000;fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
style="color:#000000;fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" />
</g>
<path
d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z"
transform="matrix(-3.34328,0,0,3.34328,-89.2797,-623.176)"
id="path4050-2-7-9-4"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible" />
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" />
<path
d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z"
transform="matrix(-3.34328,0,0,3.34328,-111.2797,-623.176)"
id="path4050-2-7-9-4-8"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible" />
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" />
<path
d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z"
transform="matrix(-2.86565,0,0,2.86565,-70.8457,-534.143)"
id="path4050-2-7-9-4-0"
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" />
<path
d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z"
transform="matrix(-2.86565,0,0,2.86565,-92.8457,-534.143)"
id="path4050-2-7-9-4-0-9"
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
inkscape:connector-curvature="0" />
<path
d="m 47.87528,-34.0295 c 1.53896,0.0448 3.0511,0.70928 4.125,1.8125 l 32.25,32.25 -32.25,32.25 c -2.2253,2.2253 -6.2747,2.2253 -8.5,0 -2.2253,-2.22528 -2.2253,-6.2747 0,-8.5 l 23.75,-23.75 -23.75,-23.75 c -1.73168,-1.6731 -2.295,-4.44228 -1.3546,-6.65894 0.94042,-2.21668 3.32312,-3.73604 5.7296,-3.65356 z"
id="path3165-7-3-1"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;opacity:0.35;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans" />
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;opacity:0.35;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans"
inkscape:connector-curvature="0" />
<path
d="m 41.8316,28.09418 c -0.014,-1.58898 0.54158,-3.18406 1.66868,-4.31118 l 23.75,-23.75 m -25.1046,-30.40894 c 0.94042,-2.21668 3.32312,-3.73604 5.7296,-3.65356 1.53896,0.0448 3.0511,0.70928 4.125,1.8125 l 32.25,32.25"
id="path3165-7-3-1-9"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans" />
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="96" height="96" id="svg25070" version="1.1" inkscape:version="0.47 r22583" sodipodi:docname="dark-arrow-larger.svg">
<defs id="defs25072">
<inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 24 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="48 : 24 : 1" inkscape:persp3d-origin="24 : 16 : 1" id="perspective25078"/>
<inkscape:perspective id="perspective24985" 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"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4034-0-4" id="linearGradient24957" gradientUnits="userSpaceOnUse" gradientTransform="translate(6)" x1="-86.552246" y1="185.439" x2="-83.37072" y2="197.31261"/>
<linearGradient inkscape:collect="always" id="linearGradient4034-0-4">
<stop style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" offset="0" id="stop4036-5-7"/>
<stop style="stop-color: rgb(186, 189, 182); stop-opacity: 1;" offset="1" id="stop4038-9-6"/>
</linearGradient>
<filter id="filter24765" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB">
<feColorMatrix id="feColorMatrix24767" type="saturate" values="1" result="fbSourceGraphic"/>
<feColorMatrix id="feColorMatrix24769" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
</filter>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4632-1-3-9-3-2" id="linearGradient24955" gradientUnits="userSpaceOnUse" gradientTransform="translate(-5)" x1="-74.520325" y1="169.06032" x2="-74.520325" y2="205.94189"/>
<linearGradient id="linearGradient4632-1-3-9-3-2">
<stop style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" offset="0" id="stop4634-1-8-3-9-0"/>
<stop id="stop4636-1-9-9-8-8" offset="0.0274937" style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"/>
<stop id="stop4638-8-3-9-6-6" offset="0.274937" style="stop-color: rgb(242, 242, 242); stop-opacity: 1;"/>
<stop id="stop4640-8-5-7-8-9" offset="0.38707438" style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"/>
<stop id="stop4642-5-41-9-6-9" offset="0.66528589" style="stop-color: rgb(217, 218, 216); stop-opacity: 1;"/>
<stop id="stop4644-5-2-7-9-2" offset="0.76745707" style="stop-color: rgb(223, 224, 221); stop-opacity: 1;"/>
<stop style="stop-color: rgb(240, 240, 240); stop-opacity: 1;" offset="1" id="stop4646-3-2-3-7-3"/>
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient4869-4-1" id="radialGradient24959" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)" cx="-33.412369" cy="185.74171" fx="-33.412369" fy="185.74171" r="2.3554697"/>
<linearGradient id="linearGradient4869-4-1">
<stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop4871-6-2"/>
<stop id="stop4879-7-4" offset="0.31807542" style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"/>
<stop id="stop4877-6-1" offset="0.74691135" style="stop-color: rgb(200, 201, 198); stop-opacity: 1;"/>
<stop style="stop-color: rgb(211, 215, 207); stop-opacity: 1;" offset="1" id="stop4873-1-0"/>
</linearGradient>
<filter id="filter25011" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB">
<feColorMatrix id="feColorMatrix25013" type="saturate" values="1" result="fbSourceGraphic"/>
<feColorMatrix id="feColorMatrix25015" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
</filter>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient4869-4-0" id="radialGradient24961" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)" cx="-33.412369" cy="185.74171" fx="-33.412369" fy="185.74171" r="2.3554697"/>
<linearGradient id="linearGradient4869-4-0">
<stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop4871-6-8"/>
<stop id="stop4879-7-5" offset="0.31807542" style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"/>
<stop id="stop4877-6-5" offset="0.74691135" style="stop-color: rgb(200, 201, 198); stop-opacity: 1;"/>
<stop style="stop-color: rgb(211, 215, 207); stop-opacity: 1;" offset="1" id="stop4873-1-4"/>
</linearGradient>
<filter id="filter25023" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB">
<feColorMatrix id="feColorMatrix25025" type="saturate" values="1" result="fbSourceGraphic"/>
<feColorMatrix id="feColorMatrix25027" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
</filter>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4941" id="linearGradient24963" gradientUnits="userSpaceOnUse" x1="-39.858727" y1="184.61784" x2="-38.244785" y2="188.84898"/>
<linearGradient inkscape:collect="always" id="linearGradient4941">
<stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop4943"/>
<stop style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" offset="1" id="stop4945"/>
</linearGradient>
<filter id="filter25033" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB">
<feColorMatrix id="feColorMatrix25035" type="saturate" values="1" result="fbSourceGraphic"/>
<feColorMatrix id="feColorMatrix25037" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
</filter>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4941-7" id="linearGradient24965" gradientUnits="userSpaceOnUse" x1="-39.858727" y1="184.61784" x2="-38.244785" y2="188.84898"/>
<linearGradient inkscape:collect="always" id="linearGradient4941-7">
<stop style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" offset="0" id="stop4943-2"/>
<stop style="stop-color: rgb(255, 255, 255); stop-opacity: 0;" offset="1" id="stop4945-5"/>
</linearGradient>
<filter id="filter25043" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB">
<feColorMatrix id="feColorMatrix25045" type="saturate" values="1" result="fbSourceGraphic"/>
<feColorMatrix id="feColorMatrix25047" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
</filter>
<filter id="filter25049" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB">
<feColorMatrix id="feColorMatrix25051" type="saturate" values="1" result="fbSourceGraphic"/>
<feColorMatrix id="feColorMatrix25053" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
</filter>
<filter id="filter25055" inkscape:label="Invert" x="0" y="0" width="1" height="1" inkscape:menu="Color" inkscape:menu-tooltip="Invert colors" color-interpolation-filters="sRGB">
<feColorMatrix id="feColorMatrix25057" type="saturate" values="1" result="fbSourceGraphic"/>
<feColorMatrix id="feColorMatrix25059" in="fbSourceGraphic" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
</filter>
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="2.8284271" inkscape:cx="48.631638" inkscape:cy="57.536221" inkscape:current-layer="layer1" showgrid="true" inkscape:grid-bbox="true" inkscape:document-units="px" inkscape:window-width="1200" inkscape:window-height="851" inkscape:window-x="0" inkscape:window-y="52" inkscape:window-maximized="0"/>
<metadata id="metadata25075">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer" transform="translate(0, 48)">
<g id="g4030-1-8" transform="matrix(2, 0, 0, 2, 193.25, -374.967)" style="stroke: rgb(0, 0, 0); display: inline; stroke-opacity: 1;">
<path sodipodi:nodetypes="ccc" id="path3165-7-3" d="m -72.5,173.5 -14,14 14,14" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 7; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-opacity: 1; stroke-dasharray: none; stroke-dashoffset: 0pt; visibility: visible; display: inline;"/>
</g>
<path sodipodi:type="arc" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 0.523439; visibility: visible; display: inline;" id="path4050-2-7-9-4" sodipodi:cx="-38.59375" sodipodi:cy="186.40625" sodipodi:rx="2.09375" sodipodi:ry="2.09375" d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" transform="matrix(3.34328, 0, 0, 3.34328, 185.28, -623.176)"/>
<path sodipodi:type="arc" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: rgb(0, 0, 0); fill-opacity: 1; fill-rule: nonzero; stroke: none; stroke-width: 0.523439; visibility: visible; display: inline;" id="path4050-2-7-9-4-8" sodipodi:cx="-38.59375" sodipodi:cy="186.40625" sodipodi:rx="2.09375" sodipodi:ry="2.09375" d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" transform="matrix(3.34328, 0, 0, 3.34328, 207.28, -623.176)"/>
<path sodipodi:type="arc" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 0.697921; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-opacity: 1; stroke-dasharray: none; stroke-dashoffset: 0pt; visibility: visible; display: inline;" id="path4050-2-7-9-4-0" sodipodi:cx="-38.59375" sodipodi:cy="186.40625" sodipodi:rx="2.09375" sodipodi:ry="2.09375" d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" transform="matrix(2.86565, 0, 0, 2.86565, 166.846, -534.143)"/>
<path sodipodi:type="arc" style="overflow: visible; marker: none; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 0.697921; stroke-linecap: round; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-opacity: 1; stroke-dasharray: none; stroke-dashoffset: 0pt; visibility: visible; display: inline;" id="path4050-2-7-9-4-0-9" sodipodi:cx="-38.59375" sodipodi:cy="186.40625" sodipodi:rx="2.09375" sodipodi:ry="2.09375" d="m -36.5,186.40625 a 2.09375,2.09375 0 1 1 -4.1875,0 2.09375,2.09375 0 1 1 4.1875,0 z" transform="matrix(2.86565, 0, 0, 2.86565, 188.846, -534.143)"/>
<path style="overflow: visible; marker: none; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; text-indent: 0pt; text-align: start; text-decoration: none; line-height: normal; letter-spacing: normal; word-spacing: normal; text-transform: none; direction: ltr; text-anchor: start; opacity: 0.35; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 1; stroke-miterlimit: 4; stroke-dasharray: none; visibility: visible; display: inline; font-family: Bitstream Vera Sans; stroke-opacity: 1;" d="m 317.06251,365.96875 c -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 l -16.125,16.125 16.125,16.125 c 1.11265,1.11265 3.13735,1.11265 4.25,0 1.11265,-1.11264 1.11265,-3.13735 0,-4.25 l -11.875,-11.875 11.875,-11.875 c 0.86584,-0.83655 1.1475,-2.22114 0.6773,-3.32947 -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 z" id="path3165-7-3-1" sodipodi:nodetypes="ccccscccsc" transform="matrix(2, 0, 0, 2, -586, -765.967)"/>
<path style="overflow: visible; marker: none; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; text-indent: 0pt; text-align: start; text-decoration: none; line-height: normal; letter-spacing: normal; word-spacing: normal; text-transform: none; direction: ltr; text-anchor: start; color: rgb(0, 0, 0); fill: none; stroke: rgb(0, 0, 0); stroke-width: 1; stroke-linecap: round; stroke-miterlimit: 4; stroke-dasharray: none; visibility: visible; display: inline; font-family: Bitstream Vera Sans; stroke-opacity: 1;" d="m 320.08435,397.03059 c 0.007,-0.79449 -0.27079,-1.59203 -0.83434,-2.15559 L 307.37501,383 m 12.5523,-15.20447 c -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 L 298.87501,383" id="path3165-7-3-1-9" sodipodi:nodetypes="ccccccc" transform="matrix(2, 0, 0, 2, -586, -765.967)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,447 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="96"
height="96"
id="svg25070"
version="1.1"
inkscape:version="0.48.0 r9654"
sodipodi:docname="ws-switch-arrow-up.svg">
<defs
id="defs25072">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 24 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="48 : 24 : 1"
inkscape:persp3d-origin="24 : 16 : 1"
id="perspective25078" />
<inkscape:perspective
id="perspective24985"
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" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4034-0-4"
id="linearGradient24957"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(6)"
x1="-86.552246"
y1="185.439"
x2="-83.37072"
y2="197.31261" />
<linearGradient
inkscape:collect="always"
id="linearGradient4034-0-4">
<stop
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"
offset="0"
id="stop4036-5-7" />
<stop
style="stop-color: rgb(186, 189, 182); stop-opacity: 1;"
offset="1"
id="stop4038-9-6" />
</linearGradient>
<filter
id="filter24765"
inkscape:label="Invert"
x="0"
y="0"
width="1"
height="1"
inkscape:menu="Color"
inkscape:menu-tooltip="Invert colors"
color-interpolation-filters="sRGB">
<feColorMatrix
id="feColorMatrix24767"
type="saturate"
values="1"
result="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix24769"
in="fbSourceGraphic"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4632-1-3-9-3-2"
id="linearGradient24955"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-5)"
x1="-74.520325"
y1="169.06032"
x2="-74.520325"
y2="205.94189" />
<linearGradient
id="linearGradient4632-1-3-9-3-2">
<stop
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;"
offset="0"
id="stop4634-1-8-3-9-0" />
<stop
id="stop4636-1-9-9-8-8"
offset="0.0274937"
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;" />
<stop
id="stop4638-8-3-9-6-6"
offset="0.274937"
style="stop-color: rgb(242, 242, 242); stop-opacity: 1;" />
<stop
id="stop4640-8-5-7-8-9"
offset="0.38707438"
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" />
<stop
id="stop4642-5-41-9-6-9"
offset="0.66528589"
style="stop-color: rgb(217, 218, 216); stop-opacity: 1;" />
<stop
id="stop4644-5-2-7-9-2"
offset="0.76745707"
style="stop-color: rgb(223, 224, 221); stop-opacity: 1;" />
<stop
style="stop-color: rgb(240, 240, 240); stop-opacity: 1;"
offset="1"
id="stop4646-3-2-3-7-3" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4869-4-1"
id="radialGradient24959"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)"
cx="-33.412369"
cy="185.74171"
fx="-33.412369"
fy="185.74171"
r="2.3554697" />
<linearGradient
id="linearGradient4869-4-1">
<stop
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
offset="0"
id="stop4871-6-2" />
<stop
id="stop4879-7-4"
offset="0.31807542"
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" />
<stop
id="stop4877-6-1"
offset="0.74691135"
style="stop-color: rgb(200, 201, 198); stop-opacity: 1;" />
<stop
style="stop-color: rgb(211, 215, 207); stop-opacity: 1;"
offset="1"
id="stop4873-1-0" />
</linearGradient>
<filter
id="filter25011"
inkscape:label="Invert"
x="0"
y="0"
width="1"
height="1"
inkscape:menu="Color"
inkscape:menu-tooltip="Invert colors"
color-interpolation-filters="sRGB">
<feColorMatrix
id="feColorMatrix25013"
type="saturate"
values="1"
result="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix25015"
in="fbSourceGraphic"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
</filter>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4869-4-0"
id="radialGradient24961"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0075, 0, 0, 1.0075, -5.4544, -1.25141)"
cx="-33.412369"
cy="185.74171"
fx="-33.412369"
fy="185.74171"
r="2.3554697" />
<linearGradient
id="linearGradient4869-4-0">
<stop
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
offset="0"
id="stop4871-6-8" />
<stop
id="stop4879-7-5"
offset="0.31807542"
style="stop-color: rgb(238, 238, 236); stop-opacity: 1;" />
<stop
id="stop4877-6-5"
offset="0.74691135"
style="stop-color: rgb(200, 201, 198); stop-opacity: 1;" />
<stop
style="stop-color: rgb(211, 215, 207); stop-opacity: 1;"
offset="1"
id="stop4873-1-4" />
</linearGradient>
<filter
id="filter25023"
inkscape:label="Invert"
x="0"
y="0"
width="1"
height="1"
inkscape:menu="Color"
inkscape:menu-tooltip="Invert colors"
color-interpolation-filters="sRGB">
<feColorMatrix
id="feColorMatrix25025"
type="saturate"
values="1"
result="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix25027"
in="fbSourceGraphic"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4941"
id="linearGradient24963"
gradientUnits="userSpaceOnUse"
x1="-39.858727"
y1="184.61784"
x2="-38.244785"
y2="188.84898" />
<linearGradient
inkscape:collect="always"
id="linearGradient4941">
<stop
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
offset="0"
id="stop4943" />
<stop
style="stop-color: rgb(255, 255, 255); stop-opacity: 0;"
offset="1"
id="stop4945" />
</linearGradient>
<filter
id="filter25033"
inkscape:label="Invert"
x="0"
y="0"
width="1"
height="1"
inkscape:menu="Color"
inkscape:menu-tooltip="Invert colors"
color-interpolation-filters="sRGB">
<feColorMatrix
id="feColorMatrix25035"
type="saturate"
values="1"
result="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix25037"
in="fbSourceGraphic"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
</filter>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4941-7"
id="linearGradient24965"
gradientUnits="userSpaceOnUse"
x1="-39.858727"
y1="184.61784"
x2="-38.244785"
y2="188.84898" />
<linearGradient
inkscape:collect="always"
id="linearGradient4941-7">
<stop
style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
offset="0"
id="stop4943-2" />
<stop
style="stop-color: rgb(255, 255, 255); stop-opacity: 0;"
offset="1"
id="stop4945-5" />
</linearGradient>
<filter
id="filter25043"
inkscape:label="Invert"
x="0"
y="0"
width="1"
height="1"
inkscape:menu="Color"
inkscape:menu-tooltip="Invert colors"
color-interpolation-filters="sRGB">
<feColorMatrix
id="feColorMatrix25045"
type="saturate"
values="1"
result="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix25047"
in="fbSourceGraphic"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
</filter>
<filter
id="filter25049"
inkscape:label="Invert"
x="0"
y="0"
width="1"
height="1"
inkscape:menu="Color"
inkscape:menu-tooltip="Invert colors"
color-interpolation-filters="sRGB">
<feColorMatrix
id="feColorMatrix25051"
type="saturate"
values="1"
result="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix25053"
in="fbSourceGraphic"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
</filter>
<filter
id="filter25055"
inkscape:label="Invert"
x="0"
y="0"
width="1"
height="1"
inkscape:menu="Color"
inkscape:menu-tooltip="Invert colors"
color-interpolation-filters="sRGB">
<feColorMatrix
id="feColorMatrix25057"
type="saturate"
values="1"
result="fbSourceGraphic" />
<feColorMatrix
id="feColorMatrix25059"
in="fbSourceGraphic"
values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="-12.356322"
inkscape:cy="57.536221"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1200"
inkscape:window-height="840"
inkscape:window-x="0"
inkscape:window-y="26"
inkscape:window-maximized="0" />
<metadata
id="metadata25075">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0, 48)">
<g
id="g3181"
transform="matrix(0,1,-1,0,48.0003,-48)">
<g
style="stroke:#000000;stroke-opacity:1;display:inline"
transform="matrix(2,0,0,2,193.25,-374.967)"
id="g4030-1-8">
<path
style="color:#000000;fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
d="m -72.5,173.5 -14,14 14,14"
id="path3165-7-3"
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0" />
</g>
<path
transform="matrix(3.34328,0,0,3.34328,185.28,-623.176)"
d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z"
sodipodi:ry="2.09375"
sodipodi:rx="2.09375"
sodipodi:cy="186.40625"
sodipodi:cx="-38.59375"
id="path4050-2-7-9-4"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible"
sodipodi:type="arc" />
<path
transform="matrix(3.34328,0,0,3.34328,207.28,-623.176)"
d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z"
sodipodi:ry="2.09375"
sodipodi:rx="2.09375"
sodipodi:cy="186.40625"
sodipodi:cx="-38.59375"
id="path4050-2-7-9-4-8"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.52343899;marker:none;visibility:visible;display:inline;overflow:visible"
sodipodi:type="arc" />
<path
transform="matrix(2.86565,0,0,2.86565,166.846,-534.143)"
d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z"
sodipodi:ry="2.09375"
sodipodi:rx="2.09375"
sodipodi:cy="186.40625"
sodipodi:cx="-38.59375"
id="path4050-2-7-9-4-0"
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
sodipodi:type="arc" />
<path
transform="matrix(2.86565,0,0,2.86565,188.846,-534.143)"
d="m -36.5,186.40625 c 0,1.15635 -0.937404,2.09375 -2.09375,2.09375 -1.156346,0 -2.09375,-0.9374 -2.09375,-2.09375 0,-1.15635 0.937404,-2.09375 2.09375,-2.09375 1.156346,0 2.09375,0.9374 2.09375,2.09375 z"
sodipodi:ry="2.09375"
sodipodi:rx="2.09375"
sodipodi:cy="186.40625"
sodipodi:cx="-38.59375"
id="path4050-2-7-9-4-0-9"
style="color:#000000;fill:none;stroke:#000000;stroke-width:0.69792098;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
sodipodi:type="arc" />
<path
transform="matrix(2,0,0,2,-586,-765.967)"
sodipodi:nodetypes="ccccscccsc"
id="path3165-7-3-1"
d="m 317.06251,365.96875 c -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 l -16.125,16.125 16.125,16.125 c 1.11265,1.11265 3.13735,1.11265 4.25,0 1.11265,-1.11264 1.11265,-3.13735 0,-4.25 l -11.875,-11.875 11.875,-11.875 c 0.86584,-0.83655 1.1475,-2.22114 0.6773,-3.32947 -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 z"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;opacity:0.35;color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans"
inkscape:connector-curvature="0" />
<path
transform="matrix(2,0,0,2,-586,-765.967)"
sodipodi:nodetypes="ccccccc"
id="path3165-7-3-1-9"
d="m 320.08435,397.03059 c 0.007,-0.79449 -0.27079,-1.59203 -0.83434,-2.15559 L 307.37501,383 m 12.5523,-15.20447 c -0.47021,-1.10834 -1.66156,-1.86802 -2.8648,-1.82678 -0.76948,0.0224 -1.52555,0.35464 -2.0625,0.90625 L 298.87501,383"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0pt;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;text-anchor:start;color:#000000;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;font-family:Bitstream Vera Sans"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 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" />
-->
@ -33,7 +49,7 @@
<foaf:Person>
<foaf:name>Colin Walters</foaf:name>
<foaf:mbox rdf:resource="mailto:walters@verbum.org" />
<gnome:userid>cwalters</gnome:userid>
<gnome:userid>walters</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>

View File

@ -2,27 +2,30 @@
jsdir = $(pkgdatadir)/js
nobase_dist_js_DATA = \
misc/config.js \
misc/docInfo.js \
misc/fileUtils.js \
misc/format.js \
misc/gnomeSession.js \
misc/history.js \
misc/modemManager.js \
misc/params.js \
misc/telepathy.js \
misc/utils.js \
misc/util.js \
perf/core.js \
prefs/clockPreferences.js \
ui/altTab.js \
ui/appDisplay.js \
ui/appFavorites.js \
ui/boxpointer.js \
ui/calendar.js \
ui/chrome.js \
ui/ctrlAltTab.js \
ui/dash.js \
ui/dateMenu.js \
ui/dnd.js \
ui/docDisplay.js \
ui/endSessionDialog.js \
ui/environment.js \
ui/extensionSystem.js \
ui/genericDisplay.js \
ui/iconGrid.js \
ui/lightbox.js \
ui/link.js \
@ -31,11 +34,13 @@ nobase_dist_js_DATA = \
ui/magnifierDBus.js \
ui/main.js \
ui/messageTray.js \
ui/modalDialog.js \
ui/notificationDaemon.js \
ui/overview.js \
ui/panel.js \
ui/panelMenu.js \
ui/placeDisplay.js \
ui/polkitAuthenticationAgent.js \
ui/popupMenu.js \
ui/runDialog.js \
ui/scripting.js \
@ -45,13 +50,18 @@ nobase_dist_js_DATA = \
ui/statusIconDispatcher.js \
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 \
ui/telepathyClient.js \
ui/tweener.js \
ui/viewSelector.js \
ui/windowAttentionHandler.js \
ui/windowManager.js \
ui/workspace.js \
ui/workspaceThumbnail.js \
ui/workspacesView.js \
ui/workspaceSwitcherPopup.js
ui/workspaceSwitcherPopup.js \
ui/xdndHandler.js

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

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

View File

@ -29,8 +29,8 @@ DocInfo.prototype = {
return St.TextureCache.get_default().load_recent_thumbnail(size, this.recentInfo);
},
launch : function() {
Shell.DocSystem.get_default().open(this.recentInfo);
launch : function(workspaceIndex) {
Shell.DocSystem.get_default().open(this.recentInfo, workspaceIndex);
},
matchTerms: function(terms) {
@ -60,8 +60,7 @@ function getDocManager() {
}
/**
* DocManager wraps the DocSystem, primarily to expose DocInfo objects
* which conform to the GenericDisplay item API.
* DocManager wraps the DocSystem, primarily to expose DocInfo objects.
*/
function DocManager() {
this._init();

View File

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

115
js/misc/history.js Normal file
View File

@ -0,0 +1,115 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Lang = imports.lang;
const Signals = imports.signals;
const Clutter = imports.gi.Clutter;
const Params = imports.misc.params;
const DEFAULT_LIMIT = 512;
function HistoryManager(params) {
this._init(params);
}
HistoryManager.prototype = {
_init: function(params) {
params = Params.parse(params, { gsettingsKey: null,
limit: DEFAULT_LIMIT,
entry: null });
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() {
this._history = global.settings.get_strv(this._key);
this._historyIndex = this._history.length;
},
prevItem: function(text) {
if (this._historyIndex <= 0)
return text;
if (text)
this._history[this._historyIndex] = text;
this._historyIndex--;
return this._indexChanged();
},
nextItem: function(text) {
if (this._historyIndex >= this._history.length)
return text;
if (text)
this._history[this._historyIndex] = text;
this._historyIndex++;
return this._indexChanged();
},
lastItem: function() {
if (this._historyIndex != this._history.length) {
this._historyIndex = this._history.length;
this._indexChanged();
}
return this._historyIndex[this._history.length];
},
addItem: function(input) {
if (this._history.length == 0 ||
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;
},
_save: function() {
if (this._history.length > this._limit)
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

@ -1,359 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const DBus = imports.dbus;
// D-Bus utils
function nameToPath(name) {
return '/' + name.replace(/\./g, '/');
};
function pathToName(path) {
if (path[0] != '/')
throw new Error('not a D-Bus path: ' + path);
return path.substr(1).replace(/\//g, '.');
};
// This is tp_escape_as_identifier() from telepathy-glib
function escapeAsIdentifier(name) {
if (!name)
return '_';
// first char is replaced with _XX if it's non-alpha,
// later chars are replaced with _XX if they're non-alphanumeric
if (name.length == 1) {
return name.replace(/[^a-zA-Z]/, _hexEscape);
} else {
return (name[0].replace(/[^a-zA-Z]/, _hexEscape) +
name.substring(1).replace(/[^a-zA-Z0-9]/g, _hexEscape));
}
}
function _hexEscape(ch) {
return '_' + ch.charCodeAt(0).toString(16);
}
// Telepathy D-Bus interface definitions. Note that most of these are
// incomplete, and only cover the methods/properties/signals that
// we're currently using.
const TELEPATHY = 'org.freedesktop.Telepathy';
const CLIENT_NAME = TELEPATHY + '.Client';
const ClientIface = {
name: CLIENT_NAME,
properties: [
{ name: 'Interfaces',
signature: 'as',
access: 'read' }
]
};
const CLIENT_APPROVER_NAME = TELEPATHY + '.Client.Approver';
const ClientApproverIface = {
name: CLIENT_APPROVER_NAME,
methods: [
{ name: 'AddDispatchOperation',
inSignature: 'a(oa{sv})oa{sv}',
outSignature: '' }
],
properties: [
{ name: 'ApproverChannelFilter',
signature: 'aa{sv}',
access: 'read' }
]
};
const CLIENT_HANDLER_NAME = TELEPATHY + '.Client.Handler';
const ClientHandlerIface = {
name: CLIENT_HANDLER_NAME,
methods: [
{ name: 'HandleChannels',
inSignature: 'ooa(oa{sv})aota{sv}',
outSignature: '' }
],
properties: [
{ name: 'HandlerChannelFilter',
signature: 'aa{sv}',
access: 'read' }
]
};
const CLIENT_OBSERVER_NAME = TELEPATHY + '.Client.Observer';
const ClientObserverIface = {
name: CLIENT_OBSERVER_NAME,
methods: [
{ name: 'ObserveChannels',
inSignature: 'ooa(oa{sv})oaoa{sv}',
outSignature: '' }
],
properties: [
{ name: 'ObserverChannelFilter',
signature: 'aa{sv}',
access: 'read' }
]
};
const CHANNEL_DISPATCH_OPERATION_NAME = TELEPATHY + '.ChannelDispatchOperation';
const ChannelDispatchOperationIface = {
name: CHANNEL_DISPATCH_OPERATION_NAME,
methods: [
{ name: 'HandleWith',
inSignature: 's',
outSignature: '' },
{ name: 'Claim',
inSignature: '',
outSignature: '' }
]
};
let ChannelDispatchOperation = DBus.makeProxyClass(ChannelDispatchOperationIface);
const CONNECTION_NAME = TELEPATHY + '.Connection';
const ConnectionIface = {
name: CONNECTION_NAME,
signals: [
{ name: 'StatusChanged',
inSignature: 'uu' }
]
};
let Connection = DBus.makeProxyClass(ConnectionIface);
const ConnectionStatus = {
CONNECTED: 0,
CONNECTING: 1,
DISCONNECTED: 2
};
const CONNECTION_ALIASING_NAME = CONNECTION_NAME + '.Interface.Aliasing';
const ConnectionAliasingIface = {
name: CONNECTION_ALIASING_NAME,
methods: [
{ name: 'RequestAliases',
inSignature: 'au',
outSignature: 'as'
}
],
signals: [
{ name: 'AliasesChanged',
inSignature: 'a(us)' }
]
};
let ConnectionAliasing = DBus.makeProxyClass(ConnectionAliasingIface);
const CONNECTION_AVATARS_NAME = CONNECTION_NAME + '.Interface.Avatars';
const ConnectionAvatarsIface = {
name: CONNECTION_AVATARS_NAME,
methods: [
{ name: 'GetKnownAvatarTokens',
inSignature: 'au',
outSignature: 'a{us}'
},
{ name: 'RequestAvatars',
inSignature: 'au',
outSignature: ''
}
],
signals: [
{ name: 'AvatarRetrieved',
inSignature: 'usays'
},
{ name: 'AvatarUpdated',
inSignature: 'us'
}
]
};
let ConnectionAvatars = DBus.makeProxyClass(ConnectionAvatarsIface);
const CONNECTION_CONTACTS_NAME = CONNECTION_NAME + '.Interface.Contacts';
const ConnectionContactsIface = {
name: CONNECTION_CONTACTS_NAME,
methods: [
{ name: 'GetContactAttributes',
inSignature: 'auasb',
outSignature: 'a{ua{sv}}'
}
]
};
let ConnectionContacts = DBus.makeProxyClass(ConnectionContactsIface);
const CONNECTION_REQUESTS_NAME = CONNECTION_NAME + '.Interface.Requests';
const ConnectionRequestsIface = {
name: CONNECTION_REQUESTS_NAME,
methods: [
{ name: 'CreateChannel',
inSignature: 'a{sv}',
outSignature: 'oa{sv}'
},
{ name: 'EnsureChannel',
inSignature: 'a{sv}',
outSignature: 'boa{sv}'
}
],
properties: [
{ name: 'Channels',
signature: 'a(oa{sv})',
access: 'read' }
],
signals: [
{ name: 'NewChannels',
inSignature: 'a(oa{sv})'
},
{ name: 'ChannelClosed',
inSignature: 'o'
}
]
};
let ConnectionRequests = DBus.makeProxyClass(ConnectionRequestsIface);
const CONNECTION_SIMPLE_PRESENCE_NAME = CONNECTION_NAME + '.Interface.SimplePresence';
const ConnectionSimplePresenceIface = {
name: CONNECTION_SIMPLE_PRESENCE_NAME,
methods: [
{ name: 'SetPresence',
inSignature: 'ss'
},
{ name: 'GetPresences',
inSignature: 'au',
outSignature: 'a{u(uss)}'
}
],
signals: [
{ name: 'PresencesChanged',
inSignature: 'a{u(uss)}' }
]
};
let ConnectionSimplePresence = DBus.makeProxyClass(ConnectionSimplePresenceIface);
const ConnectionPresenceType = {
UNSET: 0,
OFFLINE: 1,
AVAILABLE: 2,
AWAY: 3,
EXTENDED_AWAY: 4,
HIDDEN: 5,
BUSY: 6,
UNKNOWN: 7,
ERROR: 8
};
const HandleType = {
NONE: 0,
CONTACT: 1,
ROOM: 2,
LIST: 3,
GROUP: 4
};
const CHANNEL_NAME = TELEPATHY + '.Channel';
const ChannelIface = {
name: CHANNEL_NAME,
signals: [
{ name: 'Closed',
inSignature: '' }
]
};
let Channel = DBus.makeProxyClass(ChannelIface);
const CHANNEL_TEXT_NAME = CHANNEL_NAME + '.Type.Text';
const ChannelTextIface = {
name: CHANNEL_TEXT_NAME,
methods: [
{ name: 'ListPendingMessages',
inSignature: 'b',
outSignature: 'a(uuuuus)'
},
{ name: 'AcknowledgePendingMessages',
inSignature: 'au',
outSignature: ''
},
{ name: 'Send',
inSignature: 'us',
outSignature: ''
}
],
signals: [
{ name: 'Received',
inSignature: 'uuuuus' }
]
};
let ChannelText = DBus.makeProxyClass(ChannelTextIface);
const ChannelTextMessageType = {
NORMAL: 0,
ACTION: 1,
NOTICE: 2,
AUTO_REPLY: 3,
DELIVERY_REPORT: 4
};
const CHANNEL_CONTACT_LIST_NAME = CHANNEL_NAME + '.Type.ContactList';
// There is no interface associated with ContactList; it's just a
// special kind of Channel.Interface.Group
const CHANNEL_GROUP_NAME = CHANNEL_NAME + '.Interface.Group';
const ChannelGroupIface = {
name: CHANNEL_GROUP_NAME,
properties: [
{ name: 'Members',
signature: 'au',
access: 'read' }
],
signals: [
{ name: 'MembersChanged',
inSignature: 'sauauauauuu' }
]
};
let ChannelGroup = DBus.makeProxyClass(ChannelGroupIface);
const ACCOUNT_MANAGER_NAME = TELEPATHY + '.AccountManager';
const AccountManagerIface = {
name: ACCOUNT_MANAGER_NAME,
properties: [
{ name: 'ValidAccounts',
signature: 'ao',
access: 'read' }
],
signals: [
{ name: 'AccountValidityChanged',
inSignature: 'ob' }
]
};
let AccountManager = DBus.makeProxyClass(AccountManagerIface);
const ACCOUNT_NAME = TELEPATHY + '.Account';
const AccountIface = {
name: ACCOUNT_NAME,
properties: [
{ name: 'Connection',
signature: 'o',
access: 'read' }
]
};
let Account = DBus.makeProxyClass(AccountIface);
const CHANNEL_DISPATCHER_NAME = TELEPATHY + '.ChannelDispatcher';
const ChannelDispatcherIface = {
name: CHANNEL_DISPATCHER_NAME,
methods: [
{ name: 'EnsureChannel',
inSignature: 'oa{sv}xs',
outSignature: 'o' }
]
};
let ChannelDispatcher = DBus.makeProxyClass(ChannelDispatcherIface);
const CHANNEL_REQUEST_NAME = TELEPATHY + '.ChannelRequest';
const ChannelRequestIface = {
name: CHANNEL_REQUEST_NAME,
methods: [
{ name: 'Proceed',
inSignature: '',
outSignature: '' }
],
signals: [
{ name: 'Failed',
signature: 'ss' },
{ name: 'Succeeded',
signature: '' }
]
};
let ChannelRequest = DBus.makeProxyClass(ChannelRequestIface);

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

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

@ -1,19 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
/* http://daringfireball.net/2010/07/improved_regex_for_matching_urls */
const _urlRegexp = /\b(([a-z][\w-]+:(\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)([^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/gi;
// findUrls:
// @str: string to find URLs in
//
// Searches @str for URLs and returns an array of objects with %url
// properties showing the matched URL string, and %pos properties indicating
// the position within @str where the URL was found.
//
// Return value: the list of match objects, as described above
function findUrls(str) {
let res = [], match;
while ((match = _urlRegexp.exec(str)))
res.push({ url: match[0], pos: match.index });
return res;
}

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

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

View File

@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
@ -15,6 +16,8 @@ const POPUP_APPICON_SIZE = 96;
const POPUP_SCROLL_TIME = 0.10; // seconds
const POPUP_FADE_TIME = 0.1; // seconds
const APP_ICON_HOVER_TIMEOUT = 200; // milliseconds
const DISABLE_HOVER_TIMEOUT = 500; // milliseconds
const THUMBNAIL_DEFAULT_SIZE = 256;
@ -34,7 +37,8 @@ function AltTabPopup() {
AltTabPopup.prototype = {
_init : function() {
this.actor = new Shell.GenericContainer({ name: 'altTabPopup',
reactive: true });
reactive: true,
visible: false });
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
@ -49,6 +53,8 @@ AltTabPopup.prototype = {
this._thumbnailTimeoutId = 0;
this._motionTimeoutId = 0;
this.thumbnailsVisible = false;
// Initially disable hover so we ignore the enter-event if
// the switcher appears underneath the current pointer location
this._disableHover();
@ -81,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);
@ -115,7 +121,7 @@ AltTabPopup.prototype = {
}
},
show : function(backward) {
show : function(backward, switch_group) {
let tracker = Shell.WindowTracker.get_default();
let apps = tracker.get_running_apps ('');
@ -126,13 +132,13 @@ AltTabPopup.prototype = {
return false;
this._haveModal = true;
this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside));
this.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
this._appSwitcher = new AppSwitcher(apps);
this._appSwitcher = new AppSwitcher(apps, this);
this.actor.add_actor(this._appSwitcher.actor);
this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated));
this._appSwitcher.connect('item-entered', Lang.bind(this, this._appEntered));
@ -140,7 +146,16 @@ AltTabPopup.prototype = {
this._appIcons = this._appSwitcher.icons;
// Make the initial selection
if (this._appIcons.length == 1) {
if (switch_group) {
if (backward) {
this._select(0, this._appIcons[0].cachedWindows.length - 1);
} else {
if (this._appIcons[0].cachedWindows.length > 1)
this._select(0, 1);
else
this._select(0, 0);
}
} else if (this._appIcons.length == 1) {
if (!backward && this._appIcons[0].cachedWindows.length > 1) {
// For compatibility with the multi-app case below
this._select(0, 1, true);
@ -212,41 +227,38 @@ AltTabPopup.prototype = {
_keyPressEvent : function(actor, event) {
let keysym = event.get_key_symbol();
let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK);
// X allows servers to represent Shift+Tab in two different ways
if (shift && keysym == Clutter.Tab)
keysym = Clutter.ISO_Left_Tab;
let event_state = Shell.get_event_state(event);
let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
let action = global.screen.get_display().get_keybinding_action(event.get_key_code(), event_state);
this._disableHover();
if (keysym == Clutter.grave)
this._select(this._currentApp, this._nextWindow());
else if (keysym == Clutter.asciitilde)
this._select(this._currentApp, this._previousWindow());
if (action == Meta.KeyBindingAction.SWITCH_GROUP)
this._select(this._currentApp, backwards ? this._previousWindow() : this._nextWindow());
else if (keysym == Clutter.Escape)
this.destroy();
else if (this._thumbnailsFocused) {
if (keysym == Clutter.Tab) {
if (this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1)
this._select(this._nextApp());
else
this._select(this._currentApp, this._nextWindow());
} else if (keysym == Clutter.ISO_Left_Tab) {
if (this._currentWindow == 0 || this._currentWindow == -1)
this._select(this._previousApp());
else
this._select(this._currentApp, this._previousWindow());
} else if (keysym == Clutter.Left)
if (action == Meta.KeyBindingAction.SWITCH_WINDOWS)
if (backwards) {
if (this._currentWindow == 0 || this._currentWindow == -1)
this._select(this._previousApp());
else
this._select(this._currentApp, this._previousWindow());
} else {
if (this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1)
this._select(this._nextApp());
else
this._select(this._currentApp, this._nextWindow());
}
else if (keysym == Clutter.Left)
this._select(this._currentApp, this._previousWindow());
else if (keysym == Clutter.Right)
this._select(this._currentApp, this._nextWindow());
else if (keysym == Clutter.Up)
this._select(this._currentApp, null, true);
} else {
if (keysym == Clutter.Tab)
this._select(this._nextApp());
else if (keysym == Clutter.ISO_Left_Tab)
this._select(this._previousApp());
if (action == Meta.KeyBindingAction.SWITCH_WINDOWS)
this._select(backwards ? this._previousApp() : this._nextApp());
else if (keysym == Clutter.Left)
this._select(this._previousApp());
else if (keysym == Clutter.Right)
@ -364,30 +376,35 @@ AltTabPopup.prototype = {
this.destroy();
},
_popModal: function() {
if (this._haveModal) {
Main.popModal(this.actor);
this._haveModal = false;
}
},
destroy : function() {
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.destroy();
})
});
this._popModal();
if (this.actor.visible) {
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.destroy();
})
});
} else
this.actor.destroy();
},
_onDestroy : function() {
if (this._haveModal)
Main.popModal(this.actor);
this._popModal();
if (this._thumbnails)
this._destroyThumbnails();
if (this._keyPressEventId)
global.stage.disconnect(this._keyPressEventId);
if (this._keyReleaseEventId)
global.stage.disconnect(this._keyReleaseEventId);
if (this._motionTimeoutId != 0)
Mainloop.source_remove(this._motionTimeoutId);
if (this._thumbnailTimeoutId != 0)
@ -458,11 +475,15 @@ AltTabPopup.prototype = {
},
_destroyThumbnails : function() {
Tweener.addTween(this._thumbnails.actor,
let thumbnailsActor = this._thumbnails.actor;
Tweener.addTween(thumbnailsActor,
{ opacity: 0,
time: THUMBNAIL_FADE_TIME,
transition: 'easeOutQuad',
onComplete: function() { this.destroy(); }
onComplete: Lang.bind(this, function() {
thumbnailsActor.destroy();
this.thumbnailsVisible = false;
})
});
this._thumbnails = null;
},
@ -478,7 +499,8 @@ AltTabPopup.prototype = {
Tweener.addTween(this._thumbnails.actor,
{ opacity: 255,
time: THUMBNAIL_FADE_TIME,
transition: 'easeOutQuad'
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
});
}
};
@ -519,16 +541,11 @@ SwitcherList.prototype = {
this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
pseudo_class: 'highlighted' });
this._leftArrow.connect('repaint', Lang.bind(this,
function (area) {
Shell.draw_box_pointer(area, Shell.PointerDirection.LEFT);
}));
function() { _drawArrow(this._leftArrow, St.Side.LEFT); }));
this._rightArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
pseudo_class: 'highlighted' });
this._rightArrow.connect('repaint', Lang.bind(this,
function (area) {
Shell.draw_box_pointer(area, Shell.PointerDirection.RIGHT);
}));
function() { _drawArrow(this._rightArrow, St.Side.RIGHT); }));
this.actor.add_actor(this._leftArrow);
this.actor.add_actor(this._rightArrow);
@ -585,23 +602,27 @@ SwitcherList.prototype = {
},
addItem : function(item) {
let bbox = new St.Clickable({ style_class: 'item-box',
reactive: true });
let bbox = new St.Button({ style_class: 'item-box',
reactive: true });
bbox.set_child(item);
this._list.add_actor(bbox);
let n = this._items.length;
bbox.connect('clicked', Lang.bind(this, function () {
this._itemActivated(n);
}));
bbox.connect('enter-event', Lang.bind(this, function () {
this._itemEntered(n);
}));
bbox.connect('clicked', Lang.bind(this, function() { this._onItemClicked(n); }));
bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); }));
this._items.push(bbox);
},
_onItemClicked: function (index) {
this._itemActivated(index);
},
_onItemEnter: function (index) {
this._itemEntered(index);
},
addSeparator: function () {
let box = new St.Bin({ style_class: 'separator' });
this._separator = box;
@ -609,16 +630,18 @@ SwitcherList.prototype = {
},
highlight: function(index, justOutline) {
if (this._highlighted != -1)
this._items[this._highlighted].style_class = 'item-box';
if (this._highlighted != -1) {
this._items[this._highlighted].remove_style_pseudo_class('outlined');
this._items[this._highlighted].remove_style_pseudo_class('selected');
}
this._highlighted = index;
if (this._highlighted != -1) {
if (justOutline)
this._items[this._highlighted].style_class = 'outlined-item-box';
this._items[this._highlighted].add_style_pseudo_class('outlined');
else
this._items[this._highlighted].style_class = 'selected-item-box';
this._items[this._highlighted].add_style_pseudo_class('selected');
}
let monitor = global.get_primary_monitor();
@ -804,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() });
@ -818,14 +841,14 @@ AppIcon.prototype = {
}
};
function AppSwitcher(apps) {
this._init(apps);
function AppSwitcher(apps, altTabPopup) {
this._init(apps, altTabPopup);
}
AppSwitcher.prototype = {
__proto__ : SwitcherList.prototype,
_init : function(apps) {
_init : function(apps, altTabPopup) {
SwitcherList.prototype._init.call(this, true);
// Construct the AppIcons, sort by time, add to the popup
@ -857,6 +880,8 @@ AppSwitcher.prototype = {
this._curApp = -1;
this._iconSize = 0;
this._altTabPopup = altTabPopup;
this._mouseTimeOutId = 0;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
@ -864,17 +889,19 @@ AppSwitcher.prototype = {
while(this._items.length > 1 && this._items[j].style_class != 'item-box') {
j++;
}
let iconPadding = this._items[j].get_theme_node().get_horizontal_padding();
let themeNode = this._items[j].get_theme_node();
let iconPadding = themeNode.get_horizontal_padding();
let iconBorder = themeNode.get_border_width(St.Side.LEFT) + themeNode.get_border_width(St.Side.RIGHT);
let [iconMinHeight, iconNaturalHeight] = this.icons[j].label.get_preferred_height(-1);
let iconSpacing = iconNaturalHeight + iconPadding;
let iconSpacing = iconNaturalHeight + iconPadding + iconBorder;
let totalSpacing = this._list.spacing * (this._items.length - 1);
if (this._separator)
totalSpacing += this._separator.width + this._list.spacing;
// We just assume the whole screen here due to weirdness happing with the passed width
let focus = global.get_focus_monitor();
let primary = global.get_primary_monitor();
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
let availWidth = focus.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding();
let availWidth = primary.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding();
let height = 0;
for(let i = 0; i < iconSizes.length; i++) {
@ -919,6 +946,29 @@ AppSwitcher.prototype = {
}
},
// We override SwitcherList's _onItemEnter method to delay
// activation when the thumbnail list is open
_onItemEnter: function (index) {
if (this._mouseTimeOutId != 0)
Mainloop.source_remove(this._mouseTimeOutId);
if (this._altTabPopup.thumbnailsVisible) {
this._mouseTimeOutId = Mainloop.timeout_add(APP_ICON_HOVER_TIMEOUT,
Lang.bind(this, function () {
this._enterItem(index);
this._mouseTimeOutId = 0;
return false;
}));
} else
this._itemEntered(index);
},
_enterItem: function(index) {
let [x, y, mask] = global.get_pointer();
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
if (this._items[index].contains(pickedActor))
this._itemEntered(index);
},
// We override SwitcherList's highlight() method to also deal with
// the AppSwitcher->ThumbnailList arrows. Apps with only 1 window
// will hide their arrows by default, but show them when their
@ -951,10 +1001,7 @@ AppSwitcher.prototype = {
let n = this._arrows.length;
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
arrow.connect('repaint', Lang.bind(this,
function (area) {
Shell.draw_box_pointer(area, Shell.PointerDirection.DOWN);
}));
arrow.connect('repaint', function() { _drawArrow(arrow, St.Side.BOTTOM); });
this._list.add_actor(arrow);
this._arrows.push(arrow);
@ -1040,6 +1087,9 @@ ThumbnailList.prototype = {
for (let i = 0; i < this._thumbnailBins.length; i++) {
let mutterWindow = this._windows[i].get_compositor_private();
if (!mutterWindow)
continue;
let windowTexture = mutterWindow.get_texture ();
let [width, height] = windowTexture.get_size();
let scale = Math.min(1.0, THUMBNAIL_DEFAULT_SIZE / width, availHeight / height);
@ -1057,3 +1107,46 @@ ThumbnailList.prototype = {
this._thumbnailBins = new Array();
}
};
function _drawArrow(area, side) {
let themeNode = area.get_theme_node();
let borderColor = themeNode.get_border_color(side);
let bodyColor = themeNode.get_foreground_color();
let [width, height] = area.get_surface_size ();
let cr = area.get_context();
cr.setLineWidth(1.0);
Clutter.cairo_set_source_color(cr, borderColor);
switch (side) {
case St.Side.TOP:
cr.moveTo(0, height);
cr.lineTo(Math.floor(width * 0.5), 0);
cr.lineTo(width, height);
break;
case St.Side.BOTTOM:
cr.moveTo(width, 0);
cr.lineTo(Math.floor(width * 0.5), height);
cr.lineTo(0, 0);
break;
case St.Side.LEFT:
cr.moveTo(width, height);
cr.lineTo(0, Math.floor(height * 0.5));
cr.lineTo(width, 0);
break;
case St.Side.RIGHT:
cr.moveTo(0, 0);
cr.lineTo(width, Math.floor(height * 0.5));
cr.lineTo(0, height);
break;
}
cr.strokePreserve();
Clutter.cairo_set_source_color(cr, bodyColor);
cr.fill();
}

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();
@ -29,10 +31,32 @@ function AlphabeticalView() {
AlphabeticalView.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ vertical: true });
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
this._appSystem = Shell.AppSystem.get_default();
this.actor.add(this._grid.actor, { y_align: St.Align.START, expand: true });
this._filterApp = null;
let box = new St.BoxLayout({ vertical: true });
box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
this.actor = new St.ScrollView({ x_fill: true,
y_fill: false,
y_align: St.Align.START,
vfade: true });
this.actor.add_actor(box);
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this.actor.connect('notify::mapped', Lang.bind(this,
function() {
if (!this.actor.mapped)
return;
let adjustment = this.actor.vscroll.adjustment;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(adjustment, direction);
// Reset scroll on mapping
adjustment.value = 0;
}));
},
_removeAll: function() {
@ -40,20 +64,51 @@ AlphabeticalView.prototype = {
this._apps = [];
},
_addApp: function(app) {
let appIcon = new AppWellIcon(this._appSystem.get_app(app.get_id()));
appIcon.connect('launching', Lang.bind(this, function() {
this.emit('launching');
}));
appIcon._draggable.connect('drag-begin', Lang.bind(this, function() {
this.emit('drag-begin');
}));
_addApp: function(appInfo) {
let appIcon = new AppWellIcon(this._appSystem.get_app(appInfo.get_id()));
this._grid.addItem(appIcon.actor);
appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
appIcon._appInfo = appInfo;
if (this._filterApp && !this._filterApp(appInfo))
appIcon.actor.hide();
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++)
this._apps[i].actor.visible = filter(this._apps[i]._appInfo);
},
refresh: function(apps) {
let ids = [];
for (let i in apps)
@ -70,8 +125,6 @@ AlphabeticalView.prototype = {
}
};
Signals.addSignalMethods(AlphabeticalView.prototype);
function ViewByCategories() {
this._init();
}
@ -79,59 +132,121 @@ function ViewByCategories() {
ViewByCategories.prototype = {
_init: function() {
this._appSystem = Shell.AppSystem.get_default();
this.actor = new St.BoxLayout({ vertical: true });
this.actor = new St.BoxLayout({ style_class: 'all-app' });
this.actor._delegate = this;
this._view = new AlphabeticalView();
// 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 });
// Always select the "All" filter when switching to the app view
this.actor.connect('notify::mapped', Lang.bind(this,
function() {
if (this.actor.mapped && this._allFilter)
this._selectCategory(-1);
}));
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);
},
_updateSections: function(apps) {
this._removeAll();
_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));
},
let sections = this._appSystem.get_sections();
if (!sections)
_selectCategory: function(num) {
if (this._currentCategory == num) // nothing to do
return;
for (let i = 0; i < sections.length; i++) {
if (i) {
let actor = new St.Bin({ style_class: 'app-section-divider' });
let divider = new St.Bin({ style_class: 'app-section-divider-container',
child: actor,
x_fill: true });
this.actor.add(divider, { y_fill: false, expand: true });
}
let _apps = apps.filter(function(app) {
return app.get_section() == sections[i];
});
this._sections[i] = { view: new AlphabeticalView(),
apps: _apps,
name: sections[i] };
this._sections[i].view.connect('launching', Lang.bind(this, function() {
this.emit('launching');
}));
this._sections[i].view.connect('drag-begin', Lang.bind(this, function() {
this.emit('drag-begin');
}));
this.actor.add(this._sections[i].view.actor, { y_align: St.Align.START, expand: true });
this._currentCategory = num;
if (num != -1)
this._allFilter.remove_style_pseudo_class('selected');
else
this._allFilter.add_style_pseudo_class('selected');
this._view.setFilter(Lang.bind(this, function(app) {
if (num == -1)
return true;
return this._sections[num].name == app.get_section();
}));
for (let i = 0; i < this._sections.length; i++) {
if (i == num)
this._sections[i].filterActor.add_style_pseudo_class('selected');
else
this._sections[i].filterActor.remove_style_pseudo_class('selected');
}
},
_addFilter: function(name, num) {
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
style_class: 'app-filter',
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);
}));
if (num != -1)
this._sections[num] = { filterActor: button,
name: name };
else
this._allFilter = button;
},
_removeAll: function() {
this.actor.destroy_children();
this._sections.forEach(function (section) { section.view.disconnectAll(); });
this._sections = [];
this._filters.destroy_children();
},
refresh: function(apps) {
this._updateSections(apps);
for (let i = 0; i < this._sections.length; i++) {
this._sections[i].view.refresh(this._sections[i].apps);
this._removeAll();
let sections = this._appSystem.get_sections();
this._apps = apps;
this._view.refresh(apps);
/* Translators: Filter to display all applications */
this._addFilter(_("All"), -1);
if (!sections)
return;
for (let i = 0; i < sections.length; i++)
this._addFilter(sections[i], i);
this._selectCategory(-1);
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);
}
}
};
Signals.addSignalMethods(ViewByCategories.prototype);
/* This class represents a display containing a collection of application items.
* The applications are sorted based on their name.
*/
@ -146,17 +261,8 @@ AllAppDisplay.prototype = {
Main.queueDeferredWork(this._workId);
}));
this._scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
vshadows: true });
this.actor = new St.Bin({ style_class: 'all-app',
y_align: St.Align.START,
child: this._scrollView });
this._appView = new ViewByCategories();
this._scrollView.add_actor(this._appView.actor);
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this.actor = new St.Bin({ child: this._appView.actor, x_fill: true, y_fill: true });
this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
},
@ -169,8 +275,6 @@ AllAppDisplay.prototype = {
this._appView.refresh(apps);
}
};
Signals.addSignalMethods(AllAppDisplay.prototype);
function BaseAppSearchProvider() {
this._init();
@ -190,17 +294,26 @@ 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) {
activateResult: function(id, params) {
params = Params.parse(params, { workspace: null,
timestamp: null });
let app = this._appSys.get_app(id);
app.activate();
app.activate(params.workspace ? params.workspace.index() : -1);
},
dragActivateResult: function(id) {
dragActivateResult: function(id, params) {
params = Params.parse(params, { workspace: null,
timestamp: null });
let app = this._appSys.get_app(id);
app.open_new_window();
app.open_new_window(params.workspace ? params.workspace.get_index() : -1);
}
};
@ -227,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');
}
};
@ -242,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) {
@ -251,30 +360,24 @@ 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();
}
};
function AppIcon(app) {
this._init(app);
function AppIcon(app, params) {
this._init(app, params);
}
AppIcon.prototype = {
__proto__: IconGrid.BaseIcon.prototype,
_init : function(app) {
_init : function(app, params) {
this.app = app;
let label = this.app.get_name();
IconGrid.BaseIcon.prototype._init.call(this,
label,
{ setSizeManually: true });
params);
},
createIcon: function(iconSize) {
@ -282,23 +385,27 @@ AppIcon.prototype = {
}
};
function AppWellIcon(app) {
this._init(app);
function AppWellIcon(app, iconParams) {
this._init(app, iconParams);
}
AppWellIcon.prototype = {
_init : function(app) {
_init : function(app, iconParams) {
this.app = app;
this.actor = new St.Clickable({ style_class: 'app-well-app',
reactive: true,
x_fill: true,
y_fill: true });
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;
this.icon = new AppIcon(app);
this.icon = new AppIcon(app, iconParams);
this.actor.set_child(this.icon.actor);
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);
@ -309,12 +416,15 @@ 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);
}));
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._menuTimeoutId = 0;
@ -353,29 +463,34 @@ AppWellIcon.prototype = {
Lang.bind(this, function() {
this.popupMenu();
}));
}
},
_onClicked: function(actor, event) {
this._removeMenuTimeout();
let button = event.get_button();
if (button == 1) {
this._onActivate(event);
} else if (button == 2) {
let newWorkspace = Main.overview.workspaces.addWorkspace();
if (newWorkspace != null) {
newWorkspace.activate(global.get_current_time());
this.emit('launching');
this.app.open_new_window();
Main.overview.hide();
}
} else if (button == 3) {
this.popupMenu();
return true;
}
return false;
},
_onClicked: function(actor, button) {
this._removeMenuTimeout();
if (button == 1) {
this._onActivate(Clutter.get_current_event());
} else if (button == 2) {
// Last workspace is always empty
let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1);
launchWorkspace.activate(global.get_current_time());
this.emit('launching');
this.app.open_new_window(-1);
Main.overview.hide();
}
return false;
},
_onKeyboardPopupMenu: function() {
this.popupMenu();
this._menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
getId: function() {
return this.app.get_id();
},
@ -386,67 +501,35 @@ AppWellIcon.prototype = {
if (!this._menu) {
this._menu = new AppIconMenu(this);
this._menu.connect('highlight-window', Lang.bind(this, function (menu, window) {
this.highlightWindow(window);
}));
this._menu.connect('activate-window', Lang.bind(this, function (menu, window) {
this.activateWindow(window);
}));
this._menu.connect('popup', Lang.bind(this, function (menu, isPoppedUp) {
if (isPoppedUp) {
this._onMenuPoppedUp();
} else {
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;
},
highlightWindow: function(metaWindow) {
if (this._didActivateWindow)
return;
if (!this._getRunning())
return;
Main.overview.getWorkspacesForWindow(metaWindow).setHighlightWindow(metaWindow);
},
activateWindow: function(metaWindow) {
if (metaWindow) {
this._didActivateWindow = true;
Main.activateWindow(metaWindow);
} else {
Main.overview.hide();
}
},
_onMenuPoppedUp: function() {
if (this._getRunning()) {
Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(this.app.get_id());
this._setWindowSelection = true;
this._didActivateWindow = false;
}
},
_onMenuPoppedDown: function() {
this.actor.sync_hover();
if (this._didActivateWindow)
return;
if (!this._setWindowSelection)
return;
Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(null);
this._setWindowSelection = false;
},
_getRunning: function() {
return this.app.state != Shell.AppState.STOPPED;
},
_onActivate: function (event) {
@ -455,24 +538,22 @@ AppWellIcon.prototype = {
if (modifiers & Clutter.ModifierType.CONTROL_MASK
&& this.app.state == Shell.AppState.RUNNING) {
this.app.open_new_window();
this.app.open_new_window(-1);
} else {
this.app.activate();
this.app.activate(-1);
}
Main.overview.hide();
},
// called by this._menuManager when it has the grab
menuEventFilter: function(event) {
return this._menu.menuEventFilter(event);
},
shellWorkspaceLaunch : function(params) {
params = Params.parse(params, { workspace: null,
timestamp: null });
shellWorkspaceLaunch : function() {
this.app.open_new_window();
this.app.open_new_window(params.workspace ? params.workspace.index() : -1);
},
getDragActor: function() {
return this.app.create_icon_texture(this.icon.iconSize);
return this.app.create_icon_texture(Main.overview.dash.iconSize);
},
// Returns the original actor that should align with the actor
@ -491,11 +572,17 @@ AppIconMenu.prototype = {
__proto__: PopupMenu.PopupMenu.prototype,
_init: function(source) {
PopupMenu.PopupMenu.prototype._init.call(this, source.actor, St.Align.MIDDLE, St.Side.LEFT, 0);
let side = St.Side.LEFT;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
side = St.Side.RIGHT;
PopupMenu.PopupMenu.prototype._init.call(this, source.actor, 0.5, side, 0);
// We want to keep the item hovered while the menu is up
this.blockSourceEvents = true;
this._source = source;
this.connect('active-changed', Lang.bind(this, this._onActiveChanged));
this.connect('activate', Lang.bind(this, this._onActivate));
this.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
@ -535,14 +622,12 @@ 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"));
this._highlightedItem = null;
},
_appendSeparator: function () {
@ -566,74 +651,16 @@ AppIconMenu.prototype = {
if (open) {
this.emit('popup', true);
} else {
this._updateHighlight(null);
this.emit('popup', false);
}
},
// called by this._menuManager when it has the grab
menuEventFilter: function(event) {
let eventType = event.type();
// Check if the user is interacting with a window representation
// rather than interacting with the menu
if (eventType == Clutter.EventType.BUTTON_RELEASE) {
let metaWindow = this._findMetaWindowForActor(event.get_source());
if (metaWindow)
this.emit('activate-window', metaWindow);
} else if (eventType == Clutter.EventType.ENTER) {
let metaWindow = this._findMetaWindowForActor(event.get_source());
if (metaWindow)
this._selectMenuItemForWindow(metaWindow, true);
} else if (eventType == Clutter.EventType.LEAVE) {
let metaWindow = this._findMetaWindowForActor(event.get_source());
if (metaWindow)
this._selectMenuItemForWindow(metaWindow, false);
}
return false;
},
_findMetaWindowForActor: function (actor) {
if (actor._delegate instanceof Workspace.WindowClone)
return actor._delegate.metaWindow;
else if (actor.get_meta_window)
return actor.get_meta_window();
return null;
},
_updateHighlight: function (item) {
if (this._highlightedItem)
this.emit('highlight-window', null);
this._highlightedItem = item;
if (this._highlightedItem) {
let window = this._highlightedItem._window;
if (window)
this.emit('highlight-window', window);
}
},
_selectMenuItemForWindow: function (metaWindow, selected) {
let items = this.getMenuItems();
for (let i = 0; i < items.length; i++) {
let item = items[i];
let menuMetaWindow = item._window;
if (menuMetaWindow == metaWindow)
item.setActive(selected);
}
},
_onActiveChanged: function (menu, child) {
this._updateHighlight(child);
},
_onActivate: function (actor, child) {
if (child._window) {
let metaWindow = child._window;
this.emit('activate-window', metaWindow);
} else if (child == this._newWindowMenuItem) {
this._source.app.open_new_window();
this._source.app.open_new_window(-1);
this.emit('activate-window', null);
} else if (child == this._toggleFavoriteMenuItem) {
let favs = AppFavorites.getAppFavorites();

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;
@ -11,7 +12,7 @@ const POPUP_ANIMATION_TIME = 0.15;
/**
* BoxPointer:
* @side: A St.Side type; currently only St.Side.TOP is implemented
* @side: side to draw the arrow on
* @binProperties: Properties to set on contained bin
*
* An actor which displays a triangle "arrow" pointing to a given
@ -40,76 +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;
},
animateAppear: function(onComplete) {
let x = this.actor.x;
let y = this.actor.y;
show: function(animate, onComplete) {
let themeNode = this.actor.get_theme_node();
let rise = themeNode.get_length('-arrow-rise');
this.actor.opacity = 0;
this.opacity = 0;
this.actor.show();
switch (this._arrowSide) {
case St.Side.TOP:
this.actor.y -= rise;
break;
case St.Side.BOTTOM:
this.actor.y += rise;
break;
case St.Side.LEFT:
this.actor.x -= rise;
break;
case St.Side.RIGHT:
this.actor.x += rise;
break;
if (animate) {
switch (this._arrowSide) {
case St.Side.TOP:
this.yOffset = -rise;
break;
case St.Side.BOTTOM:
this.yOffset = rise;
break;
case St.Side.LEFT:
this.xOffset = -rise;
break;
case St.Side.RIGHT:
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 });
},
animateDisappear: function(onComplete) {
let x = this.actor.x;
let y = this.actor.y;
let originalX = this.actor.x;
let originalY = this.actor.y;
hide: function(animate, onComplete) {
let xOffset = 0;
let yOffset = 0;
let themeNode = this.actor.get_theme_node();
let rise = themeNode.get_length('-arrow-rise');
switch (this._arrowSide) {
case St.Side.TOP:
y += rise;
break;
case St.Side.BOTTOM:
y -= rise;
break;
case St.Side.LEFT:
x += rise;
break;
case St.Side.RIGHT:
x -= rise;
break;
if (animate) {
switch (this._arrowSide) {
case St.Side.TOP:
yOffset = rise;
break;
case St.Side.BOTTOM:
yOffset = -rise;
break;
case St.Side.LEFT:
xOffset = rise;
break;
case St.Side.RIGHT:
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) {
@ -172,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) {
@ -185,10 +193,8 @@ BoxPointer.prototype = {
let halfBorder = borderWidth / 2;
let halfBase = Math.floor(base/2);
let borderColor = new Clutter.Color();
themeNode.get_color('-arrow-border-color', borderColor);
let backgroundColor = new Clutter.Color();
themeNode.get_color('-arrow-background-color', backgroundColor);
let borderColor = themeNode.get_color('-arrow-border-color');
let backgroundColor = themeNode.get_color('-arrow-background-color');
let [width, height] = area.get_surface_size();
let [boxWidth, boxHeight] = [width, height];
@ -208,46 +214,88 @@ BoxPointer.prototype = {
cr.translate(rise, 0);
}
cr.moveTo(borderRadius, halfBorder);
let [x1, y1] = [halfBorder, halfBorder];
let [x2, y2] = [boxWidth - halfBorder, boxHeight - halfBorder];
cr.moveTo(x1 + borderRadius, y1);
if (this._arrowSide == St.Side.TOP) {
cr.lineTo(this._arrowOrigin - halfBase, halfBorder);
cr.lineTo(this._arrowOrigin, halfBorder - rise);
cr.lineTo(this._arrowOrigin + halfBase, halfBorder);
if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
cr.lineTo(this._arrowOrigin, y1 - rise);
cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y1);
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y1);
cr.lineTo(this._arrowOrigin, y1 - rise);
} else {
cr.lineTo(this._arrowOrigin - halfBase, y1);
cr.lineTo(this._arrowOrigin, y1 - rise);
cr.lineTo(this._arrowOrigin + halfBase, y1);
}
}
cr.lineTo(boxWidth - borderRadius, halfBorder);
cr.arc(boxWidth - borderRadius - halfBorder, borderRadius + halfBorder, borderRadius,
cr.lineTo(x2 - borderRadius, y1);
// top-right corner
cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius,
3*Math.PI/2, Math.PI*2);
if (this._arrowSide == St.Side.RIGHT) {
cr.lineTo(boxWidth - halfBorder, this._arrowOrigin - halfBase);
cr.lineTo(boxWidth - halfBorder + rise, this._arrowOrigin);
cr.lineTo(boxWidth - halfBorder, this._arrowOrigin + halfBase);
if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
cr.lineTo(x2 + rise, this._arrowOrigin);
cr.lineTo(x2, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase);
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
cr.lineTo(x2, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase);
cr.lineTo(x2 + rise, this._arrowOrigin);
} else {
cr.lineTo(x2, this._arrowOrigin - halfBase);
cr.lineTo(x2 + rise, this._arrowOrigin);
cr.lineTo(x2, this._arrowOrigin + halfBase);
}
}
cr.lineTo(boxWidth - halfBorder, boxHeight - borderRadius);
cr.arc(boxWidth - borderRadius - halfBorder, boxHeight - borderRadius - halfBorder, borderRadius,
cr.lineTo(x2, y2 - borderRadius);
// bottom-right corner
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
0, Math.PI/2);
if (this._arrowSide == St.Side.BOTTOM) {
cr.lineTo(this._arrowOrigin + halfBase, boxHeight - halfBorder);
cr.lineTo(this._arrowOrigin, boxHeight - halfBorder + rise);
cr.lineTo(this._arrowOrigin - halfBase, boxHeight - halfBorder);
if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y2);
cr.lineTo(this._arrowOrigin, y2 + rise);
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
cr.lineTo(this._arrowOrigin, y2 + rise);
cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y2);
} else {
cr.lineTo(this._arrowOrigin + halfBase, y2);
cr.lineTo(this._arrowOrigin, y2 + rise);
cr.lineTo(this._arrowOrigin - halfBase, y2);
}
}
cr.lineTo(borderRadius, boxHeight - halfBorder);
cr.arc(borderRadius + halfBorder, boxHeight - borderRadius - halfBorder, borderRadius,
cr.lineTo(x1 + borderRadius, y2);
// bottom-left corner
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
Math.PI/2, Math.PI);
if (this._arrowSide == St.Side.LEFT) {
cr.lineTo(halfBorder, this._arrowOrigin + halfBase);
cr.lineTo(halfBorder - rise, this._arrowOrigin);
cr.lineTo(halfBorder, this._arrowOrigin - halfBase);
if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
cr.lineTo(x1, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase);
cr.lineTo(x1 - rise, this._arrowOrigin);
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
cr.lineTo(x1 - rise, this._arrowOrigin);
cr.lineTo(x1, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase);
} else {
cr.lineTo(x1, this._arrowOrigin + halfBase);
cr.lineTo(x1 - rise, this._arrowOrigin);
cr.lineTo(x1, this._arrowOrigin - halfBase);
}
}
cr.lineTo(halfBorder, borderRadius);
cr.arc(borderRadius + halfBorder, borderRadius + halfBorder, borderRadius,
cr.lineTo(x1, y1 + borderRadius);
// top-left corner
cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius,
Math.PI, 3*Math.PI/2);
Clutter.cairo_set_source_color(cr, backgroundColor);
@ -262,32 +310,47 @@ BoxPointer.prototype = {
// so that we can query the correct size.
this.actor.show();
// Position correctly relative to the sourceActor
let [sourceX, sourceY] = sourceActor.get_transformed_position();
let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
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 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
// edge by the same distance as the main part of the box is
// separated from its sourceActor
let primary = global.get_primary_monitor();
let arrowRise = this.actor.get_theme_node().get_length('-arrow-rise');
let themeNode = this.actor.get_theme_node();
let borderWidth = themeNode.get_length('-arrow-border-width');
let arrowBase = themeNode.get_length('-arrow-base');
let borderRadius = themeNode.get_length('-arrow-border-radius');
let margin = (4 * borderRadius + borderWidth + arrowBase);
let halfMargin = margin / 2;
let resX, resY;
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;
}
@ -296,42 +359,21 @@ BoxPointer.prototype = {
switch (this._arrowSide) {
case St.Side.TOP:
case St.Side.BOTTOM:
switch (alignment) {
case St.Align.START:
resX = sourceX;
break;
case St.Align.MIDDLE:
resX = sourceX - Math.floor((natWidth - sourceWidth) / 2);
break;
case St.Align.END:
resX = sourceX - (natWidth - sourceWidth);
break;
}
resX = sourceCenterX - (halfMargin + (natWidth - margin) * alignment);
resX = Math.min(resX, primary.x + primary.width - natWidth - arrowRise - gap);
resX = Math.max(resX, primary.x);
this.setArrowOrigin((sourceX - resX) + Math.floor(sourceWidth / 2));
resX = Math.max(resX, primary.x + 10);
resX = Math.min(resX, primary.x + primary.width - (10 + natWidth));
this.setArrowOrigin(sourceCenterX - resX);
break;
case St.Side.LEFT:
case St.Side.RIGHT:
switch (alignment) {
case St.Align.START:
resY = sourceY;
break;
case St.Align.MIDDLE:
resY = sourceY - Math.floor((natHeight - sourceHeight) / 2);
break;
case St.Align.END:
resY = sourceY - (natHeight - sourceHeight);
break;
}
resY = sourceCenterY - (halfMargin + (natHeight - margin) * alignment);
resY = Math.min(resY, primary.y + primary.height - natHeight - arrowRise - gap);
resY = Math.max(resY, primary.y);
resY = Math.max(resY, primary.y + 10);
resY = Math.min(resY, primary.y + primary.height - (10 + natHeight));
this.setArrowOrigin((sourceY - resY) + Math.floor(sourceHeight / 2));
this.setArrowOrigin(sourceCenterY - resY);
break;
}
@ -342,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
@ -355,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,22 +1,87 @@
/* -*- 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;
const St = imports.gi.St;
const Signals = imports.signals;
const Pango = imports.gi.Pango;
const Gettext_gtk30 = imports.gettext.domain('gtk30');
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const C_ = Gettext.pgettext;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
const WEEKDATE_HEADER_WIDTH_DIGITS = 3;
const SHOW_WEEKDATE_KEY = 'show-weekdate';
// in org.gnome.desktop.interface
const CLOCK_FORMAT_KEY = 'clock-format';
function _sameDay(dateA, dateB) {
return (dateA.getDate() == dateB.getDate() &&
dateA.getMonth() == dateB.getMonth() &&
dateA.getYear() == dateB.getYear());
}
function _sameYear(dateA, dateB) {
return (dateA.getYear() == dateB.getYear());
}
/* TODO: maybe needs config - right now we assume that Saturday and
* Sunday are non-work days (not true in e.g. Israel, it's Sunday and
* Monday there)
*/
function _isWorkDay(date) {
return date.getDay() != 0 && date.getDay() != 6;
}
function _getBeginningOfDay(date) {
let ret = new Date(date.getTime());
ret.setHours(0);
ret.setMinutes(0);
ret.setSeconds(0);
ret.setMilliseconds(0);
return ret;
}
function _getEndOfDay(date) {
let ret = new Date(date.getTime());
ret.setHours(23);
ret.setMinutes(59);
ret.setSeconds(59);
ret.setMilliseconds(999);
return ret;
}
function _formatEventTime(event, clockFormat) {
let ret;
if (event.allDay) {
/* Translators: Shown in calendar event list for all day events
* Keep it short, best if you can use less then 10 characters
*/
ret = C_("event list time", "All Day");
} else {
switch (clockFormat) {
case '24h':
/* Translators: Shown in calendar event list, if 24h format */
ret = event.date.toLocaleFormat(C_("event list time", "%H:%M"));
break;
default:
/* explicit fall-through */
case '12h':
/* Transators: Shown in calendar event list, if 12h format */
ret = event.date.toLocaleFormat(C_("event list time", "%l:%M %p"));
break;
}
}
return ret;
}
function _getCalendarWeekForDate(date) {
// Based on the algorithms found here:
// http://en.wikipedia.org/wiki/Talk:ISO_week_date
@ -43,12 +108,259 @@ function _getDigitWidth(actor){
return width;
}
function Calendar() {
function _getCalendarDayAbbreviation(dayNumber) {
let abbreviations = [
/* Translators: Calendar grid abbreviation for Sunday.
*
* NOTE: These grid abbreviations are always shown together
* and in order, e.g. "S M T W T F S".
*/
C_("grid sunday", "S"),
/* Translators: Calendar grid abbreviation for Monday */
C_("grid monday", "M"),
/* Translators: Calendar grid abbreviation for Tuesday */
C_("grid tuesday", "T"),
/* Translators: Calendar grid abbreviation for Wednesday */
C_("grid wednesday", "W"),
/* Translators: Calendar grid abbreviation for Thursday */
C_("grid thursday", "T"),
/* Translators: Calendar grid abbreviation for Friday */
C_("grid friday", "F"),
/* Translators: Calendar grid abbreviation for Saturday */
C_("grid saturday", "S")
];
return abbreviations[dayNumber];
}
function _getEventDayAbbreviation(dayNumber) {
let abbreviations = [
/* Translators: Event list abbreviation for Sunday.
*
* NOTE: These list abbreviations are normally not shown together
* so they need to be unique (e.g. Tuesday and Thursday cannot
* both be 'T').
*/
C_("list sunday", "Su"),
/* Translators: Event list abbreviation for Monday */
C_("list monday", "M"),
/* Translators: Event list abbreviation for Tuesday */
C_("list tuesday", "T"),
/* Translators: Event list abbreviation for Wednesday */
C_("list wednesday", "W"),
/* Translators: Event list abbreviation for Thursday */
C_("list thursday", "Th"),
/* Translators: Event list abbreviation for Friday */
C_("list friday", "F"),
/* Translators: Event list abbreviation for Saturday */
C_("list saturday", "S")
];
return abbreviations[dayNumber];
}
// Abstraction for an appointment/event in a calendar
function CalendarEvent(date, end, summary, allDay) {
this._init(date, end, summary, allDay);
}
CalendarEvent.prototype = {
_init: function(date, end, summary, allDay) {
this.date = date;
this.end = end;
this.summary = summary;
this.allDay = allDay;
}
};
// Interface for appointments/events - e.g. the contents of a calendar
//
// First, an implementation with no events
function EmptyEventSource() {
this._init();
}
Calendar.prototype = {
EmptyEventSource.prototype = {
_init: function() {
},
requestRange: function(begin, end) {
},
getEvents: function(begin, end) {
let result = [];
return result;
},
hasEvents: function(day) {
return false;
}
};
Signals.addSignalMethods(EmptyEventSource.prototype);
const CalendarServerIface = {
name: 'org.gnome.Shell.CalendarServer',
methods: [{ name: 'GetEvents',
inSignature: 'xxb',
outSignature: 'a(sssbxxa{sv})' }],
signals: [{ name: 'Changed',
inSignature: '' }]
};
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);
}
function _datesEqual(a, b) {
if (a < b)
return false;
else if (a > b)
return false;
return true;
}
function _dateIntervalsOverlap(a0, a1, b0, b1)
{
if (a1 <= b0)
return false;
else if (b1 <= a0)
return false;
else
return true;
}
DBusEventSource.prototype = {
_init: function(owner) {
this._resetCache();
this._dbusProxy = new CalendarServer(owner);
this._dbusProxy.connect('Changed', Lang.bind(this, this._onChanged));
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));
},
_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');
},
_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 = [];
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);
}
}
return result;
},
hasEvents: function(day) {
let dayBegin = _getBeginningOfDay(day);
let dayEnd = _getEndOfDay(day);
let events = this.getEvents(dayBegin, dayEnd);
if (events.length == 0)
return false;
return true;
}
};
Signals.addSignalMethods(DBusEventSource.prototype);
// Calendar:
// @eventSource: is an object implementing the EventSource API, e.g. the
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
function Calendar(eventSource) {
this._init(eventSource);
}
Calendar.prototype = {
_init: function(eventSource) {
this._eventSource = eventSource;
this._eventSource.connect('changed', Lang.bind(this,
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
// should add a C function so we can do the full handling.
@ -71,6 +383,7 @@ Calendar.prototype = {
}
// Find the ordering for month/year in the calendar heading
this._headerFormatWithoutYear = '%B';
switch (Gettext_gtk30.gettext('calendar:MY')) {
case 'calendar:MY':
this._headerFormat = '%B %Y';
@ -85,7 +398,7 @@ Calendar.prototype = {
}
// Start off with the current date
this.date = new Date();
this._selectedDate = new Date();
this.actor = new St.Table({ homogeneous: false,
style_class: 'calendar',
@ -95,14 +408,17 @@ Calendar.prototype = {
Lang.bind(this, this._onScroll));
this._buildHeader ();
this._update();
},
// Sets the calendar to show a specific date
setDate: function(date) {
if (!_sameDay(date, this.date)) {
this.date = date;
this._update();
setDate: function(date, forceReload) {
if (!_sameDay(date, this._selectedDate)) {
this._selectedDate = date;
this._update(forceReload);
this.emit('selected-date-changed', new Date(this._selectedDate));
} else {
if (forceReload)
this._update(forceReload);
}
},
@ -116,45 +432,36 @@ Calendar.prototype = {
{ row: 0, col: 0, col_span: offsetCols + 7 });
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChange));
let [backlabel, forwardlabel] = ['&lt;', '&gt;'];
if (St.Widget.get_default_direction () == St.TextDirection.RTL) {
[backlabel, forwardlabel] = [forwardlabel, backlabel];
}
let back = new St.Button({ label: backlabel, style_class: 'calendar-change-month' });
let back = new St.Button({ style_class: 'calendar-change-month-back' });
this._topBox.add(back);
back.connect('clicked', Lang.bind(this, this._prevMonth));
back.connect('clicked', Lang.bind(this, this._onPrevMonthButtonClicked));
this._dateLabel = new St.Label();
this._topBox.add(this._dateLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
this._monthLabel = new St.Label({style_class: 'calendar-month-label'});
this._topBox.add(this._monthLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
let forward = new St.Button({ label: forwardlabel, style_class: 'calendar-change-month' });
let forward = new St.Button({ style_class: 'calendar-change-month-forward' });
this._topBox.add(forward);
forward.connect('clicked', Lang.bind(this, this._nextMonth));
forward.connect('clicked', Lang.bind(this, this._onNextMonthButtonClicked));
// Add weekday labels...
//
// We need to figure out the abbreviated localized names for the days of the week;
// we do this by just getting the next 7 days starting from right now and then putting
// them in the right cell in the table. It doesn't matter if we add them in order
let iter = new Date(this.date);
let iter = new Date(this._selectedDate);
iter.setSeconds(0); // Leap second protection. Hah!
iter.setHours(12);
if (this._useWeekdate) {
this._weekdateHeader = new St.Label();
this.actor.add(this._weekdateHeader,
{ row: 1,
col: 0,
x_fill: false, x_align: St.Align.MIDDLE });
this._setWeekdateHeaderWidth();
} else {
this._weekdateHeader = null;
}
for (let i = 0; i < 7; i++) {
this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }),
// Could use iter.toLocaleFormat('%a') but that normally gives three characters
// and we want, ideally, a single character for e.g. S M T W T F S
let customDayAbbrev = _getCalendarDayAbbreviation(iter.getDay());
let label = new St.Label({ style_class: 'calendar-day-base calendar-day-heading',
text: customDayAbbrev });
this.actor.add(label,
{ row: 1,
col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.END });
x_fill: false, x_align: St.Align.MIDDLE });
iter.setTime(iter.getTime() + MSECS_IN_DAY);
}
@ -178,43 +485,72 @@ Calendar.prototype = {
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
case Clutter.ScrollDirection.LEFT:
this._prevMonth();
this._onPrevMonthButtonClicked();
break;
case Clutter.ScrollDirection.DOWN:
case Clutter.ScrollDirection.RIGHT:
this._nextMonth();
this._onNextMonthButtonClicked();
break;
}
},
_prevMonth: function() {
if (this.date.getMonth() == 0) {
this.date.setMonth(11);
this.date.setFullYear(this.date.getFullYear() - 1);
} else {
this.date.setMonth(this.date.getMonth() - 1);
_onPrevMonthButtonClicked: function() {
let newDate = new Date(this._selectedDate);
let oldMonth = newDate.getMonth();
if (oldMonth == 0) {
newDate.setMonth(11);
newDate.setFullYear(newDate.getFullYear() - 1);
if (newDate.getMonth() != 11) {
let day = 32 - new Date(newDate.getFullYear() - 1, 11, 32).getDate();
newDate = new Date(newDate.getFullYear() - 1, 11, day);
}
}
this._update();
else {
newDate.setMonth(oldMonth - 1);
if (newDate.getMonth() != oldMonth - 1) {
let day = 32 - new Date(newDate.getFullYear(), oldMonth - 1, 32).getDate();
newDate = new Date(newDate.getFullYear(), oldMonth - 1, day);
}
}
this.setDate(newDate, false);
},
_nextMonth: function() {
if (this.date.getMonth() == 11) {
this.date.setMonth(0);
this.date.setFullYear(this.date.getFullYear() + 1);
} else {
this.date.setMonth(this.date.getMonth() + 1);
_onNextMonthButtonClicked: function() {
let newDate = new Date(this._selectedDate);
let oldMonth = newDate.getMonth();
if (oldMonth == 11) {
newDate.setMonth(0);
newDate.setFullYear(newDate.getFullYear() + 1);
if (newDate.getMonth() != 0) {
let day = 32 - new Date(newDate.getFullYear() + 1, 0, 32).getDate();
newDate = new Date(newDate.getFullYear() + 1, 0, day);
}
}
this._update();
else {
newDate.setMonth(oldMonth + 1);
if (newDate.getMonth() != oldMonth + 1) {
let day = 32 - new Date(newDate.getFullYear(), oldMonth + 1, 32).getDate();
newDate = new Date(newDate.getFullYear(), oldMonth + 1, day);
}
}
this.setDate(newDate, false);
},
_onSettingsChange: function() {
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
this._buildHeader();
this._update();
this._update(false);
},
_update: function() {
this._dateLabel.text = this.date.toLocaleFormat(this._headerFormat);
_update: function(forceReload) {
let now = new Date();
if (_sameYear(this._selectedDate, now))
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormatWithoutYear);
else
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat);
// Remove everything but the topBox and the weekday labels
let children = this.actor.get_children();
@ -222,45 +558,217 @@ Calendar.prototype = {
children[i].destroy();
// Start at the beginning of the week before the start of the month
let iter = new Date(this.date);
iter.setDate(1);
iter.setSeconds(0);
iter.setHours(12);
let daysToWeekStart = (7 + iter.getDay() - this._weekStart) % 7;
iter.setTime(iter.getTime() - daysToWeekStart * MSECS_IN_DAY);
let now = new Date();
let beginDate = new Date(this._selectedDate);
beginDate.setDate(1);
beginDate.setSeconds(0);
beginDate.setHours(12);
let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7;
beginDate.setTime(beginDate.getTime() - daysToWeekStart * MSECS_IN_DAY);
let iter = new Date(beginDate);
let row = 2;
while (true) {
let label = new St.Label({ text: iter.getDate().toString() });
if (_sameDay(now, iter))
label.style_class = 'calendar-day calendar-today';
else if (iter.getMonth() != this.date.getMonth())
label.style_class = 'calendar-day calendar-other-month-day';
let button = new St.Button({ label: iter.getDate().toString() });
let iterStr = iter.toUTCString();
button.connect('clicked', Lang.bind(this, function() {
let newlySelectedDate = new Date(iterStr);
this.setDate(newlySelectedDate, false);
}));
let hasEvents = this._eventSource.hasEvents(iter);
let styleClass = 'calendar-day-base calendar-day';
if (_isWorkDay(iter))
styleClass += ' calendar-work-day'
else
label.style_class = 'calendar-day';
styleClass += ' calendar-nonwork-day'
// Hack used in lieu of border-collapse - see gnome-shell.css
if (row == 2)
styleClass = 'calendar-day-top ' + styleClass;
if (iter.getDay() == this._weekStart)
styleClass = 'calendar-day-left ' + styleClass;
if (_sameDay(now, iter))
styleClass += ' calendar-today';
else if (iter.getMonth() != this._selectedDate.getMonth())
styleClass += ' calendar-other-month-day';
if (_sameDay(this._selectedDate, iter))
button.add_style_pseudo_class('active');
if (hasEvents)
styleClass += ' calendar-day-with-events'
button.style_class = styleClass;
let offsetCols = this._useWeekdate ? 1 : 0;
this.actor.add(label,
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.END });
this.actor.add(button,
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 });
if (this._useWeekdate && iter.getDay() == 4) {
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
style_class: 'calendar-day calendar-calendarweek'});
style_class: 'calendar-day-base calendar-week-number'});
this.actor.add(label,
{ row: row, col: 0,
x_fill: false, x_align: St.Align.MIDDLE });
{ row: row, col: 0, y_align: St.Align.MIDDLE });
}
iter.setTime(iter.getTime() + MSECS_IN_DAY);
if (iter.getDay() == this._weekStart) {
// We stop on the first "first day of the week" after the month we are displaying
if (iter.getMonth() > this.date.getMonth() || iter.getYear() > this.date.getYear())
if (iter.getMonth() > this._selectedDate.getMonth() || iter.getYear() > this._selectedDate.getYear())
break;
row++;
}
}
// Signal to the event source that we are interested in events
// only from this date range
this._eventSource.requestRange(beginDate, iter, forceReload);
}
};
Signals.addSignalMethods(Calendar.prototype);
function EventsList(eventSource) {
this._init(eventSource);
}
EventsList.prototype = {
_init: function(eventSource) {
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
this._date = new Date();
this._eventSource = eventSource;
this._eventSource.connect('changed', Lang.bind(this, this._update));
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
let weekStartString = Gettext_gtk30.gettext('calendar:week_start:0');
if (weekStartString.indexOf('calendar:week_start:') == 0) {
this._weekStart = parseInt(weekStartString.substring(20));
}
if (isNaN(this._weekStart) ||
this._weekStart < 0 ||
this._weekStart > 6) {
log('Translation of "calendar:week_start:0" in GTK+ is not correct');
this._weekStart = 0;
}
this._update();
},
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
if (includeDayName) {
dayNameBox.add(new St.Label( { style_class: 'events-day-dayname',
text: day } ),
{ x_fill: true } );
}
timeBox.add(new St.Label( { style_class: 'events-day-time',
text: time} ),
{ x_fill: true } );
eventTitleBox.add(new St.Label( { style_class: 'events-day-task',
text: desc} ));
},
_addPeriod: function(header, begin, end, includeDayName, showNothingScheduled) {
let events = this._eventSource.getEvents(begin, end);
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);;
if (events.length == 0 && !showNothingScheduled)
return;
let vbox = new St.BoxLayout( {vertical: true} );
this.actor.add(vbox);
vbox.add(new St.Label({ style_class: 'events-day-header', text: header }));
let box = new St.BoxLayout({style_class: 'events-header-hbox'});
let dayNameBox = new St.BoxLayout({ vertical: true, style_class: 'events-day-name-box' });
let timeBox = new St.BoxLayout({ vertical: true, style_class: 'events-time-box' });
let eventTitleBox = new St.BoxLayout({ vertical: true, style_class: 'events-event-box' });
box.add(dayNameBox, {x_fill: false});
box.add(timeBox, {x_fill: false});
box.add(eventTitleBox, {expand: true});
vbox.add(box);
for (let n = 0; n < events.length; n++) {
let event = events[n];
let dayString = _getEventDayAbbreviation(event.date.getDay());
let timeString = _formatEventTime(event, clockFormat);
let summaryString = event.summary;
this._addEvent(dayNameBox, timeBox, eventTitleBox, includeDayName, dayString, timeString, summaryString);
}
if (events.length == 0 && showNothingScheduled) {
let now = new Date();
/* Translators: Text to show if there are no events */
let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
let timeString = _formatEventTime(nothingEvent, clockFormat);
this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
}
},
_showOtherDay: function(day) {
this.actor.destroy_children();
let dayBegin = _getBeginningOfDay(day);
let dayEnd = _getEndOfDay(day);
let dayString;
let now = new Date();
if (_sameYear(day, now))
/* Translators: Shown on calendar heading when selected day occurs on current year */
dayString = day.toLocaleFormat(C_("calendar heading", "%A, %B %d"));
else
/* Translators: Shown on calendar heading when selected day occurs on different year */
dayString = day.toLocaleFormat(C_("calendar heading", "%A, %B %d, %Y"));
this._addPeriod(dayString, dayBegin, dayEnd, false, true);
},
_showToday: function() {
this.actor.destroy_children();
let now = new Date();
let dayBegin = _getBeginningOfDay(now);
let dayEnd = _getEndOfDay(now);
this._addPeriod(_("Today"), dayBegin, dayEnd, false, true);
let tomorrowBegin = new Date(dayBegin.getTime() + 86400 * 1000);
let tomorrowEnd = new Date(dayEnd.getTime() + 86400 * 1000);
this._addPeriod(_("Tomorrow"), tomorrowBegin, tomorrowEnd, false, true);
if (dayEnd.getDay() <= 4 + this._weekStart) {
/* If now is within the first 5 days we show "This week" and
* include events up until and including Saturday/Sunday
* (depending on whether a week starts on Sunday/Monday).
*/
let thisWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let thisWeekEnd = new Date(dayEnd.getTime() + (6 + this._weekStart - dayEnd.getDay()) * 86400 * 1000);
this._addPeriod(_("This week"), thisWeekBegin, thisWeekEnd, true, false);
} else {
/* otherwise it's one of the two last days of the week ... show
* "Next week" and include events up until and including *next*
* Saturday/Sunday
*/
let nextWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let nextWeekEnd = new Date(dayEnd.getTime() + (13 + this._weekStart - dayEnd.getDay()) * 86400 * 1000);
this._addPeriod(_("Next week"), nextWeekBegin, nextWeekEnd, true, false);
}
},
// Sets the event list to show events from a specific date
setDate: function(date) {
if (!_sameDay(date, this._date)) {
this._date = date;
this._update();
}
},
_update: function() {
let today = new Date();
if (_sameDay (this._date, today)) {
this._showToday();
} else {
this._showOtherDay(this._date);
}
}
};

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() {
let windows = global.get_window_actors();
let primary = global.get_primary_monitor();
_updateFullscreen: function() {
let windows = Main.getWindowActorsForWorkspace(global.screen.get_active_workspace_index());
// 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);
}

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

@ -0,0 +1,328 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const AltTab = imports.ui.altTab;
const Main = imports.ui.main;
const 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();
}
CtrlAltTabManager.prototype = {
_init: function() {
this._items = [];
this._focusManager = St.FocusManager.get_for_stage(global.stage);
},
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);
},
removeGroup: function(root) {
this._focusManager.remove_group(root);
for (let i = 0; i < this._items.length; i++) {
if (this._items[i].root == root) {
this._items.splice(i, 1);
return;
}
}
},
focusGroup: function(item) {
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
global.stage_input_mode == Shell.StageInputMode.NORMAL)
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
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.proxy.mapped; });
// And add the windows metacity would show in its Ctrl-Alt-Tab list
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);
}
};
function mod(a, b) {
return (a + b) % b;
}
function CtrlAltTabPopup() {
this._init();
}
CtrlAltTabPopup.prototype = {
_init : function() {
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));
this._haveModal = false;
this._selection = 0;
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;
this._haveModal = true;
this._keyPressEventId = this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
this._keyReleaseEventId = this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
this._items = items;
this._switcher = new CtrlAltTabSwitcher(items);
this.actor.add_actor(this._switcher.actor);
if (startBackwards)
this._selection = this._items.length - 1;
this._select(this._selection);
let [x, y, mods] = global.get_pointer();
if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
this._finish();
return false;
}
this.actor.opacity = 0;
this.actor.show();
Tweener.addTween(this.actor,
{ opacity: 255,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad'
});
return true;
},
_next : function() {
return mod(this._selection + 1, this._items.length);
},
_previous : function() {
return mod(this._selection - 1, this._items.length);
},
_keyPressEvent : function(actor, event) {
let keysym = event.get_key_symbol();
let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK);
if (shift && keysym == Clutter.KEY_Tab)
keysym = Clutter.ISO_Left_Tab;
if (keysym == Clutter.KEY_Escape)
this.destroy();
else if (keysym == Clutter.KEY_Tab)
this._select(this._next());
else if (keysym == Clutter.KEY_ISO_Left_Tab)
this._select(this._previous());
else if (keysym == Clutter.KEY_Left)
this._select(this._previous());
else if (keysym == Clutter.KEY_Right)
this._select(this._next());
return true;
},
_keyReleaseEvent : function(actor, event) {
let [x, y, mods] = global.get_pointer();
let state = mods & Clutter.ModifierType.MOD1_MASK;
if (state == 0)
this._finish();
return true;
},
_finish : function() {
this.destroy();
Main.ctrlAltTabManager.focusGroup(this._items[this._selection]);
},
_popModal: function() {
if (this._haveModal) {
Main.popModal(this.actor);
this._haveModal = false;
}
},
destroy : function() {
this._popModal();
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.destroy();
})
});
},
_onDestroy : function() {
this._popModal();
if (this._keyPressEventId)
this.actor.disconnect(this._keyPressEventId);
if (this._keyReleaseEventId)
this.actor.disconnect(this._keyReleaseEventId);
},
_select : function(num) {
this._selection = num;
this._switcher.highlight(num);
}
};
function CtrlAltTabSwitcher(items) {
this._init(items);
}
CtrlAltTabSwitcher.prototype = {
__proto__ : AltTab.SwitcherList.prototype,
_init : function(items) {
AltTab.SwitcherList.prototype._init.call(this, true);
for (let i = 0; i < items.length; i++)
this._addIcon(items[i]);
},
_addIcon : function(item) {
let box = new St.BoxLayout({ style_class: 'alt-tab-app',
vertical: true });
let icon = item.iconActor;
if (!icon) {
icon = new St.Icon({ icon_name: item.iconName,
icon_type: St.IconType.SYMBOLIC,
icon_size: POPUP_APPICON_SIZE });
}
box.add(icon, { x_fill: false, y_fill: false } );
let text = new St.Label({ text: item.name });
box.add(text, { x_fill: false });
this.addItem(box);
}
};

View File

@ -1,5 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Signals = imports.signals;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
@ -13,22 +14,177 @@ const AppFavorites = imports.ui.appFavorites;
const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const DASH_ANIMATION_TIME = 0.2;
// A container like StBin, but taking the child's scale into account
// when requesting a size
function DashItemContainer() {
this._init();
}
DashItemContainer.prototype = {
_init: function() {
this.actor = new Shell.GenericContainer({ style_class: 'dash-item-container' });
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._delegate = this;
this.child = null;
this._childScale = 1;
this._childOpacity = 255;
},
_allocate: function(actor, box, flags) {
if (this.child == null)
return;
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] =
this.child.get_preferred_size();
let [childScaleX, childScaleY] = this.child.get_scale();
let childWidth = Math.min(natChildWidth * childScaleX, availWidth);
let childHeight = Math.min(natChildHeight * childScaleY, availHeight);
let childBox = new Clutter.ActorBox();
childBox.x1 = (availWidth - childWidth) / 2;
childBox.y1 = (availHeight - childHeight) / 2;
childBox.x2 = childBox.x1 + childWidth;
childBox.y2 = childBox.y1 + childHeight;
this.child.allocate(childBox, flags);
},
_getPreferredHeight: function(actor, forWidth, alloc) {
alloc.min_size = 0;
alloc.natural_size = 0;
if (this.child == null)
return;
let [minHeight, natHeight] = this.child.get_preferred_height(forWidth);
alloc.min_size += minHeight * this.child.scale_y;
alloc.natural_size += natHeight * this.child.scale_y;
},
_getPreferredWidth: function(actor, forHeight, alloc) {
alloc.min_size = 0;
alloc.natural_size = 0;
if (this.child == null)
return;
let [minWidth, natWidth] = this.child.get_preferred_width(forHeight);
alloc.min_size = minWidth * this.child.scale_y;
alloc.natural_size = natWidth * this.child.scale_y;
},
setChild: function(actor) {
if (this.child == actor)
return;
this.actor.destroy_children();
this.child = actor;
this.actor.add_actor(this.child);
},
animateIn: function() {
if (this.child == null)
return;
this.childScale = 0;
this.childOpacity = 0;
Tweener.addTween(this,
{ childScale: 1.0,
childOpacity: 255,
time: DASH_ANIMATION_TIME,
transition: 'easeOutQuad'
});
},
animateOutAndDestroy: function() {
if (this.child == null) {
this.actor.destroy();
return;
}
this.childScale = 1.0;
Tweener.addTween(this,
{ childScale: 0.0,
childOpacity: 0,
time: DASH_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this.actor.destroy();
})
});
},
set childScale(scale) {
this._childScale = scale;
if (this.child == null)
return;
this.child.set_scale_with_gravity(scale, scale,
Clutter.Gravity.CENTER);
this.actor.queue_relayout();
},
get childScale() {
return this._childScale;
},
set childOpacity(opacity) {
this._childOpacity = opacity;
if (this.child == null)
return;
this.child.set_opacity(opacity);
this.actor.queue_redraw();
},
get childOpacity() {
return this._childOpacity;
}
};
function RemoveFavoriteIcon() {
this._init();
}
RemoveFavoriteIcon.prototype = {
__proto__: DashItemContainer.prototype,
_init: function() {
this.actor = new St.Bin({ style_class: 'remove-favorite' });
DashItemContainer.prototype._init.call(this);
this._iconBin = new St.Bin({ style_class: 'remove-favorite' });
this._iconActor = null;
this.icon = new IconGrid.BaseIcon(_("Remove"),
{ setSizeManually: true,
showLabel: false,
createIcon: Lang.bind(this, this._createIcon) });
this.actor.set_child(this.icon.actor);
this.actor._delegate = this;
this._iconBin.set_child(this.icon.actor);
this._iconBin._delegate = this;
this.setChild(this._iconBin);
this.hiding = false;
},
animateOutAndDestroy: function() {
DashItemContainer.prototype.animateOutAndDestroy.call(this);
this.hiding = true;
},
_createIcon: function(size) {
@ -39,7 +195,7 @@ RemoveFavoriteIcon.prototype = {
},
setHover: function(hovered) {
this.actor.set_hover(hovered);
this._iconBin.set_hover(hovered);
if (this._iconActor)
this._iconActor.set_hover(hovered);
},
@ -54,7 +210,7 @@ RemoveFavoriteIcon.prototype = {
if (source instanceof AppDisplay.AppWellIcon) {
let appSystem = Shell.AppSystem.get_default();
app = appSystem.get_app(source.getId());
} else if (source instanceof Workspace.WindowClone) {
} else if (source.metaWindow) {
let tracker = Shell.WindowTracker.get_default();
app = tracker.get_window_app(source.metaWindow);
}
@ -72,23 +228,35 @@ RemoveFavoriteIcon.prototype = {
};
function DragPlaceholderItem() {
this._init();
}
DragPlaceholderItem.prototype = {
__proto__: DashItemContainer.prototype,
_init: function() {
DashItemContainer.prototype._init.call(this);
this.setChild(new St.Bin({ style_class: 'dash-placeholder' }));
}
};
function Dash() {
this._init();
}
Dash.prototype = {
_init : function() {
this._menus = [];
this._menuDisplays = [];
this._maxHeight = -1;
this._iconSize = 48;
this.iconSize = 64;
this._shownInitially = false;
this._dragPlaceholder = null;
this._dragPlaceholderPos = -1;
this._animatingPlaceholdersCount = 0;
this._favRemoveTarget = null;
this._favorites = [];
this._box = new St.BoxLayout({ name: 'dash',
vertical: true,
clip_to_allocation: true });
@ -110,38 +278,53 @@ Dash.prototype = {
this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._queueRedisplay));
this._tracker.connect('app-state-changed', Lang.bind(this, this._queueRedisplay));
},
show: function() {
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
Lang.bind(this, this._onDragBegin));
this._itemDragEndId = Main.overview.connect('item-drag-end',
Lang.bind(this, this._onDragEnd));
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
Lang.bind(this, this._onDragBegin));
this._windowDragEndId = Main.overview.connect('window-drag-end',
Lang.bind(this, this._onDragEnd));
},
hide: function() {
Main.overview.disconnect(this._itemDragBeginId);
Main.overview.disconnect(this._itemDragEndId);
Main.overview.disconnect(this._windowDragBeginId);
Main.overview.disconnect(this._windowDragEndId);
Main.overview.connect('item-drag-begin',
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.destroy();
this._favRemoveTarget = null;
this._favRemoveTarget.actor.hide();
this._adjustIconSize();
this._favRemoveTarget.actor.show();
this._favRemoveTarget.animateOutAndDestroy();
this._favRemoveTarget.actor.connect('destroy', Lang.bind(this,
function() {
this._favRemoveTarget = null;
}));
}
DND.removeMonitor(this._dragMonitor);
},
@ -150,7 +333,7 @@ Dash.prototype = {
let app = null;
if (dragEvent.source instanceof AppDisplay.AppWellIcon)
app = this._appSystem.get_app(dragEvent.source.getId());
else if (dragEvent.source instanceof Workspace.WindowClone)
else if (dragEvent.source.metaWindow)
app = this._tracker.get_window_app(dragEvent.source.metaWindow);
else
return DND.DragMotionResult.CONTINUE;
@ -163,8 +346,10 @@ Dash.prototype = {
if (srcIsFavorite && this._favRemoveTarget == null) {
this._favRemoveTarget = new RemoveFavoriteIcon();
this._favRemoveTarget.icon.setIconSize(this._iconSize);
this._favRemoveTarget.icon.setIconSize(this.iconSize);
this._box.add(this._favRemoveTarget.actor);
this._adjustIconSize();
this._favRemoveTarget.animateIn();
}
let favRemoveHovered = false;
@ -192,8 +377,10 @@ Dash.prototype = {
Main.queueDeferredWork(this._workId);
},
_addApp: function(app) {
let display = new AppDisplay.AppWellIcon(app);
_createAppItem: function(app) {
let display = new AppDisplay.AppWellIcon(app,
{ setSizeManually: true,
showLabel: false });
display._draggable.connect('drag-begin',
Lang.bind(this, function() {
display.actor.opacity = 50;
@ -202,13 +389,84 @@ Dash.prototype = {
Lang.bind(this, function() {
display.actor.opacity = 255;
}));
this._box.add(display.actor);
display.actor.set_tooltip_text(app.get_name());
let item = new DashItemContainer();
item.setChild(display.actor);
display.icon.setIconSize(this.iconSize);
return item;
},
_adjustIconSize: function() {
let children = this._box.get_children();
if (children.length == 0) {
this._box.add_style_pseudo_class('empty');
return;
}
this._box.remove_style_pseudo_class('empty');
if (this._maxHeight == -1)
return;
let iconChildren = children.filter(function(actor) {
return actor.visible &&
actor._delegate.child &&
actor._delegate.child._delegate &&
actor._delegate.child._delegate.icon;
});
// Compute the amount of extra space (or missing space) we have
// per icon with the current icon size
let [minHeight, natHeight] = this.actor.get_preferred_height(-1);
let diff = (this._maxHeight - natHeight) / iconChildren.length;
let iconSizes = [ 16, 22, 24, 32, 48, 64 ];
let newIconSize = 16;
for (let i = 0; i < iconSizes.length; i++) {
if (iconSizes[i] < this.iconSize + diff)
newIconSize = iconSizes[i];
}
if (newIconSize == this.iconSize)
return;
let oldIconSize = this.iconSize;
this.iconSize = newIconSize;
let scale = oldIconSize / newIconSize;
for (let i = 0; i < iconChildren.length; i++) {
let icon = iconChildren[i]._delegate.child._delegate.icon;
// Set the new size immediately, to keep the icons' sizes
// in sync with this.iconSize
icon.setIconSize(this.iconSize);
// Don't animate the icon size change when the overview
// is not visible or when initially filling the dash
if (!Main.overview.visible || !this._shownInitially)
continue;
let [targetWidth, targetHeight] = icon.icon.get_size();
// Scale the icon's texture to the previous size and
// tween to the new size
icon.icon.set_size(icon.icon.width * scale,
icon.icon.height * scale);
Tweener.addTween(icon.icon,
{ width: targetWidth,
height: targetHeight,
time: DASH_ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
},
_redisplay: function () {
this._box.hide();
this._box.remove_all();
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
/* hardcode here pending some design about how exactly desktop contexts behave */
@ -216,47 +474,142 @@ Dash.prototype = {
let running = this._tracker.get_running_apps(contextId);
for (let id in favorites) {
let app = favorites[id];
this._addApp(app);
}
let children = this._box.get_children().filter(function(actor) {
return actor._delegate.child &&
actor._delegate.child._delegate &&
actor._delegate.child._delegate.app;
});
// Apps currently in the dash
let oldApps = children.map(function(actor) {
return actor._delegate.child._delegate.app;
});
// Apps supposed to be in the dash
let newApps = [];
for (let id in favorites)
newApps.push(favorites[id]);
for (let i = 0; i < running.length; i++) {
let app = running[i];
if (app.get_id() in favorites)
continue;
this._addApp(app);
newApps.push(app);
}
let children = this._box.get_children();
if (children.length == 0) {
this._box.add_style_pseudo_class('empty');
} else {
this._box.remove_style_pseudo_class('empty');
// Figure out the actual changes to the list of items; we iterate
// over both the list of items currently in the dash and the list
// of items expected there, and collect additions and removals.
// Moves are both an addition and a removal, where the order of
// the operations depends on whether we encounter the position
// where the item has been added first or the one from where it
// was removed.
// There is an assumption that only one item is moved at a given
// time; when moving several items at once, everything will still
// end up at the right position, but there might be additional
// additions/removals (e.g. it might remove all the launchers
// and add them back in the new order even if a smaller set of
// additions and removals is possible).
// If above assumptions turns out to be a problem, we might need
// to use a more sophisticated algorithm, e.g. Longest Common
// Subsequence as used by diff.
let addedItems = [];
let removedActors = [];
if (this._maxHeight > -1) {
let iconSizes = [ 48, 32, 24, 22, 16 ];
let newIndex = 0;
let oldIndex = 0;
while (newIndex < newApps.length || oldIndex < oldApps.length) {
// No change at oldIndex/newIndex
if (oldApps[oldIndex] == newApps[newIndex]) {
oldIndex++;
newIndex++;
continue;
}
for (let i = 0; i < iconSizes.length; i++) {
let minHeight, natHeight;
// App removed at oldIndex
if (oldApps[oldIndex] &&
newApps.indexOf(oldApps[oldIndex]) == -1) {
removedActors.push(children[oldIndex]);
oldIndex++;
continue;
}
this._iconSize = iconSizes[i];
for (let j = 0; j < children.length; j++)
children[j]._delegate.icon.setIconSize(this._iconSize);
// App added at newIndex
if (newApps[newIndex] &&
oldApps.indexOf(newApps[newIndex]) == -1) {
addedItems.push({ app: newApps[newIndex],
item: this._createAppItem(newApps[newIndex]),
pos: newIndex });
newIndex++;
continue;
}
[minHeight, natHeight] = this.actor.get_preferred_height(-1);
// App moved
let insertHere = newApps[newIndex + 1] &&
newApps[newIndex + 1] == oldApps[oldIndex];
let alreadyRemoved = removedActors.reduce(function(result, actor) {
let removedApp = actor._delegate.child._delegate.app;
return result || removedApp == newApps[newIndex];
}, false);
if (natHeight <= this._maxHeight)
break;
}
if (insertHere || alreadyRemoved) {
let newItem = this._createAppItem(newApps[newIndex]);
addedItems.push({ app: newApps[newIndex],
item: newItem,
pos: newIndex + removedActors.length });
newIndex++;
} else {
removedActors.push(children[oldIndex]);
oldIndex++;
}
}
this._box.show();
for (let i = 0; i < addedItems.length; i++)
this._box.insert_actor(addedItems[i].item.actor,
addedItems[i].pos);
// Hide removed actors to not take them into account
// when adjusting the icon size ...
for (let i = 0; i < removedActors.length; i++)
removedActors[i].hide();
// ... and do the same for the remove target if necessary
if (this._favRemoveTarget && this._favRemoveTarget.hiding)
this._favRemoveTarget.actor.hide();
this._adjustIconSize();
if (this._favRemoveTarget && this._favRemoveTarget.hiding)
this._favRemoveTarget.actor.show();
// Skip animations on first run when adding the initial set
// of items, to avoid all items zooming in at once
if (!this._shownInitially) {
this._shownInitially = true;
return;
}
for (let i = 0; i < removedActors.length; i++) {
removedActors[i].show();
let item = removedActors[i]._delegate;
// Don't animate item removal when the overview is hidden
if (Main.overview.visible)
item.animateOutAndDestroy();
else
item.actor.destroy();
}
// Don't animate item addition when the overview is hidden
if (!Main.overview.visible)
return;
for (let i = 0; i < addedItems.length; i++)
addedItems[i].item.animateIn();
},
_clearDragPlaceholder: function() {
if (this._dragPlaceholder) {
this._dragPlaceholder.destroy();
this._dragPlaceholder.animateOutAndDestroy();
this._dragPlaceholder = null;
this._dragPlaceholderPos = -1;
}
@ -266,40 +619,79 @@ Dash.prototype = {
let app = null;
if (source instanceof AppDisplay.AppWellIcon)
app = this._appSystem.get_app(source.getId());
else if (source instanceof Workspace.WindowClone)
else if (source.metaWindow)
app = this._tracker.get_window_app(source.metaWindow);
// Don't allow favoriting of transient apps
if (app == null || app.is_transient())
return DND.DragMotionResult.NO_DROP;
let numFavorites = AppFavorites.getAppFavorites().getFavorites().length;
let numChildren = this._box.get_children().length;
let favorites = AppFavorites.getAppFavorites().getFavorites();
let numFavorites = favorites.length;
let favPos = favorites.indexOf(app);
let children = this._box.get_children();
let numChildren = children.length;
let boxHeight = this._box.height;
// Keep the placeholder out of the index calculation; assuming that
// the remove target has the same size as "normal" items, we don't
// need to do the same adjustment there.
if (this._dragPlaceholder) {
boxHeight -= this._dragPlaceholder.height;
boxHeight -= this._dragPlaceholder.actor.height;
numChildren--;
}
let pos = Math.round(y * numChildren / boxHeight);
if (pos != this._dragPlaceholderPos && pos <= numFavorites) {
this._dragPlaceholderPos = pos;
if (this._dragPlaceholder)
this._dragPlaceholder.destroy();
this._dragPlaceholder = new St.Bin({ style_class: 'dash-placeholder' });
this._box.insert_actor(this._dragPlaceholder, pos);
if (this._animatingPlaceholdersCount > 0) {
let appChildren = children.filter(function(actor) {
return actor._delegate &&
actor._delegate.child &&
actor._delegate.child._delegate &&
actor._delegate.child._delegate.app;
});
this._dragPlaceholderPos = children.indexOf(appChildren[pos]);
} else {
this._dragPlaceholderPos = pos;
}
// Don't allow positioning before or after self
if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
if (this._dragPlaceholder) {
this._dragPlaceholder.animateOutAndDestroy();
this._animatingPlaceholdersCount++;
this._dragPlaceholder.actor.connect('destroy',
Lang.bind(this, function() {
this._animatingPlaceholdersCount--;
}));
}
this._dragPlaceholder = null;
return DND.DragMotionResult.CONTINUE;
}
// If the placeholder already exists, we just move
// it, but if we are adding it, expand its size in
// an animation
let fadeIn;
if (this._dragPlaceholder) {
this._dragPlaceholder.actor.destroy();
fadeIn = false;
} else {
fadeIn = true;
}
this._dragPlaceholder = new DragPlaceholderItem();
this._box.insert_actor(this._dragPlaceholder.actor,
this._dragPlaceholderPos);
if (fadeIn)
this._dragPlaceholder.animateIn();
}
let id = app.get_id();
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
let srcIsFavorite = (id in favorites);
let srcIsFavorite = (favPos != -1);
if (srcIsFavorite)
return DND.DragMotionResult.MOVE_DROP;
@ -312,7 +704,7 @@ Dash.prototype = {
let app = null;
if (source instanceof AppDisplay.AppWellIcon) {
app = this._appSystem.get_app(source.getId());
} else if (source instanceof Workspace.WindowClone) {
} else if (source.metaWindow) {
app = this._tracker.get_window_app(source.metaWindow);
}
@ -330,7 +722,11 @@ Dash.prototype = {
let favPos = 0;
let children = this._box.get_children();
for (let i = 0; i < this._dragPlaceholderPos; i++) {
let childId = children[i]._delegate.app.get_id();
if (this._dragPlaceholder &&
children[i] == this._dragPlaceholder.actor)
continue;
let childId = children[i]._delegate.child._delegate.app.get_id();
if (childId == id)
continue;
if (childId in favorites)

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

@ -0,0 +1,212 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Util = imports.misc.util;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Calendar = imports.ui.calendar;
// in org.gnome.desktop.interface
const CLOCK_FORMAT_KEY = 'clock-format';
// in org.gnome.shell.clock
const CLOCK_SHOW_DATE_KEY = 'show-date';
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
function _onVertSepRepaint (area)
{
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let stippleColor = themeNode.get_color('-stipple-color');
let stippleWidth = themeNode.get_length('-stipple-width');
let x = Math.floor(width/2) + 0.5;
cr.moveTo(x, 0);
cr.lineTo(x, height);
Clutter.cairo_set_source_color(cr, stippleColor);
cr.setDash([1, 3], 1); // Hard-code for now
cr.setLineWidth(stippleWidth);
cr.stroke();
};
function DateMenuButton() {
this._init();
}
DateMenuButton.prototype = {
__proto__: PanelMenu.Button.prototype,
_init: function() {
let item;
let hbox;
let vbox;
this._eventSource = new Calendar.DBusEventSource();
let menuAlignment = 0.25;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
menuAlignment = 1.0 - menuAlignment;
PanelMenu.Button.prototype._init.call(this, menuAlignment);
this._clock = new St.Label();
this.actor.set_child(this._clock);
hbox = new St.BoxLayout({name: 'calendarArea'});
this.menu.addActor(hbox);
// Fill up the first column
vbox = new St.BoxLayout({vertical: true});
hbox.add(vbox);
// Date
this._date = new St.Label();
this._date.style_class = 'datemenu-date-label';
vbox.add(this._date);
this._eventList = new Calendar.EventsList(this._eventSource);
// Calendar
this._calendar = new Calendar.Calendar(this._eventSource);
this._calendar.connect('selected-date-changed',
Lang.bind(this, function(calendar, date) {
this._eventList.setDate(date);
}));
vbox.add(this._calendar.actor);
item = new PopupMenu.PopupSeparatorMenuItem();
item.setColumnWidths(1);
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
item = new PopupMenu.PopupMenuItem(_("Date and Time Settings"));
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
item.actor.can_focus = false;
vbox.add(item.actor);
// Add vertical separator
item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
pseudo_class: 'highlighted' });
item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
hbox.add(item);
// Fill up the second column
vbox = new St.BoxLayout({vertical: true});
hbox.add(vbox, { expand: true });
// Event list
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();
/* 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
}
}));
// Done with hbox for calendar and event list
// Track changes to clock settings
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
this._desktopSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
this._clockSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
// Start the clock
this._updateClockAndDate();
},
_updateClockAndDate: function() {
let format = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY);
let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY);
let clockFormat;
let dateFormat;
switch (format) {
case '24h':
if (showDate)
/* Translators: This is the time format with date used
in 24-hour mode. */
clockFormat = showSeconds ? _("%a %b %e, %R:%S")
: _("%a %b %e, %R");
else
/* Translators: This is the time format without date used
in 24-hour mode. */
clockFormat = showSeconds ? _("%a %R:%S")
: _("%a %R");
break;
case '12h':
default:
if (showDate)
/* Translators: This is a time format with date used
for AM/PM. */
clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p")
: _("%a %b %e, %l:%M %p");
else
/* Translators: This is a time format without date used
for AM/PM. */
clockFormat = showSeconds ? _("%a %l:%M:%S %p")
: _("%a %l:%M %p");
break;
}
let displayDate = new Date();
this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
/* Translators: This is the date format to use when the calendar popup is
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
*/
dateFormat = _("%A %B %e, %Y");
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
Mainloop.timeout_add_seconds(1, Lang.bind(this, this._updateClockAndDate));
return false;
},
_onPreferencesActivate: function() {
this.menu.close();
let app = Shell.AppSystem.get_default().get_app('gnome-datetime-panel.desktop');
app.activate(-1);
},
_onOpenCalendarActivate: function() {
this.menu.close();
// TODO: pass the selected day
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;
},
@ -112,11 +122,11 @@ _Draggable.prototype = {
return false;
this._buttonDown = true;
// special case St.Clickable: grabbing the pointer would mess up the
// special case St.Button: grabbing the pointer would mess up the
// internal state, so we start the drag manually on hover change
if (this.actor instanceof St.Clickable)
if (this.actor instanceof St.Button)
this.actor.connect('notify::hover',
Lang.bind(this, this._onClickableHoverChanged));
Lang.bind(this, this._onButtonHoverChanged));
else
this._grabActor();
@ -127,8 +137,8 @@ _Draggable.prototype = {
return false;
},
_onClickableHoverChanged: function(button) {
if (button.hover || !button.held)
_onButtonHoverChanged: function(button) {
if (button.hover || !button.pressed)
return;
button.fake_release();
@ -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;
@ -461,12 +478,14 @@ _Draggable.prototype = {
// its parent, adjusting for the fact that the parent
// may have been moved or scaled
let [parentX, parentY] = this._dragOrigParent.get_transformed_position();
x = parentX + this._dragOrigParent.scale_x * this._dragOrigX;
y = parentY + this._dragOrigParent.scale_y * this._dragOrigY;
let [parentWidth, parentHeight] = this._dragOrigParent.get_size();
let [parentScaledWidth, parentScaledHeight] = this._dragOrigParent.get_transformed_size();
let parentScale = parentScaledWidth / parentWidth;
let parentScale = 1.0;
if (parentWidth != 0)
parentScale = parentScaledWidth / parentWidth;
x = parentX + parentScale * this._dragOrigX;
y = parentY + parentScale * this._dragOrigY;
scale = this._dragOrigScale * parentScale;
} else {
// Snap back actor to its original stage position
@ -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

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

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

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

View File

@ -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);
@ -88,8 +93,6 @@ function init() {
_blockMethod('Clutter.Event.get_state', 'Shell.get_event_state',
'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.');
_blockMethod('Gdk.Display.get_device_state', 'global.get_pointer',
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
_blockMethod('Gdk.Window.get_device_position', 'global.get_pointer',
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');

View File

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

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

View File

@ -17,7 +17,8 @@ function BaseIcon(label, createIcon) {
BaseIcon.prototype = {
_init : function(label, params) {
params = Params.parse(params, { createIcon: null,
setSizeManually: false });
setSizeManually: false,
showLabel: true });
this.actor = new St.Bin({ style_class: 'overview-icon',
x_fill: true,
y_fill: true });
@ -40,42 +41,52 @@ BaseIcon.prototype = {
box.add_actor(this._iconBin);
this._name = new St.Label({ text: label });
box.add_actor(this._name);
if (params.showLabel) {
this._name = new St.Label({ text: label });
box.add_actor(this._name);
} else {
this._name = null;
}
if (params.createIcon)
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) {
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(-1);
let iconSize = availHeight;
let [iconMinHeight, iconNatHeight] = this._iconBin.get_preferred_height(-1);
let preferredHeight = labelNatHeight + this._spacing + iconNatHeight;
let labelHeight = availHeight >= preferredHeight ? labelNatHeight
: labelMinHeight;
let iconSize = availHeight - this._spacing - labelHeight;
let iconPadding = (availWidth - iconSize) / 2;
let [iconMinWidth, iconNatWidth] = this._iconBin.get_preferred_width(-1);
let preferredHeight = iconNatHeight;
let childBox = new Clutter.ActorBox();
childBox.x1 = iconPadding;
childBox.y1 = 0;
childBox.x2 = availWidth - iconPadding;
childBox.y2 = iconSize;
this._iconBin.allocate(childBox, flags);
if (this._name) {
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(-1);
preferredHeight += this._spacing + labelNatHeight;
childBox.x1 = 0;
childBox.x2 = availWidth;
childBox.y1 = iconSize + this._spacing;
childBox.y2 = childBox.y1 + labelHeight;
this._name.allocate(childBox, flags);
let labelHeight = availHeight >= preferredHeight ? labelNatHeight
: labelMinHeight;
iconSize -= this._spacing + labelHeight;
childBox.x1 = 0;
childBox.x2 = availWidth;
childBox.y1 = iconSize + this._spacing;
childBox.y2 = childBox.y1 + labelHeight;
this._name.allocate(childBox, flags);
}
childBox.x1 = Math.floor((availWidth - iconNatWidth) / 2);
childBox.y1 = Math.floor((iconSize - iconNatHeight) / 2);
childBox.x2 = childBox.x1 + iconNatWidth;
childBox.y2 = childBox.y1 + iconNatHeight;
this._iconBin.allocate(childBox, flags);
},
_getPreferredWidth: function(actor, forHeight, alloc) {
@ -84,9 +95,14 @@ BaseIcon.prototype = {
_getPreferredHeight: function(actor, forWidth, alloc) {
let [iconMinHeight, iconNatHeight] = this._iconBin.get_preferred_height(forWidth);
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(forWidth);
alloc.min_size = iconMinHeight + this._spacing + labelMinHeight;
alloc.natural_size = iconNatHeight + this._spacing + labelNatHeight;
alloc.min_size = iconMinHeight;
alloc.natural_size = iconNatHeight;
if (this._name) {
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(forWidth);
alloc.min_size += this._spacing + labelMinHeight;
alloc.natural_size += this._spacing + labelNatHeight;
}
},
// This can be overridden by a subclass, or by the createIcon
@ -99,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;
},
@ -116,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);
}
};
@ -165,8 +191,16 @@ IconGrid.prototype = {
alloc.natural_size = nColumns * this._item_size + totalSpacing;
},
_getPreferredHeight: function (grid, forWidth, alloc) {
_getVisibleChildren: function() {
let children = this._grid.get_children();
children = children.filter(function(actor) {
return actor.visible;
});
return children;
},
_getPreferredHeight: function (grid, forWidth, alloc) {
let children = this._getVisibleChildren();
let [nColumns, usedWidth] = this._computeLayout(forWidth);
let nRows;
if (nColumns > 0)
@ -182,7 +216,7 @@ IconGrid.prototype = {
},
_allocate: function (grid, box, flags) {
let children = this._grid.get_children();
let children = this._getVisibleChildren();
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
@ -247,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

@ -1,6 +1,7 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Cogl = imports.gi.Cogl;
const GConf = imports.gi.GConf;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
@ -13,6 +14,7 @@ const Mainloop = imports.mainloop;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const History = imports.misc.history;
const ExtensionSystem = imports.ui.extensionSystem;
const Link = imports.ui.link;
const Tweener = imports.ui.tweener;
@ -25,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; ' +
@ -36,6 +39,8 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
'const it = Main.lookingGlass.getIt(); ' +
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
const HISTORY_KEY = 'looking-glass-history';
function Notebook() {
this._init();
}
@ -359,6 +364,30 @@ ObjInspector.prototype = {
}
};
function addBorderPaintHook(actor) {
let signalId = actor.connect_after('paint',
function () {
let color = new Cogl.Color();
color.init_from_4ub(0xff, 0, 0, 0xc4);
Cogl.set_source_color(color);
let geom = actor.get_allocation_geometry();
let width = 2;
// clockwise order
Cogl.rectangle(0, 0, geom.width, width);
Cogl.rectangle(geom.width - width, width,
geom.width, geom.height);
Cogl.rectangle(0, geom.height,
geom.width - width, geom.height - width);
Cogl.rectangle(0, geom.height - width,
width, width);
});
actor.queue_redraw();
return signalId;
}
function Inspector() {
this._init();
}
@ -398,6 +427,9 @@ Inspector.prototype = {
},
_allocate: function(actor, box, flags) {
if (!this._eventHandler)
return;
let primary = global.get_primary_monitor();
let [minWidth, minHeight, natWidth, natHeight] =
@ -415,6 +447,7 @@ Inspector.prototype = {
Clutter.ungrab_pointer(this._eventHandler);
Clutter.ungrab_keyboard(this._eventHandler);
this._eventHandler.destroy();
this._eventHandler = null;
this.emit('closed');
},
@ -490,10 +523,13 @@ Inspector.prototype = {
let position = '[inspect x: ' + stageX + ' y: ' + stageY + ']';
this._displayText.text = '';
this._displayText.text = position + ' ' + this._target;
if (this._borderPaintTarget != null)
this._borderPaintTarget.disconnect(this._borderPaintId);
this._borderPaintTarget = this._target;
this._borderPaintId = Shell.add_hook_paint_red_border(this._target);
if (this._borderPaintTarget != this._target) {
if (this._borderPaintTarget != null)
this._borderPaintTarget.disconnect(this._borderPaintId);
this._borderPaintTarget = this._target;
this._borderPaintId = addBorderPaintHook(this._target);
}
}
};
@ -639,18 +675,10 @@ function LookingGlass() {
LookingGlass.prototype = {
_init : function() {
this._idleHistorySaveId = 0;
let historyPath = global.userdatadir + '/lookingglass-history.txt';
this._historyFile = Gio.file_new_for_path(historyPath);
this._savedText = null;
this._historyNavIndex = -1;
this._history = [];
this._borderPaintTarget = null;
this._borderPaintId = 0;
this._borderDestroyId = 0;
this._readHistory();
this._open = false;
this._offset = 0;
@ -663,11 +691,11 @@ LookingGlass.prototype = {
style_class: 'lg-dialog',
vertical: true,
visible: false });
this.actor.connect('key-press-event', Lang.bind(this, this._globalKeyPressEvent));
let gconf = GConf.Client.get_default();
gconf.add_dir('/desktop/gnome/interface', GConf.ClientPreloadType.PRELOAD_NONE);
gconf.notify_add('/desktop/gnome/interface/monospace_font_name',
Lang.bind(this, this._updateFont));
this._interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._interfaceSettings.connect('changed::monospace-font-name',
Lang.bind(this, this._updateFont));
this._updateFont();
Main.uiGroup.add_actor(this.actor);
@ -747,39 +775,15 @@ LookingGlass.prototype = {
if (text == '')
return true;
this._evaluate(text);
this._historyNavIndex = -1;
return true;
}));
this._entry.clutter_text.connect('key-press-event', Lang.bind(this, function(o, e) {
let symbol = e.get_key_symbol();
if (symbol == Clutter.Up) {
if (this._historyNavIndex >= this._history.length - 1)
return true;
this._historyNavIndex++;
if (this._historyNavIndex == 0)
this._savedText = this._entry.text;
this._entry.text = this._history[this._history.length - this._historyNavIndex - 1];
return true;
} else if (symbol == Clutter.Down) {
if (this._historyNavIndex <= 0)
return true;
this._historyNavIndex--;
if (this._historyNavIndex < 0)
this._entry.text = this._savedText;
else
this._entry.text = this._history[this._history.length - this._historyNavIndex - 1];
return true;
} else {
this._historyNavIndex = -1;
this._savedText = null;
return false;
}
}));
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
entry: this._entry.clutter_text });
},
_updateFont: function() {
let gconf = GConf.Client.get_default();
let fontName = gconf.get_string('/desktop/gnome/interface/monospace_font_name');
let fontName = this._interfaceSettings.get_string('monospace-font-name');
// This is mishandled by the scanner - should by Pango.FontDescription_from_string(fontName);
// https://bugzilla.gnome.org/show_bug.cgi?id=595889
let fontDesc = Pango.font_description_from_string(fontName);
@ -790,29 +794,6 @@ LookingGlass.prototype = {
+ 'font-family: "' + fontDesc.get_family() + '";';
},
_readHistory: function () {
if (!this._historyFile.query_exists(null))
return;
let [result, contents, length, etag] = this._historyFile.load_contents(null);
this._history = contents.split('\n').filter(function (e) { return e != ''; });
},
_queueHistorySave: function() {
if (this._idleHistorySaveId > 0)
return;
this._idleHistorySaveId = Mainloop.timeout_add_seconds(5, Lang.bind(this, this._doSaveHistory));
},
_doSaveHistory: function () {
this._idleHistorySaveId = false;
let output = this._historyFile.replace(null, true, Gio.FileCreateFlags.NONE, null);
let dataOut = new Gio.DataOutputStream({ base_stream: output });
dataOut.put_string(this._history.join('\n'), null);
dataOut.put_string('\n', null);
dataOut.close(null);
return false;
},
_pushResult: function(command, obj) {
let index = this._results.length + this._offset;
let result = new Result('>>> ' + command, obj, index);
@ -824,7 +805,7 @@ LookingGlass.prototype = {
}
if (obj instanceof Clutter.Actor) {
this._borderPaintTarget = obj;
this._borderPaintId = Shell.add_hook_paint_red_border(obj);
this._borderPaintId = addBorderPaintHook(obj);
this._borderDestroyId = obj.connect('destroy', Lang.bind(this, function () {
this._borderDestroyId = 0;
this._borderPaintTarget = null;
@ -843,8 +824,7 @@ LookingGlass.prototype = {
},
_evaluate : function(command) {
this._history.push(command);
this._queueHistorySave();
this._history.addItem(command);
let fullCmd = commandHeader + command;
@ -925,20 +905,16 @@ LookingGlass.prototype = {
if (this._open)
return;
if (!Main.pushModal(this.actor))
if (!Main.pushModal(this._entry))
return;
this._keyPressEventId = global.stage.connect('key-press-event',
Lang.bind(this, this._globalKeyPressEvent));
this.actor.show();
this.actor.lower(Main.chrome.actor);
this._open = true;
this._history.lastItem();
Tweener.removeTweens(this.actor);
global.stage.set_key_focus(this._entry);
// We inverse compensate for the slow-down so you can change the factor
// through LookingGlass without long waits.
Tweener.addTween(this.actor, { time: 0.5 / St.get_slow_down_factor(),
@ -951,12 +927,8 @@ LookingGlass.prototype = {
if (!this._open)
return;
if (this._keyPressEventId)
global.stage.disconnect(this._keyPressEventId);
this._objInspector.actor.hide();
this._historyNavIndex = -1;
this._open = false;
Tweener.removeTweens(this.actor);
@ -966,7 +938,7 @@ LookingGlass.prototype = {
this._borderPaintTarget = null;
}
Main.popModal(this.actor);
Main.popModal(this._entry);
Tweener.addTween(this.actor, { time: 0.5 / St.get_slow_down_factor(),
transition: 'easeOutQuad',

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -17,8 +17,13 @@ const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Chrome = imports.ui.chrome;
const CtrlAltTab = imports.ui.ctrlAltTab;
const EndSessionDialog = imports.ui.endSessionDialog;
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
const Environment = imports.ui.environment;
const ExtensionSystem = imports.ui.extensionSystem;
const MessageTray = imports.ui.messageTray;
@ -34,13 +39,16 @@ const ShellDBus = imports.ui.shellDBus;
const TelepathyClient = imports.ui.telepathyClient;
const WindowManager = imports.ui.windowManager;
const Magnifier = imports.ui.magnifier;
const XdndHandler = imports.ui.xdndHandler;
const StatusIconDispatcher = imports.ui.statusIconDispatcher;
const Util = imports.misc.util;
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
let chrome = null;
let panel = null;
let hotCorners = [];
let placesManager = null;
let overview = null;
let runDialog = null;
@ -50,15 +58,19 @@ let messageTray = null;
let notificationDaemon = null;
let windowAttentionHandler = null;
let telepathyClient = null;
let ctrlAltTabManager = null;
let recorder = null;
let shellDBusService = null;
let modalCount = 0;
let modalActorFocusStack = [];
let uiGroup = null;
let magnifier = null;
let xdndHandler = null;
let statusIconDispatcher = null;
let _errorLogStack = [];
let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
let background = null;
@ -74,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
@ -84,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
@ -103,10 +121,8 @@ function start() {
global.stage.color = DEFAULT_BACKGROUND_COLOR;
global.stage.no_clear_hint = true;
let themeContext = St.ThemeContext.get_for_stage (global.stage);
let stylesheetPath = global.datadir + '/theme/gnome-shell.css';
let theme = new St.Theme ({ application_stylesheet: stylesheetPath });
themeContext.set_theme (theme);
_defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
loadTheme();
let shellwm = global.window_manager;
shellwm.takeover_keybinding('panel_main_menu');
@ -120,11 +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();
@ -136,6 +155,9 @@ function start() {
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
telepathyClient = new TelepathyClient.Client();
overview.init();
statusIconDispatcher.start(messageTray.actor);
_startDate = new Date();
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
@ -162,11 +184,24 @@ function start() {
}
});
global.gdk_screen.connect('monitors-changed', _relayout);
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT, false, -1, 1);
// Provide the bus object for gnome-session to
// initiate logouts.
EndSessionDialog.init();
// Attempt to become a PolicyKit authentication agent
PolkitAuthenticationAgent.init()
global.screen.connect('monitors-changed', _relayout);
ExtensionSystem.init();
ExtensionSystem.loadExtensions();
// Perform initial relayout here
_relayout();
panel.startStatusArea();
panel.startupAnimation();
let display = global.screen.get_display();
@ -174,20 +209,233 @@ function start() {
global.stage.connect('captured-event', _globalKeyPressHandler);
// Perform initial relayout here
_relayout();
_log('info', 'loaded at ' + _startDate);
log('GNOME Shell started at ' + _startDate);
Mainloop.idle_add(_removeUnusedWorkspaces);
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
if (perfModuleName) {
let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT");
let module = eval('imports.perf.' + perfModuleName + ';');
Scripting.runPerfScript(module, perfOutput);
}
global.screen.connect('notify::n-workspaces', _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++) {
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++) {
let win = windows[i];
if (win.get_meta_window().is_on_all_workspaces())
continue;
let workspaceIndex = win.get_workspace();
emptyWorkspaces[workspaceIndex] = false;
}
// If we don't have an empty workspace at the end, add one
if (!emptyWorkspaces[emptyWorkspaces.length -1]) {
global.screen.append_new_workspace(false, global.get_current_time());
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);
}
function _nWorkspacesChanged() {
let oldNumWorkspaces = _workspaces.length;
let newNumWorkspaces = global.screen.n_workspaces;
if (oldNumWorkspaces == newNumWorkspaces)
return false;
let lostWorkspaces = [];
if (newNumWorkspaces > oldNumWorkspaces) {
let w;
// Assume workspaces are only added at the end
for (w = oldNumWorkspaces; w < newNumWorkspaces; w++)
_workspaces[w] = global.screen.get_workspace_by_index(w);
for (w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let workspace = _workspaces[w];
workspace._windowAddedId = workspace.connect('window-added', _queueCheckWorkspaces);
workspace._windowRemovedId = workspace.connect('window-removed', _windowRemoved);
}
} else {
// Assume workspaces are only removed sequentially
// (e.g. 2,3,4 - not 2,4,7)
let removedIndex;
let removedNum = oldNumWorkspaces - newNumWorkspaces;
for (let w = 0; w < oldNumWorkspaces; w++) {
let workspace = global.screen.get_workspace_by_index(w);
if (_workspaces[w] != workspace) {
removedIndex = w;
break;
}
}
let lostWorkspaces = _workspaces.splice(removedIndex, removedNum);
lostWorkspaces.forEach(function(workspace) {
workspace.disconnect(workspace._windowAddedId);
workspace.disconnect(workspace._windowRemovedId);
});
}
_queueCheckWorkspaces();
return false;
}
/**
* getThemeStylesheet:
*
* Get the theme CSS file that the shell will load
*
* Returns: A file path that contains the theme CSS,
* null if using the default
*/
function getThemeStylesheet()
{
return _cssStylesheet;
}
/**
* setThemeStylesheet:
* @cssStylesheet: A file path that contains the theme CSS,
* set it to null to use the default
*
* Set the theme CSS file that the shell will load
*/
function setThemeStylesheet(cssStylesheet)
{
_cssStylesheet = cssStylesheet;
}
/**
* loadTheme:
*
* Reloads the theme CSS file
*/
function loadTheme() {
let themeContext = St.ThemeContext.get_for_stage (global.stage);
let cssStylesheet = _defaultCssStylesheet;
if (_cssStylesheet != null)
cssStylesheet = _cssStylesheet;
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
themeContext.set_theme (theme);
}
/**
* 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);
}
/**
@ -232,45 +480,90 @@ 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
// in the overview, we just hide the overview. The positions
// will be updated when it is next shown. We do the same for
// the calendar popdown.
// will be updated when it is next shown.
overview.hide();
panel.hideCalendar();
}
// metacity-clutter currently uses the same prefs as plain metacity,
// which probably means we'll be starting out with multiple workspaces;
// remove any unused ones. (We do this from an idle handler, because
// global.get_window_actors() still returns NULL at the point when start()
// is called.)
function _removeUnusedWorkspaces() {
function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) {
return win.get_workspace() == workspaceIndex ||
(win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
}
let windows = global.get_window_actors();
let maxWorkspace = 0;
for (let i = 0; i < windows.length; i++) {
let win = windows[i];
if (!win.get_meta_window().is_on_all_workspaces() &&
win.get_workspace() > maxWorkspace) {
maxWorkspace = win.get_workspace();
}
}
let screen = global.screen;
if (screen.n_workspaces > maxWorkspace) {
for (let w = screen.n_workspaces - 1; w > maxWorkspace; w--) {
let workspace = screen.get_workspace_by_index(w);
screen.remove_workspace(workspace, 0);
}
}
return false;
function getWindowActorsForWorkspace(workspaceIndex) {
return global.get_window_actors().filter(function (win) {
return isWindowActorDisplayedOnWorkspace(win, workspaceIndex);
});
}
// This function encapsulates hacks to make certain global keybindings
@ -278,57 +571,67 @@ function _removeUnusedWorkspaces() {
// are disabled with a global grab. (When there is a global grab, then
// all key events will be delivered to the stage, so ::captured-event
// on the stage can be used for global keybindings.)
//
// We expect to need to conditionally enable just a few keybindings
// depending on circumstance; the main hackiness here is that we are
// assuming that keybindings have their default values; really we
// should be asking Mutter to resolve the key into an action and then
// base our handling based on the action.
function _globalKeyPressHandler(actor, event) {
if (modalCount == 0)
return false;
if (event.type() != Clutter.EventType.KEY_RELEASE)
if (event.type() != Clutter.EventType.KEY_PRESS)
return false;
let symbol = event.get_key_symbol();
let keyCode = event.get_key_code();
let modifierState = Shell.get_event_state(event);
// Check the overview key first, this isn't a Meta.KeyBindingAction yet
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
// The super key is the default for triggering the overview, and should
// get us out of the overview when we are already in it.
if (overview.visible)
overview.hide();
let display = global.screen.get_display();
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
let action = display.get_keybinding_action(keyCode, modifierState);
// The screenshot action should always be available (even if a
// modal dialog is present)
if (action == Meta.KeyBindingAction.COMMAND_SCREENSHOT) {
let gconf = GConf.Client.get_default();
let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot');
if (command != null && command != '')
Util.spawnCommandLine(command);
return true;
}
// Whitelist some of the Metacity actions
let display = global.screen.get_display();
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
// Other bindings are only available when the overview is up and
// no modal dialog is present.
if (!overview.visible || modalCount > 1)
return false;
// This isn't a Meta.KeyBindingAction yet
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
overview.hide();
return true;
}
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
let action = display.get_keybinding_action(keyCode, modifierState);
switch (action) {
case Meta.KeyBindingAction.COMMAND_SCREENSHOT:
let gconf = GConf.Client.get_default();
let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot');
if (command != null && command != '') {
let [ok, len, args] = GLib.shell_parse_argv(command);
let p = new Shell.Process({'args' : args});
p.run();
}
// left/right would effectively act as synonyms for up/down if we enabled them;
// but that could be considered confusing; we also disable them in the main view.
//
// case Meta.KeyBindingAction.WORKSPACE_LEFT:
// wm.actionMoveWorkspaceLeft();
// return true;
// case Meta.KeyBindingAction.WORKSPACE_RIGHT:
// wm.actionMoveWorkspaceRight();
// return true;
case Meta.KeyBindingAction.WORKSPACE_UP:
wm.actionMoveWorkspaceUp();
return true;
case Meta.KeyBindingAction.WORKSPACE_LEFT:
wm.actionMoveWorkspaceLeft();
return true;
case Meta.KeyBindingAction.WORKSPACE_RIGHT:
wm.actionMoveWorkspaceRight();
case Meta.KeyBindingAction.WORKSPACE_DOWN:
wm.actionMoveWorkspaceDown();
return true;
case Meta.KeyBindingAction.PANEL_RUN_DIALOG:
case Meta.KeyBindingAction.COMMAND_2:
getRunDialog().open();
return true;
case Meta.KeyBindingAction.PANEL_MAIN_MENU:
overview.hide();
return true;
case Meta.KeyBindingAction.SWITCH_PANELS:
ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK);
return true;
}
return false;
@ -336,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;
}
@ -347,21 +648,29 @@ function _findModal(actor) {
/**
* pushModal:
* @actor: #ClutterActor which will be given keyboard focus
* @timestamp: optional timestamp
*
* Ensure we are in a mode where all keyboard and mouse input goes to
* the stage. Multiple calls to this function act in a stacking fashion;
* the effect will be undone when an equal number of popModal() invocations
* have been made.
* the stage, and focus @actor. Multiple calls to this function act in
* a stacking fashion; the effect will be undone when an equal number
* of popModal() invocations have been made.
*
* Next, record the current Clutter keyboard focus on a stack. If the modal stack
* returns to this actor, reset the focus to the actor which was focused
* at the time pushModal() was invoked.
* Next, record the current Clutter keyboard focus on a stack. If the
* modal stack returns to this actor, reset the focus to the actor
* which was focused at the time pushModal() was invoked.
*
* @timestamp is optionally used to associate the call with a specific user
* initiated event. If not provided then the value of
* global.get_current_time() is assumed.
*
* Returns: true iff we successfully acquired a grab or already had one
*/
function pushModal(actor) {
function pushModal(actor, timestamp) {
if (timestamp == undefined)
timestamp = global.get_current_time();
if (modalCount == 0) {
if (!global.begin_modal(global.get_current_time())) {
if (!global.begin_modal(timestamp)) {
log('pushModal: invocation of begin_modal failed');
return false;
}
@ -370,52 +679,80 @@ function pushModal(actor) {
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(null);
global.stage.set_key_focus(actor);
return true;
}
/**
* popModal:
* @actor: #ClutterActor passed to original invocation of pushModal().
* @timestamp: optional timestamp
*
* Reverse the effect of pushModal(). If this invocation is undoing
* the topmost invocation, then the focus will be restored to the
* previous focus at the time when pushModal() was invoked.
*
* @timestamp is optionally used to associate the call with a specific user
* initiated event. If not provided then the value of
* global.get_current_time() is assumed.
*/
function popModal(actor) {
modalCount -= 1;
function popModal(actor, timestamp) {
if (timestamp == undefined)
timestamp = global.get_current_time();
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.end_modal(global.get_current_time());
global.end_modal(timestamp);
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
}

File diff suppressed because it is too large Load Diff

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

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

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;
@ -9,9 +10,11 @@ const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Config = imports.misc.config;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Params = imports.misc.params;
const Util = imports.misc.util;
let nextNotificationId = 1;
@ -91,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 = {};
@ -115,31 +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');
// kill the notification-daemon. pkill is more portable
// than killall, but on Linux at least it won't match if
// you pass more than 15 characters of the process name...
// However, if you use the '-f' flag to match the entire
// command line, it will work, but we have to be careful
// in that case that we don't match 'gedit
// notification-daemon.c' or whatever...
let p = new Shell.Process({ args: ['pkill', '-f',
'^([^ ]*/)?(notification-daemon|notify-osd)$']});
p.run();
}
},
_iconForNotificationData: function(icon, hints, size) {
let textureCache = St.TextureCache.get_default();
@ -153,9 +121,9 @@ NotificationDaemon.prototype = {
return new St.Icon({ icon_name: icon,
icon_type: St.IconType.FULLCOLOR,
icon_size: size });
} else if (hints.icon_data) {
} else if (hints['image-data']) {
let [width, height, rowStride, hasAlpha,
bitsPerSample, nChannels, data] = hints.icon_data;
bitsPerSample, nChannels, data] = hints['image-data'];
return textureCache.load_from_raw(data, data.length, hasAlpha,
width, height, rowStride, size);
} else {
@ -175,14 +143,43 @@ NotificationDaemon.prototype = {
}
},
_newSource: function(title, pid) {
let source = new Source(title, pid);
this._sources[pid] = source;
// Returns the source associated with ndata.notification if it is set.
// Otherwise, returns the source associated with the pid if one is
// stored in this._sources and the notification is not transient.
// Otherwise, creates a new source as long as pid is provided.
//
// Either a pid or ndata.notification is needed to retrieve or
// create a source.
_getSource: function(title, pid, ndata) {
if (!pid && !(ndata && ndata.notification))
return null;
source.connect('destroy', Lang.bind(this,
function() {
delete this._sources[pid];
}));
// We use notification's source for the notifications we still have
// around that are getting replaced because we don't keep sources
// for transient notifications in this._sources, but we still want
// the notification associated with them to get replaced correctly.
if (ndata && ndata.notification)
return ndata.notification.source;
let isForTransientNotification = (ndata && ndata.hints['transient'] == true);
// We don't want to override a persistent notification
// with a transient one from the same sender, so we
// always create a new source object for new transient notifications
// and never add it to this._sources .
if (!isForTransientNotification && this._sources[pid])
return this._sources[pid];
let source = new Source(title, pid);
source.setTransient(isForTransientNotification);
if (!isForTransientNotification) {
this._sources[pid] = source;
source.connect('destroy', Lang.bind(this,
function() {
delete this._sources[pid];
}));
}
Main.messageTray.add(source);
return source;
@ -192,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++;
@ -216,6 +215,15 @@ NotificationDaemon.prototype = {
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
// Be compatible with the various hints for image data
// 'image-data' is the latest name of this hint, introduced in 1.2
if (!hints['image-data']) {
if (hints['image_data'])
hints['image-data'] = hints['image_data']; // version 1.1 of the spec
else if (hints['icon_data'])
hints['image-data'] = hints['icon_data']; // previous versions of the spec
}
let ndata = { appName: appName,
icon: icon,
summary: summary,
@ -234,7 +242,8 @@ NotificationDaemon.prototype = {
let sender = DBus.getCurrentMessageContext().sender;
let pid = this._senderToPid[sender];
let source = pid ? this._sources[pid] : null;
let source = this._getSource(appName, pid, ndata);
if (source) {
this._notifyForSource(source, ndata);
@ -255,16 +264,23 @@ NotificationDaemon.prototype = {
if (!ndata)
return;
this._senderToPid[sender] = pid;
source = this._sources[pid];
if (!source)
source = this._newSource(appName, pid);
source.connect('destroy', Lang.bind(this,
function() {
delete this._senderToPid[sender];
}));
source = this._getSource(appName, pid, ndata);
// We only store sender-pid entries for persistent sources.
// Removing the entries once the source is destroyed
// would result in the entries associated with transient
// sources removed once the notification is shown anyway.
// However, keeping these pairs would mean that we would
// possibly remove an entry associated with a persistent
// source when a transient source for the same sender is
// distroyed.
if (!source.isTransient) {
this._senderToPid[sender] = pid;
source.connect('destroy', Lang.bind(this,
function() {
delete this._senderToPid[sender];
}));
}
this._notifyForSource(source, ndata);
}));
@ -283,15 +299,27 @@ NotificationDaemon.prototype = {
{ icon: iconActor,
bannerMarkup: true });
ndata.notification = notification;
notification.connect('clicked', Lang.bind(this,
function(n) {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
}));
notification.connect('destroy', Lang.bind(this,
function(n) {
function(n, reason) {
delete this._notifications[id];
let notificationClosedReason;
switch (reason) {
case MessageTray.NotificationDestroyedReason.EXPIRED:
notificationClosedReason = NotificationClosedReason.EXPIRED;
break;
case MessageTray.NotificationDestroyedReason.DISMISSED:
notificationClosedReason = NotificationClosedReason.DISMISSED;
break;
case MessageTray.NotificationDestroyedReason.SOURCE_CLOSED:
notificationClosedReason = NotificationClosedReason.APP_CLOSED;
break;
}
this._emitNotificationClosed(id, notificationClosedReason);
}));
notification.connect('action-invoked', Lang.bind(this,
function(n, actionId) {
this._emitActionInvoked(id, actionId);
}));
notification.connect('action-invoked', Lang.bind(this, this._actionInvoked, source, id));
} else {
notification.update(summary, body, { icon: iconActor,
bannerMarkup: true,
@ -303,21 +331,33 @@ NotificationDaemon.prototype = {
for (let i = 0; i < actions.length - 1; i += 2)
notification.addButton(actions[i], actions[i + 1]);
}
notification.setUrgent(hints.urgency == Urgency.CRITICAL);
switch (hints.urgency) {
case Urgency.LOW:
notification.setUrgency(MessageTray.Urgency.LOW);
break;
case Urgency.NORMAL:
notification.setUrgency(MessageTray.Urgency.NORMAL);
break;
case Urgency.CRITICAL:
notification.setUrgency(MessageTray.Urgency.CRITICAL);
break;
}
notification.setResident(hints.resident == true);
// 'transient' is a reserved keyword in JS, so we have to retrieve the value
// of the 'transient' hint with hints['transient'] rather than hints.transient
notification.setTransient(hints['transient'] == true);
let sourceIconActor = source.useNotificationIcon ? this._iconForNotificationData(icon, hints, source.ICON_SIZE) : null;
source.notify(notification, sourceIconActor);
source.processNotification(notification, sourceIconActor);
},
CloseNotification: function(id) {
let ndata = this._notifications[id];
if (ndata) {
if (ndata.notification)
ndata.notification.destroy();
ndata.notification.destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
delete this._notifications[id];
}
this._emitNotificationClosed(id, NotificationClosedReason.APP_CLOSED);
},
GetCapabilities: function() {
@ -337,10 +377,10 @@ NotificationDaemon.prototype = {
GetServerInformation: function() {
return [
'GNOME Shell',
Config.PACKAGE_NAME,
'GNOME',
'0.1', // FIXME, get this from somewhere
'1.0'
Config.PACKAGE_VERSION,
'1.2'
];
},
@ -352,17 +392,12 @@ NotificationDaemon.prototype = {
for (let id in this._sources) {
let source = this._sources[id];
if (source.app == tracker.focus_app) {
source.activated();
source.destroyNonResidentNotifications();
return;
}
}
},
_actionInvoked: function(notification, action, source, id) {
source.activated();
this._emitActionInvoked(id, action);
},
_emitNotificationClosed: function(id, reason) {
DBus.session.emit_signal('/org/freedesktop/Notifications',
'org.freedesktop.Notifications',
@ -378,9 +413,7 @@ NotificationDaemon.prototype = {
},
_onTrayIconAdded: function(o, icon) {
let source = this._sources[icon.pid];
if (!source)
source = this._newSource(icon.title || icon.wm_class || _("Unknown"), icon.pid);
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null);
source.setTrayIcon(icon);
},
@ -404,30 +437,74 @@ 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() {
if (this.app)
return;
this.app = Shell.WindowTracker.get_default().get_app_from_pid(this._pid);
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)
if (this.useNotificationIcon) {
// notification-based icons (ie, not a trayicon) or if it was unset before
if (!this._trayIcon) {
this.useNotificationIcon = false;
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
}
@ -436,17 +513,29 @@ Source.prototype = {
setTrayIcon: function(icon) {
this._setSummaryIcon(icon);
this.useNotificationIcon = false;
this._isTrayIcon = true;
this._trayIcon = icon;
},
_notificationClicked: function(notification) {
notification.destroy();
open: function(notification) {
this.destroyNonResidentNotifications();
this.openApp();
this.activated();
},
activated: 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();
},
@ -459,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

@ -1,18 +1,21 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Lang = imports.lang;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Gdk = imports.gi.Gdk;
const AppDisplay = imports.ui.appDisplay;
const Dash = imports.ui.dash;
const DND = imports.ui.dnd;
const DocDisplay = imports.ui.docDisplay;
const GenericDisplay = imports.ui.genericDisplay;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
@ -21,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;
@ -28,31 +32,19 @@ const ANIMATION_TIME = 0.25;
// We split the screen vertically between the dash and the view selector.
const DASH_SPLIT_FRACTION = 0.1;
const SHELL_INFO_HIDE_TIMEOUT = 10;
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
function Source() {
this._init();
}
const SwipeScrollDirection = {
NONE: 0,
HORIZONTAL: 1,
VERTICAL: 2
};
Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function() {
MessageTray.Source.prototype._init.call(this,
"System Information");
this._setSummaryIcon(this.createNotificationIcon());
},
createNotificationIcon: function() {
return new St.Icon({ icon_name: 'info',
icon_type: St.IconType.FULLCOLOR,
icon_size: this.ICON_SIZE });
},
_notificationClicked: function() {
this.destroy();
}
}
const SwipeScrollResult = {
CANCEL: 0,
SWIPE: 1,
CLICK: 2
};
function ShellInfo() {
this._init();
@ -61,14 +53,10 @@ function ShellInfo() {
ShellInfo.prototype = {
_init: function() {
this._source = null;
this._timeoutId = 0;
this._undoCallback = null;
},
_onUndoClicked: function() {
Mainloop.source_remove(this._timeoutId);
this._timeoutId = 0;
if (this._undoCallback)
this._undoCallback();
this._undoCallback = null;
@ -77,22 +65,9 @@ ShellInfo.prototype = {
this._source.destroy();
},
_onTimeout: function() {
this._timeoutId = 0;
if (this._source)
this._source.destroy();
return false;
},
setMessage: function(text, undoCallback, undoLabel) {
if (this._timeoutId)
Mainloop.source_remove(this._timeoutId);
this._timeoutId = Mainloop.timeout_add_seconds(SHELL_INFO_HIDE_TIMEOUT,
Lang.bind(this, this._onTimeout));
if (this._source == null) {
this._source = new Source();
this._source = new MessageTray.SystemNotificationSource();
this._source.connect('destroy', Lang.bind(this,
function() {
this._source = null;
@ -100,11 +75,15 @@ 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);
this._undoCallback = undoCallback;
if (undoCallback) {
@ -135,7 +114,8 @@ Overview.prototype = {
this._spacing = 0;
this._group = new St.Group({ name: 'overview' });
this._group = new St.Group({ name: 'overview',
reactive: true });
this._group._delegate = this;
this._group.connect('style-changed',
Lang.bind(this, function() {
@ -147,11 +127,17 @@ Overview.prototype = {
}
}));
this.shellInfo = new ShellInfo();
this._scrollDirection = SwipeScrollDirection.NONE;
this._scrollAdjustment = null;
this._capturedEventId = 0;
this._buttonPressId = 0;
this._workspacesDisplay = null;
this.visible = false;
this.visible = false; // animating to overview, in overview, animating out
this._shown = false; // show() and not hide()
this._shownTemporarily = false; // showTemporarily() and not hideTemporarily()
this._modal = false; // have a modal grab
this.animationInProgress = false;
this._hideInProgress = false;
@ -167,14 +153,40 @@ Overview.prototype = {
this._group.hide();
global.overlay_group.add_actor(this._group);
this._coverPane.hide();
// XDND
this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion)
};
Main.xdndHandler.connect('drag-begin', Lang.bind(this, this._onDragBegin));
Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
this._windowSwitchTimeoutId = 0;
this._windowSwitchTimestamp = 0;
this._lastActiveWorkspaceIndex = -1;
this._lastHoveredWindow = null;
this._needsFakePointerEvent = false;
this.workspaces = null;
},
// The members we construct that are implemented in JS might
// want to access the overview as Main.overview to connect
// signal handlers and so forth. So we create them after
// construction in this init() method.
init: function() {
this.shellInfo = new ShellInfo();
this.viewSelector = new ViewSelector.ViewSelector();
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());
@ -183,14 +195,234 @@ Overview.prototype = {
this.viewSelector.addSearchProvider(new DocDisplay.DocSearchProvider());
// TODO - recalculate everything when desktop size changes
this._dash = new Dash.Dash();
this._group.add_actor(this._dash.actor);
this._dash.actor.add_constraint(this.viewSelector.constrainY);
this._dash.actor.add_constraint(this.viewSelector.constrainHeight);
this.dash = new Dash.Dash();
this._group.add_actor(this.dash.actor);
this.dash.actor.add_constraint(this.viewSelector.constrainY);
this.dash.actor.add_constraint(this.viewSelector.constrainHeight);
this._coverPane.lower_bottom();
// 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');
this.workspaces = null;
},
_onDragBegin: function() {
DND.addDragMonitor(this._dragMonitor);
// Remember the workspace we started from
this._lastActiveWorkspaceIndex = global.screen.get_active_workspace_index();
},
_onDragEnd: function(time) {
// In case the drag was canceled while in the overview
// we have to go back to where we started and hide
// the overview
if (this._shownTemporarily) {
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() {
let display = Gdk.Display.get_default();
let deviceManager = display.get_device_manager();
let pointer = deviceManager.get_client_pointer();
let [screen, pointerX, pointerY] = pointer.get_position();
pointer.warp(screen, pointerX, pointerY);
},
_onDragMotion: function(dragEvent) {
let targetIsWindow = dragEvent.targetActor &&
dragEvent.targetActor._delegate &&
dragEvent.targetActor._delegate.metaWindow &&
!(dragEvent.targetActor._delegate instanceof WorkspaceThumbnail.WindowClone);
this._windowSwitchTimestamp = global.get_current_time();
if (targetIsWindow &&
dragEvent.targetActor._delegate.metaWindow == this._lastHoveredWindow)
return DND.DragMotionResult.CONTINUE;
this._lastHoveredWindow = null;
this._resetWindowSwitchTimeout();
if (targetIsWindow) {
this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow;
this._windowSwitchTimeoutId = Mainloop.timeout_add(DND_WINDOW_SWITCH_TIMEOUT,
Lang.bind(this, function() {
this._needsFakePointerEvent = true;
Main.activateWindow(dragEvent.targetActor._delegate.metaWindow,
this._windowSwitchTimestamp);
this.hideTemporarily();
this._lastHoveredWindow = null;
}));
}
return DND.DragMotionResult.CONTINUE;
},
setScrollAdjustment: function(adjustment, direction) {
this._scrollAdjustment = adjustment;
if (this._scrollAdjustment == null)
this._scrollDirection = SwipeScrollDirection.NONE;
else
this._scrollDirection = direction;
},
_onButtonPress: function(actor, event) {
if (this._scrollDirection == SwipeScrollDirection.NONE)
return;
let [stageX, stageY] = event.get_coords();
this._dragStartX = this._dragX = stageX;
this._dragStartY = this._dragY = stageY;
this._dragStartValue = this._scrollAdjustment.value;
this._lastMotionTime = -1; // used to track "stopping" while swipe-scrolling
this._capturedEventId = global.stage.connect('captured-event',
Lang.bind(this, this._onCapturedEvent));
this.emit('swipe-scroll-begin');
},
_onCapturedEvent: function(actor, event) {
let stageX, stageY;
let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
switch(event.type()) {
case Clutter.EventType.BUTTON_RELEASE:
[stageX, stageY] = event.get_coords();
// default to snapping back to the original value
let newValue = this._dragStartValue;
let minValue = this._scrollAdjustment.lower;
let maxValue = this._scrollAdjustment.upper - this._scrollAdjustment.page_size;
let direction;
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
direction = stageX > this._dragStartX ? -1 : 1;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
direction *= -1;
} else {
direction = stageY > this._dragStartY ? -1 : 1;
}
// We default to scroll a full page size; both the first
// and the last page may be smaller though, so we need to
// adjust difference in those cases.
let difference = direction * this._scrollAdjustment.page_size;
if (this._dragStartValue + difference > maxValue)
difference = maxValue - this._dragStartValue;
else if (this._dragStartValue + difference < minValue)
difference = minValue - this._dragStartValue;
// If the user has moved more than half the scroll
// difference, we want to "settle" to the new value
// even if the user stops dragging rather "throws" by
// releasing during the drag.
let distance = this._dragStartValue - this._scrollAdjustment.value;
let noStop = Math.abs(distance / difference) > 0.5;
// We detect if the user is stopped by comparing the
// timestamp of the button release with the timestamp of
// the last motion. Experimentally, a difference of 0 or 1
// millisecond indicates that the mouse is in motion, a
// larger difference indicates that the mouse is stopped.
if ((this._lastMotionTime > 0 &&
this._lastMotionTime > event.get_time() - 2) ||
noStop) {
if (this._dragStartValue + difference >= minValue &&
this._dragStartValue + difference <= maxValue)
newValue += difference;
}
let result;
// See if the user has moved the mouse enough to trigger
// a drag
if (Math.abs(stageX - this._dragStartX) < threshold &&
Math.abs(stageY - this._dragStartY) < threshold) {
// no motion? It's a click!
result = SwipeScrollResult.CLICK;
this.emit('swipe-scroll-end', result);
} else {
if (newValue == this._dragStartValue)
result = SwipeScrollResult.CANCEL;
else
result = SwipeScrollResult.SWIPE;
// The event capture handler is disconnected
// while scrolling to the final position, so
// to avoid undesired prelights we raise
// the cover pane.
this._coverPane.raise_top();
this._coverPane.show();
Tweener.addTween(this._scrollAdjustment,
{ value: newValue,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onCompleteScope: this,
onComplete: function() {
this._coverPane.hide();
this.emit('swipe-scroll-end',
result);
}
});
}
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
return result != SwipeScrollResult.CLICK;
case Clutter.EventType.MOTION:
[stageX, stageY] = event.get_coords();
let dx = this._dragX - stageX;
let dy = this._dragY - stageY;
let primary = global.get_primary_monitor();
this._dragX = stageX;
this._dragY = stageY;
this._lastMotionTime = event.get_time();
// See if the user has moved the mouse enough to trigger
// a drag
if (Math.abs(stageX - this._dragStartX) < threshold &&
Math.abs(stageY - this._dragStartY) < threshold)
return true;
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
this._scrollAdjustment.value -= (dx / primary.width) * this._scrollAdjustment.page_size;
else
this._scrollAdjustment.value += (dx / primary.width) * this._scrollAdjustment.page_size;
} else {
this._scrollAdjustment.value += (dy / primary.height) * this._scrollAdjustment.page_size;
}
return true;
// Block enter/leave events to avoid prelights
// during swipe-scroll
case Clutter.EventType.ENTER:
case Clutter.EventType.LEAVE:
return true;
}
return false;
},
_getDesktopClone: function() {
@ -211,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);
@ -220,21 +452,21 @@ Overview.prototype = {
this._coverPane.set_position(0, contentY);
this._coverPane.set_size(primary.width, contentHeight);
let viewWidth = (1.0 - DASH_SPLIT_FRACTION) * primary.width - this._spacing;
let dashWidth = Math.round(DASH_SPLIT_FRACTION * primary.width);
let viewWidth = primary.width - dashWidth - this._spacing;
let viewHeight = contentHeight - 2 * this._spacing;
let viewY = contentY + this._spacing;
let viewX = rtl ? 0
: Math.floor(DASH_SPLIT_FRACTION * primary.width) + this._spacing;
let viewX = rtl ? 0 : dashWidth + this._spacing;
// Set the dash's x position - y is handled by a constraint
let dashX;
if (rtl) {
this._dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
this.dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
dashX = primary.width;
} else {
dashX = 0;
}
this._dash.actor.set_x(dashX);
this.dash.actor.set_x(dashX);
this.viewSelector.actor.set_position(viewX, viewY);
this.viewSelector.actor.set_size(viewWidth, viewHeight);
@ -246,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');
},
@ -254,39 +490,33 @@ 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
show : function() {
if (this.visible)
if (this._shown)
return;
if (!Main.pushModal(this.viewSelector.actor))
// Do this manually instead of using _syncInputMode, to handle failure
if (!Main.pushModal(this._group))
return;
this._modal = true;
this._animateVisible();
this._shown = true;
this._buttonPressId = this._group.connect('button-press-event',
Lang.bind(this, this._onButtonPress));
},
_animateVisible: function() {
if (this.visible || this.animationInProgress)
return;
this.visible = true;
@ -303,9 +533,7 @@ Overview.prototype = {
this._group.show();
this._background.show();
this.viewSelector.show();
this._workspacesDisplay.show();
this._dash.show();
this.workspaces = this._workspacesDisplay.workspacesView;
global.overlay_group.add_actor(this.workspaces.actor);
@ -323,38 +551,108 @@ 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();
this._coverPane.show();
this.emit('showing');
},
// showTemporarily:
//
// Animates the overview visible without grabbing mouse and keyboard input;
// if show() has already been called, this has no immediate effect, but
// will result in the overview not being hidden until hideTemporarily() is
// called.
showTemporarily: function() {
if (this._shownTemporarily)
return;
this._syncInputMode();
this._animateVisible();
this._shownTemporarily = true;
},
// hide:
//
// Reverses the effect of show()
hide: function() {
if (!this.visible || this._hideInProgress)
if (!this._shown)
return;
if (!this._shownTemporarily)
this._animateNotVisible();
this._shown = false;
this._syncInputMode();
if (this._buttonPressId > 0)
this._group.disconnect(this._buttonPressId);
this._buttonPressId = 0;
},
// hideTemporarily:
//
// Reverses the effect of showTemporarily()
hideTemporarily: function() {
if (!this._shownTemporarily)
return;
if (!this._shown)
this._animateNotVisible();
this._shownTemporarily = false;
this._syncInputMode();
},
toggle: function() {
if (this._shown)
this.hide();
else
this.show();
},
//// Private methods ////
_syncInputMode: function() {
// We delay input mode changes during animation so that when removing the
// overview we don't have a problem with the release of a press/release
// going to an application.
if (this.animationInProgress)
return;
if (this._shown) {
if (!this._modal) {
if (Main.pushModal(this._group))
this._modal = true;
else
this.hide();
}
} else if (this._shownTemporarily) {
if (this._modal) {
Main.popModal(this._group);
this._modal = false;
}
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
} else {
if (this._modal) {
Main.popModal(this._group);
this._modal = false;
}
else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
global.stage_input_mode = Shell.StageInputMode.NORMAL;
}
},
_animateNotVisible: function() {
if (!this.visible || this.animationInProgress)
return;
this.animationInProgress = true;
@ -371,63 +669,32 @@ 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();
this._coverPane.show();
this.emit('hiding');
},
toggle: function() {
if (this.visible)
this.hide();
else
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 ////
_showDone: function() {
if (this._hideInProgress)
return;
this.animationInProgress = false;
this._desktopFade.hide();
this._coverPane.lower_bottom();
this._coverPane.hide();
this.emit('shown');
// Handle any calls to hide* while we were showing
if (!this._shown && !this._shownTemporarily)
this._animateNotVisible();
this._syncInputMode();
global.sync_pointer();
},
_hideDone: function() {
@ -437,8 +704,6 @@ Overview.prototype = {
this.workspaces = null;
this._workspacesDisplay.hide();
this.viewSelector.hide();
this._dash.hide();
this._desktopFade.hide();
this._background.hide();
@ -448,10 +713,20 @@ Overview.prototype = {
this.animationInProgress = false;
this._hideInProgress = false;
this._coverPane.lower_bottom();
this._coverPane.hide();
Main.popModal(this.viewSelector.actor);
this.emit('hidden');
// Handle any calls to show* while we were hiding
if (this._shown || this._shownTemporarily)
this._animateVisible();
this._syncInputMode();
// Fake a pointer event if requested
if (this._needsFakePointerEvent) {
this._fakePointerEvent();
this._needsFakePointerEvent = false;
}
}
};
Signals.addSignalMethods(Overview.prototype);

File diff suppressed because it is too large Load Diff

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,40 +22,64 @@ 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('pressed');
let focus = global.stage.get_key_focus();
if (!focus || (focus != this.actor && !menu.contains(focus)))
this.actor.grab_key_focus();
} else
this.actor.remove_style_pseudo_class('pressed');
if (open)
this.actor.add_style_pseudo_class('active');
else
this.actor.remove_style_pseudo_class('active');
}
};
@ -71,7 +97,7 @@ SystemStatusButton.prototype = {
__proto__: Button.prototype,
_init: function(iconName,tooltipText) {
Button.prototype._init.call(this, St.Align.START);
Button.prototype._init.call(this, 0.0);
this._iconActor = new St.Icon({ icon_name: iconName,
icon_type: St.IconType.SYMBOLIC,
style_class: 'system-status-icon' });

View File

@ -1,6 +1,5 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const GConf = imports.gi.GConf;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Shell = imports.gi.Shell;
@ -13,12 +12,9 @@ const _ = Gettext.gettext;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Search = imports.ui.search;
const NAUTILUS_PREFS_DIR = '/apps/nautilus/preferences';
const DESKTOP_IS_HOME_KEY = NAUTILUS_PREFS_DIR + '/desktop_is_home_dir';
const PLACES_ICON_SIZE = 16;
const Util = imports.misc.util;
/**
* Represents a place object, which is most normally a bookmark entry,
@ -63,6 +59,21 @@ PlaceInfo.prototype = {
}
};
// Helper function to translate launch parameters into a GAppLaunchContext
function _makeLaunchContext(params)
{
params = Params.parse(params, { workspace: null,
timestamp: null });
let launchContext = global.create_app_launch_context();
if (params.workspace != null)
launchContext.set_desktop(params.workspace.index());
if (params.timestamp != null)
launchContext.set_timestamp(params.timestamp);
return launchContext;
}
function PlaceDeviceInfo(mount) {
this._init(mount);
}
@ -82,9 +93,9 @@ PlaceDeviceInfo.prototype = {
return St.TextureCache.get_default().load_gicon(null, icon, size);
},
launch: function() {
launch: function(params) {
Gio.app_info_launch_default_for_uri(this._mount.get_root().get_uri(),
global.create_app_launch_context());
_makeLaunchContext(params));
},
isRemovable: function() {
@ -116,20 +127,15 @@ PlaceDeviceInfo.prototype = {
}
};
function PlacesManager() {
this._init();
}
PlacesManager.prototype = {
_init: function() {
let gconf = GConf.Client.get_default();
gconf.add_dir(NAUTILUS_PREFS_DIR, GConf.ClientPreloadType.PRELOAD_NONE);
this._defaultPlaces = [];
this._mounts = [];
this._bookmarks = [];
this._isDesktopHome = gconf.get_bool(DESKTOP_IS_HOME_KEY);
let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
let homeUri = homeFile.get_uri();
@ -139,8 +145,8 @@ PlacesManager.prototype = {
function(size) {
return St.TextureCache.get_default().load_gicon(null, homeIcon, size);
},
function() {
Gio.app_info_launch_default_for_uri(homeUri, global.create_app_launch_context());
function(params) {
Gio.app_info_launch_default_for_uri(homeUri, _makeLaunchContext(params));
});
let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
@ -152,8 +158,8 @@ PlacesManager.prototype = {
function(size) {
return St.TextureCache.get_default().load_gicon(null, desktopIcon, size);
},
function() {
Gio.app_info_launch_default_for_uri(desktopUri, global.create_app_launch_context());
function(params) {
Gio.app_info_launch_default_for_uri(desktopUri, _makeLaunchContext(params));
});
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
@ -162,40 +168,16 @@ PlacesManager.prototype = {
icon_type: St.IconType.FULLCOLOR,
icon_size: size });
},
function () {
new Shell.Process({ args: ['nautilus-connect-server'] }).run();
function (params) {
// BUG: nautilus-connect-server doesn't have a desktop file, so we can't
// launch it with the workspace from params. It's probably pretty rare
// and odd to drag this place onto a workspace in any case
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 () {
networkApp.launch();
});
}
this._defaultPlaces.push(this._home);
this._desktopMenuIndex = this._defaultPlaces.length;
if (!this._isDesktopHome)
this._defaultPlaces.push(this._desktopMenu);
if (this._network)
this._defaultPlaces.push(this._network);
this._defaultPlaces.push(this._desktopMenu);
this._defaultPlaces.push(this._connect);
/*
@ -229,9 +211,6 @@ PlacesManager.prototype = {
}));
this._reloadBookmarks();
gconf.notify_add(DESKTOP_IS_HOME_KEY, Lang.bind(this, this._updateDesktopMenuVisibility));
},
_updateDevices: function() {
@ -329,8 +308,8 @@ PlacesManager.prototype = {
function(size) {
return St.TextureCache.get_default().load_gicon(null, icon, size);
},
function() {
Gio.app_info_launch_default_for_uri(bookmark, global.create_app_launch_context());
function(params) {
Gio.app_info_launch_default_for_uri(bookmark, _makeLaunchContext(params));
});
this._bookmarks.push(item);
}
@ -340,21 +319,6 @@ PlacesManager.prototype = {
this.emit('places-updated');
},
_updateDesktopMenuVisibility: function() {
let gconf = GConf.Client.get_default();
this._isDesktopHome = gconf.get_boolean(DESKTOP_IS_HOME_KEY);
if (this._isDesktopHome)
this._removeById(this._defaultPlaces, 'special:desktop');
else
this._defaultPlaces.splice(this._desktopMenuIndex, 0,
this._desktopMenu);
/* See comment in _updateDevices for explanation why there are two signals. */
this.emit('defaults-updated');
this.emit('places-updated');
},
_addMount: function(mount) {
let devItem = new PlaceDeviceInfo(mount);
this._mounts.push(devItem);
@ -402,150 +366,8 @@ PlacesManager.prototype = {
sourceArray.splice(this._lookupIndexById(sourceArray, id), 1);
}
};
Signals.addSignalMethods(PlacesManager.prototype);
/**
* An entry in the places menu.
* @info The corresponding PlaceInfo to populate this entry.
*/
function DashPlaceDisplayItem(info) {
this._init(info);
}
DashPlaceDisplayItem.prototype = {
_init: function(info) {
this.name = info.name;
this._info = info;
this._icon = info.iconFactory(PLACES_ICON_SIZE);
this.actor = new St.Clickable({ style_class: 'places-item',
reactive: true,
x_align: St.Align.START,
x_fill: true });
let box = new St.BoxLayout({ style_class: 'places-item-box' });
this.actor.set_child(box);
let bin = new St.Bin({ child: this._icon });
box.add(bin);
let text = new St.Label({ text: info.name });
box.add(text, { expand: true, x_fill: true });
if (info.isRemovable()) {
let removeIcon = new St.Icon({ icon_name: 'media-eject',
icon_type: St.IconType.FULLCOLOR,
icon_size: PLACES_ICON_SIZE });
let removeIconBox = new St.Clickable({ child: removeIcon,
reactive: true });
box.add(removeIconBox);
removeIconBox.connect('clicked',
Lang.bind(this, function() {
this._info.remove();
}));
}
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this.actor._delegate = this;
this._draggable = DND.makeDraggable(this.actor);
this._draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
this._draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
},
_onClicked: function(b) {
this._info.launch();
Main.overview.hide();
},
getDragActorSource: function() {
return this._icon;
},
getDragActor: function(stageX, stageY) {
return this._info.iconFactory(PLACES_ICON_SIZE);
},
//// Drag and drop methods ////
shellWorkspaceLaunch: function() {
this._info.launch();
}
};
function DashPlaceDisplay() {
this._init();
}
DashPlaceDisplay.prototype = {
_init: function() {
// Places is divided semi-arbitrarily into left and right; a grid would
// look better in that there would be an even number of items left+right,
// but it seems like we want some sort of differentiation between actions
// like "Connect to server..." and regular folders
this.actor = new St.Table({ style_class: 'places-section',
homogeneous: true });
this._defaultsList = [];
this._bookmarksList = [];
this._mountsList = [];
Main.placesManager.connect('defaults-updated', Lang.bind(this, this._updateDefaults));
Main.placesManager.connect('bookmarks-updated', Lang.bind(this, this._updateBookmarks));
Main.placesManager.connect('mounts-updated', Lang.bind(this, this._updateMounts));
this._updateDefaults();
this._updateMounts();
this._updateBookmarks();
},
_updateDefaults: function() {
for (let i = 0; i < this._defaultsList.length; i++)
this._defaultsList[i].destroy();
this._defaultsList = [];
let places = Main.placesManager.getDefaultPlaces();
for (let i = 0; i < places.length; i++) {
this._defaultsList[i] = new DashPlaceDisplayItem(places[i]).actor;
this.actor.add(this._defaultsList[i], {row: i, col: 0});
}
this._updateMounts();
},
_updateMounts: function() {
for (let i = 0; i < this._mountsList.length; i++)
this._mountsList[i].destroy();
this._mountsList = [];
let places = Main.placesManager.getMounts();
for (let i = 0; i < places.length; i++) {
this._mountsList[i] = new DashPlaceDisplayItem(places[i]).actor;
this.actor.add(this._mountsList[i], {row: this._defaultsList.length + i, col: 0});
}
},
_updateBookmarks: function() {
for (let i = 0; i < this._bookmarksList.length; i++)
this._bookmarksList[i].destroy();
this._bookmarksList = [];
let places = Main.placesManager.getBookmarks();
for (let i = 0; i < places.length; i ++) {
this._bookmarksList[i] = new DashPlaceDisplayItem(places[i]).actor;
this.actor.add(this._bookmarksList[i], {row: i, col: 1});
}
}
};
Signals.addSignalMethods(DashPlaceDisplay.prototype);
function PlaceSearchProvider() {
this._init();
@ -564,12 +386,15 @@ 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) {
activateResult: function(id, params) {
let placeInfo = Main.placesManager.lookupPlaceById(id);
placeInfo.launch();
placeInfo.launch(params);
},
_compareResultMeta: function (idA, idB) {

View File

@ -0,0 +1,412 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*-
*
* Copyright 2010 Red Hat, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Author: David Zeuthen <davidz@redhat.com>
*/
const Lang = imports.lang;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Shell = imports.gi.Shell;
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const Pango = imports.gi.Pango;
const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio;
const Mainloop = imports.mainloop;
const Polkit = imports.gi.Polkit;
const PolkitAgent = imports.gi.PolkitAgent;
const ModalDialog = imports.ui.modalDialog;
function AuthenticationDialog(actionId, message, cookie, userNames) {
this._init(actionId, message, cookie, userNames);
}
AuthenticationDialog.prototype = {
__proto__: ModalDialog.ModalDialog.prototype,
_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 });
this.contentLayout.add(mainContentBox,
{ x_fill: true,
y_fill: true });
let icon = new St.Icon({ icon_name: 'dialog-password-symbolic' });
mainContentBox.add(icon,
{ x_fill: true,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.START });
let messageBox = new St.BoxLayout({ style_class: 'polkit-dialog-message-layout',
vertical: true });
mainContentBox.add(messageBox,
{ y_align: St.Align.START });
this._subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline',
text: _("Authentication Required") });
messageBox.add(this._subjectLabel,
{ y_fill: false,
y_align: St.Align.START });
this._descriptionLabel = new St.Label({ style_class: 'polkit-dialog-description',
text: message });
this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._descriptionLabel.clutter_text.line_wrap = true;
messageBox.add(this._descriptionLabel,
{ y_fill: true,
y_align: St.Align.START });
if (userNames.length > 1) {
log('polkitAuthenticationAgent: Received ' + userNames.length +
' identities that can be used for authentication. Only ' +
'considering the first one.');
}
let userName = userNames[0];
this._user = Gdm.UserManager.ref_default().get_user(userName);
let userRealName = this._user.get_real_name()
this._userLoadedId = this._user.connect('notify::is_loaded',
Lang.bind(this, this._onUserChanged));
this._userChangedId = this._user.connect('changed',
Lang.bind(this, this._onUserChanged));
// Special case 'root'
let userIsRoot = false;
if (userName == 'root') {
userIsRoot = true;
userRealName = _("Administrator");
}
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();
this._passwordBox = new St.BoxLayout({ vertical: false });
messageBox.add(this._passwordBox);
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: "",
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._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._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();
/* 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"),
action: Lang.bind(this, this._onAuthenticateButtonPressed)
}]);
this._doneEmitted = false;
this._identityToAuth = Polkit.UnixUser.new_for_name(userName);
this._cookie = cookie;
this._session = new PolkitAgent.Session({ identity: this._identityToAuth,
cookie: this._cookie });
this._session.connect('completed', Lang.bind(this, this._onSessionCompleted));
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._passwordEntry.grab_key_focus();
}));
},
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, dismissed);
}
},
_onEntryActivate: function() {
let response = this._passwordEntry.get_text();
this._session.response(response);
// When the user responds, dismiss already shown info and
// error texts (if any)
this._errorMessageLabel.hide();
this._infoMessageLabel.hide();
this._nullMessageLabel.show();
},
_onAuthenticateButtonPressed: function() {
this._onEntryActivate();
},
_onSessionCompleted: function(session, 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:"));
else
this._passwordLabel.set_text(request);
if (echo_on)
this._passwordEntry.clutter_text.set_password_char('');
else
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
this._passwordBox.show();
this._passwordEntry.set_text('');
this._passwordEntry.grab_key_focus();
this._ensureOpen();
},
_onSessionShowError: function(session, text) {
this._passwordEntry.set_text('');
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._infoMessageLabel.set_text(text);
this._infoMessageLabel.show();
this._errorMessageLabel.hide();
this._nullMessageLabel.hide();
this._ensureOpen();
},
destroySession: function() {
if (this._session) {
if (!this._completed)
this._session.cancel();
this._session = null;
}
},
_onUserChanged: function() {
if (this._user.is_loaded) {
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();
}
}
},
cancel: function() {
this._wasDismissed = true;
this.close(global.get_current_time());
this._emitDone(false, true);
},
};
Signals.addSignalMethods(AuthenticationDialog.prototype);
function AuthenticationAgent() {
this._init();
}
AuthenticationAgent.prototype = {
_init: function() {
this._native = new Shell.PolkitAuthenticationAgent();
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
this._native.connect('cancel', Lang.bind(this, this._onCancel));
this._currentDialog = null;
this._isCompleting = false;
},
_onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
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, false);
},
_onDialogDone: function(dialog, keepVisible, dismissed) {
this._completeRequest(keepVisible, dismissed);
},
_reallyCompleteRequest: function(dismissed) {
this._currentDialog.close();
this._currentDialog.destroySession();
this._currentDialog = null;
this._isCompleting = false;
this._native.complete(dismissed)
},
_completeRequest: function(keepVisible, wasDismissed) {
if (this._isCompleting)
return;
this._isCompleting = true;
if (keepVisible) {
// Give the user 2 seconds to read 'Authentication Failure' before
// dismissing the dialog
Mainloop.timeout_add(2000,
Lang.bind(this,
function() {
this._reallyCompleteRequest(wasDismissed);
}));
} else {
this._reallyCompleteRequest(wasDismissed);
}
}
}
function init() {
let agent = new AuthenticationAgent();
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,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

@ -1,8 +1,19 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const Util = imports.misc.util;
const RESULT_ICON_SIZE = 48;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const DISABLED_OPEN_SEARCH_PROVIDERS_KEY = 'disabled-open-search-providers';
// Not currently referenced by the search API, but
// this enumeration can be useful for provider
@ -152,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');
@ -196,21 +208,105 @@ 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);
function OpenSearchSystem() {
this._init();
}
OpenSearchSystem.prototype = {
_init: function() {
this._providers = [];
global.settings.connect('changed::' + DISABLED_OPEN_SEARCH_PROVIDERS_KEY, Lang.bind(this, this._refresh));
this._refresh();
},
getProviders: function() {
let res = [];
for (let i = 0; i < this._providers.length; i++)
res.push({ id: i, name: this._providers[i].name });
return res;
},
setSearchTerms: function(terms) {
this._terms = terms;
},
_checkSupportedProviderLanguage: function(provider) {
if (provider.url.search(/{language}/) == -1)
return true;
let langs = GLib.get_language_names();
langs.push('en');
let lang = null;
for (let i = 0; i < langs.length; i++) {
for (let k = 0; k < provider.langs.length; k++) {
if (langs[i] == provider.langs[k])
lang = langs[i];
}
if (lang)
break;
}
provider.lang = lang;
return lang != null;
},
activateResult: function(id, params) {
let searchTerms = this._terms.join(' ');
let url = this._providers[id].url.replace('{searchTerms}', encodeURIComponent(searchTerms));
if (url.match('{language}'))
url = url.replace('{language}', this._providers[id].lang);
try {
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context());
} catch (e) {
// TODO: remove this after glib will be removed from moduleset
// In the default jhbuild, gio is in our prefix but gvfs is not
Util.spawn(['gvfs-open', url])
}
Main.overview.hide();
},
_addProvider: function(fileName) {
let 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() {
this._providers = [];
let names = global.settings.get_strv(DISABLED_OPEN_SEARCH_PROVIDERS_KEY);
let file = Gio.file_new_for_path(global.datadir + '/search_providers');
FileUtils.listDirAsync(file, Lang.bind(this, function(files) {
for (let i = 0; i < files.length; i++) {
let enabled = true;
let name = files[i].get_name();
for (let k = 0; k < names.length; k++)
if (names[k] == name)
enabled = false;
if (enabled)
this._addProvider(name);
}
}));
}
}
Signals.addSignalMethods(OpenSearchSystem.prototype);
function SearchSystem() {
this._init();
}
@ -241,7 +337,7 @@ SearchSystem.prototype = {
updateSearch: function(searchString) {
searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, '');
if (searchString == '')
return null;
return [];
let terms = searchString.split(/\s+/);
let isSubSearch = terms.length == this._previousTerms.length;

View File

@ -5,14 +5,16 @@ 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;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Search = imports.ui.search;
const MAX_SEARCH_RESULTS_ROWS = 2;
const MAX_SEARCH_RESULTS_ROWS = 1;
function SearchResult(provider, metaInfo, terms) {
@ -23,10 +25,10 @@ SearchResult.prototype = {
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
this.actor = new St.Clickable({ style_class: 'search-result',
reactive: true,
x_align: St.Align.START,
y_fill: true });
this.actor = new St.Button({ style_class: 'search-result',
reactive: true,
x_align: St.Align.START,
y_fill: true });
this.actor._delegate = this;
let content = provider.createResultActor(metaInfo, terms);
@ -35,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;
@ -50,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);
@ -68,23 +72,24 @@ SearchResult.prototype = {
Main.overview.toggle();
},
_onResultClicked: function(actor, event) {
_onResultClicked: function(actor) {
this.activate();
},
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() {
shellWorkspaceLaunch: function(params) {
if (this.provider.dragActivateResult)
this.provider.dragActivateResult(this.metaInfo.id);
this.provider.dragActivateResult(this.metaInfo.id, params);
else
this.provider.activateResult(this.metaInfo.id);
this.provider.activateResult(this.metaInfo.id, params);
}
};
@ -101,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() {
@ -110,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;
},
@ -149,28 +176,41 @@ GridSearchResults.prototype = {
};
function SearchResults(searchSystem) {
this._init(searchSystem);
function SearchResults(searchSystem, openSearchSystem) {
this._init(searchSystem, openSearchSystem);
}
SearchResults.prototype = {
_init: function(searchSystem) {
_init: function(searchSystem, openSearchSystem) {
this._searchSystem = searchSystem;
this._openSearchSystem = openSearchSystem;
this.actor = new St.BoxLayout({ name: 'searchResults',
vertical: true });
this.actor = new St.Bin({ name: 'searchResults',
y_align: St.Align.START,
x_align: St.Align.START,
x_fill: true });
this._content = new St.BoxLayout({ name: 'searchResultsContent',
vertical: true });
let scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
vshadows: true });
vfade: true });
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
scrollView.add_actor(this._content);
this.actor.set_child(scrollView);
this.actor.add(scrollView, { x_fill: true,
y_fill: false,
expand: true,
x_align: St.Align.START,
y_align: St.Align.START });
this.actor.connect('notify::mapped', Lang.bind(this,
function() {
if (!this.actor.mapped)
return;
let adjustment = scrollView.vscroll.adjustment;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(adjustment, direction);
}));
this._statusText = new St.Label({ style_class: 'search-statustext' });
this._content.add(this._statusText);
@ -179,23 +219,59 @@ SearchResults.prototype = {
this._providerMeta = [];
for (let i = 0; i < this._providers.length; i++)
this.createProviderMeta(this._providers[i]);
this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' });
this.actor.add(this._searchProvidersBox);
this._openSearchProviders = [];
this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons));
this._updateOpenSearchProviderButtons();
},
_updateOpenSearchProviderButtons: function() {
this._selectedOpenSearchButton = -1;
for (let i = 0; i < this._openSearchProviders.length; i++)
this._openSearchProviders[i].actor.destroy();
this._openSearchProviders = this._openSearchSystem.getProviders();
for (let i = 0; i < this._openSearchProviders.length; i++)
this._createOpenSearchProviderButton(this._openSearchProviders[i]);
},
_updateOpenSearchButtonState: function() {
for (let i = 0; i < this._openSearchProviders.length; i++) {
if (i == this._selectedOpenSearchButton)
this._openSearchProviders[i].actor.add_style_pseudo_class('selected');
else
this._openSearchProviders[i].actor.remove_style_pseudo_class('selected');
}
},
_createOpenSearchProviderButton: function(provider) {
let button = new St.Button({ style_class: 'dash-search-button',
reactive: true,
x_fill: true,
y_align: St.Align.MIDDLE });
let bin = new St.Bin({ x_fill: false,
x_align:St.Align.MIDDLE });
button.connect('clicked', Lang.bind(this, function() {
this._openSearchSystem.activateResult(provider.id);
}));
let title = new St.Label({ text: provider.name,
style_class: 'dash-search-button-label' });
bin.set_child(title);
button.set_child(bin);
provider.actor = button;
this._searchProvidersBox.add(button);
},
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,
@ -208,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);
},
@ -227,6 +302,8 @@ SearchResults.prototype = {
this._searchSystem.reset();
this._statusText.hide();
this._clearDisplay();
this._selectedOpenSearchButton = -1;
this._updateOpenSearchButtonState();
},
startingSearch: function() {
@ -247,30 +324,28 @@ SearchResults.prototype = {
if (results.length == 0) {
this._statusText.set_text(_("No matching results."));
this._statusText.show();
return true;
} else {
this._selectedOpenSearchButton = -1;
this._updateOpenSearchButtonState();
this._statusText.hide();
}
let terms = this._searchSystem.getTerms();
this._openSearchSystem.setSearchTerms(terms);
for (let i = 0; i < results.length; i++) {
let [provider, providerResults] = results[i];
let meta = this._metaForProvider(provider);
meta.actor.show();
meta.resultDisplay.renderResults(providerResults, terms);
meta.count.set_text('' + providerResults.length);
}
this.selectDown(false);
if (this._selectedOpenSearchButton == -1)
this.selectDown(false);
return true;
},
_onHeaderClicked: function(provider) {
provider.expandSearch(this._searchSystem.getTerms());
},
_modifyActorSelection: function(resultDisplay, up) {
let success;
let index = resultDisplay.getSelectionIndex();
@ -284,16 +359,26 @@ SearchResults.prototype = {
},
selectUp: function(recursing) {
for (let i = this._selectedProvider; i >= 0; i--) {
let meta = this._providerMeta[i];
if (!meta.actor.visible)
continue;
let success = this._modifyActorSelection(meta.resultDisplay, true);
if (success) {
this._selectedProvider = i;
return;
if (this._selectedOpenSearchButton == -1) {
for (let i = this._selectedProvider; i >= 0; i--) {
let meta = this._providerMeta[i];
if (!meta.actor.visible)
continue;
let success = this._modifyActorSelection(meta.resultDisplay, true);
if (success) {
this._selectedProvider = i;
return;
}
}
}
if (this._selectedOpenSearchButton == -1)
this._selectedOpenSearchButton = this._openSearchProviders.length;
this._selectedOpenSearchButton--;
this._updateOpenSearchButtonState();
if (this._selectedOpenSearchButton >= 0)
return;
if (this._providerMeta.length > 0 && !recursing) {
this._selectedProvider = this._providerMeta.length - 1;
this.selectUp(true);
@ -302,18 +387,30 @@ SearchResults.prototype = {
selectDown: function(recursing) {
let current = this._selectedProvider;
if (current == -1)
current = 0;
for (let i = current; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
if (!meta.actor.visible)
continue;
let success = this._modifyActorSelection(meta.resultDisplay, false);
if (success) {
this._selectedProvider = i;
return;
if (this._selectedOpenSearchButton == -1) {
if (current == -1)
current = 0;
for (let i = current; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
if (!meta.actor.visible)
continue;
let success = this._modifyActorSelection(meta.resultDisplay, false);
if (success) {
this._selectedProvider = i;
return;
}
}
}
this._selectedOpenSearchButton++;
if (this._selectedOpenSearchButton < this._openSearchProviders.length) {
this._updateOpenSearchButtonState();
return;
}
this._selectedOpenSearchButton = -1;
this._updateOpenSearchButtonState();
if (this._providerMeta.length > 0 && !recursing) {
this._selectedProvider = 0;
this.selectDown(true);
@ -321,6 +418,13 @@ SearchResults.prototype = {
},
activateSelected: function() {
if (this._selectedOpenSearchButton != -1) {
let provider = this._openSearchProviders[this._selectedOpenSearchButton];
this._openSearchSystem.activateResult(provider.id);
Main.overview.hide();
return;
}
let current = this._selectedProvider;
if (current < 0)
return;

View File

@ -10,24 +10,20 @@ const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const A11Y_SCHEMA = "org.gnome.desktop.a11y.keyboard";
const KEY_STICKY_KEYS_ENABLED = "stickykeys-enable";
const KEY_BOUNCE_KEYS_ENABLED = "bouncekeys-enable";
const KEY_SLOW_KEYS_ENABLED = "slowkeys-enable";
const KEY_MOUSE_KEYS_ENABLED = "mousekeys-enable";
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
const KEY_STICKY_KEYS_ENABLED = 'stickykeys-enable';
const KEY_BOUNCE_KEYS_ENABLED = 'bouncekeys-enable';
const KEY_SLOW_KEYS_ENABLED = 'slowkeys-enable';
const KEY_MOUSE_KEYS_ENABLED = 'mousekeys-enable';
const AT_SCREEN_KEYBOARD_SCHEMA = "org.gnome.desktop.default-applications.at.mobility";
const AT_SCREEN_READER_SCHEMA = "org.gnome.desktop.default-applications.at.visual";
const XSETTINGS_SCHEMA = "org.gnome.settings-daemon.plugins.xsettings";
const KEY_DPI = "dpi";
const APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
const DPI_LOW_REASONABLE_VALUE = 50;
const DPI_HIGH_REASONABLE_VALUE = 500;
@ -35,32 +31,16 @@ const DPI_HIGH_REASONABLE_VALUE = 500;
const DPI_FACTOR_LARGE = 1.25;
const DPI_FACTOR_LARGER = 1.5;
const DPI_FACTOR_LARGEST = 2.0;
const DPI_DEFAULT = 96;
const KEY_META_DIR = "/apps/metacity/general";
const KEY_VISUAL_BELL = KEY_META_DIR + "/visual_bell";
const KEY_META_DIR = '/apps/metacity/general';
const KEY_VISUAL_BELL = KEY_META_DIR + '/visual_bell';
const DESKTOP_INTERFACE_SCHEMA = "org.gnome.desktop.interface";
const KEY_GTK_THEME = "gtk-theme";
const KEY_ICON_THEME = "icon-theme";
const DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface';
const KEY_GTK_THEME = 'gtk-theme';
const KEY_ICON_THEME = 'icon-theme';
const 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;
}
const HIGH_CONTRAST_THEME = 'HighContrast';
function ATIndicator() {
this._init.apply(this, arguments);
@ -79,17 +59,20 @@ ATIndicator.prototype = {
let highContrast = this._buildHCItem();
this.menu.addMenuItem(highContrast);
let magnifier = this._buildMagItem();
let magnifier = this._buildItem(_("Zoom"), APPLICATIONS_SCHEMA,
'screen-magnifier-enabled');
this.menu.addMenuItem(magnifier);
let textZoom = this._buildFontItem();
this.menu.addMenuItem(textZoom);
let screenReader = this._buildItem(_("Screen Reader"), AT_SCREEN_READER_SCHEMA, 'startup');
this.menu.addMenuItem(screenReader);
// let screenReader = this._buildItem(_("Screen Reader"), APPLICATIONS_SCHEMA,
// 'screen-reader-enabled');
// this.menu.addMenuItem(screenReader);
let screenKeyboard = this._buildItem(_("Screen Keyboard"), AT_SCREEN_KEYBOARD_SCHEMA, 'startup');
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);
@ -108,8 +91,8 @@ ATIndicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Universal Access Settings"), function() {
let p = new Shell.Process({ args: ['gnome-control-center','universal-access'] });
p.run();
let app = Shell.AppSystem.get_default().get_app('gnome-universal-access-panel.desktop');
app.activate(-1);
});
},
@ -167,9 +150,12 @@ ATIndicator.prototype = {
if (enabled) {
settings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
settings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
} else {
} else if(!hasHC) {
settings.set_string(KEY_GTK_THEME, gtkTheme);
settings.set_string(KEY_ICON_THEME, iconTheme);
} else {
settings.reset(KEY_GTK_THEME);
settings.reset(KEY_ICON_THEME);
}
});
settings.connect('changed::' + KEY_GTK_THEME, function() {
@ -190,42 +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;
widget.setToggleState(active);
});
return widget;
},
_buildMagItem: function() {
let mag = Main.magnifier;
let widget = this._buildItemExtended(_("Zoom"),
mag.isActive(),
true,
Lang.bind(mag, mag.setActive));
mag.connect('active-changed', function(magnifier, active) {
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;

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

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

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

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

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

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const DBus = imports.dbus;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
@ -10,6 +9,7 @@ const St = imports.gi.St;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
@ -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,11 +72,9 @@ 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();
let percentBin = new St.Bin();
percentBin.set_child(this._primaryPercentage, { x_align: St.Align.END });
this._batteryItem.addActor(percentBin);
this._batteryItem.addActor(this._primaryPercentage, { align: St.Align.END });
this.menu.addMenuItem(this._batteryItem);
this._deviceSep = new PopupMenu.PopupSeparatorMenuItem();
@ -84,11 +82,9 @@ Indicator.prototype = {
this._otherDevicePosition = 2;
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("What's using power..."),function() {
GLib.spawn_command_line_async('gnome-power-statistics --device wakeups');
});
this.menu.addAction(_("Power Settings"),function() {
GLib.spawn_command_line_async('gnome-control-center power');
let app = Shell.AppSystem.get_default().get_app('gnome-power-panel.desktop');
app.activate(-1);
});
this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
@ -105,12 +101,32 @@ Indicator.prototype = {
this._deviceSep.actor.hide();
return;
}
let [device_id, device_type, icon, percentage, state, time] = device;
let [device_id, device_type, icon, percentage, state, seconds] = device;
if (device_type == UPDeviceType.BATTERY) {
this._hasPrimary = true;
let minutes = Math.floor(time / 60);
this._batteryItem.label.text = Gettext.ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
this._primaryPercentage.text = '%d%%'.format(Math.round(percentage));
let time = Math.round(seconds / 60);
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;
}
this._primaryPercentage.text = Math.round(percentage) + '%';
this._batteryItem.actor.show();
if (this._deviceItems.length > 0)
this._deviceSep.actor.show();
@ -142,10 +158,6 @@ Indicator.prototype = {
continue;
let item = new DeviceItem (devices[i]);
item.connect('activate', function() {
let p = new Shell.Process({ args: ['gnome-power-statistics', '--device', device_id] });
p.run();
});
this._deviceItems.push(item);
this.menu.addMenuItem(item, this._otherDevicePosition + position);
position++;
@ -176,8 +188,8 @@ Indicator.prototype = {
_checkError: function(error) {
if (!this._restarted && error && error.message.match(/org\.freedesktop\.DBus\.Error\.(UnknownMethod|InvalidArgs)/)) {
GLib.spawn_command_line_sync('pkill -f "^gnome-power-manager$"');
GLib.spawn_command_line_async('gnome-power-manager');
Util.killall('gnome-power-manager');
Util.spawn(['gnome-power-manager']);
this._restarted = true;
}
}
@ -191,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;
@ -206,10 +218,8 @@ DeviceItem.prototype = {
this._box.add_actor(this._label);
this.addActor(this._box);
let percentBin = new St.Bin({ x_align: St.Align.END });
let percentLabel = new St.Label({ text: '%d%%'.format(Math.round(percentage)) });
percentBin.child = percentLabel;
this.addActor(percentBin);
this.addActor(percentLabel, { align: St.Align.END });
},
_deviceTypeToString: function(type) {

View File

@ -11,13 +11,15 @@ const St = imports.gi.St;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const VOLUME_MAX = 65536.0; /* PA_VOLUME_NORM */
const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
const VOLUME_NOTIFY_ID = 1;
function Indicator() {
this._init.apply(this, arguments);
}
@ -34,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;
@ -60,21 +64,29 @@ Indicator.prototype = {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Sound Settings"), function() {
let p = new Shell.Process({ args: ['gnome-control-center', 'sound'] });
p.run();
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));
this._control.open();
},
_getMaxVolume: function(property) {
if (this[property].get_can_decibel())
return this._volumeMaxAmplified;
else
return this._volumeMax;
},
_onScrollEvent: function(actor, event) {
let direction = event.get_scroll_direction();
let currentVolume = this._output.volume;
let maxVolume = this._getMaxVolume('_output');
if (direction == Clutter.ScrollDirection.DOWN) {
let prev_muted = this._output.is_muted;
this._output.volume = Math.max(0, currentVolume - VOLUME_MAX * VOLUME_ADJUSTMENT_STEP);
this._output.volume = Math.max(0, currentVolume - maxVolume * VOLUME_ADJUSTMENT_STEP);
if (this._output.volume < 1) {
this._output.volume = 0;
if (!prev_muted)
@ -83,10 +95,12 @@ Indicator.prototype = {
this._output.push_volume();
}
else if (direction == Clutter.ScrollDirection.UP) {
this._output.volume = Math.min(VOLUME_MAX, currentVolume + VOLUME_MAX * VOLUME_ADJUSTMENT_STEP);
this._output.volume = Math.min(maxVolume, currentVolume + maxVolume * VOLUME_ADJUSTMENT_STEP);
this._output.change_is_muted(false);
this._output.push_volume();
}
this._notifyVolumeChange();
},
_onControlReady: function() {
@ -161,13 +175,14 @@ Indicator.prototype = {
},
_volumeToIcon: function(volume) {
let maxVolume = this._getMaxVolume('_output');
if (volume <= 0) {
return 'audio-volume-muted';
} else {
let v = volume / VOLUME_MAX;
if (v < 0.33)
let n = Math.floor(3 * volume / maxVolume) + 1;
if (n < 2)
return 'audio-volume-low';
if (v > 0.8)
if (n >= 3)
return 'audio-volume-high';
return 'audio-volume-medium';
}
@ -178,7 +193,7 @@ Indicator.prototype = {
log ('Volume slider changed for %s, but %s does not exist'.format(property, property));
return;
}
let volume = value * VOLUME_MAX;
let volume = value * this._getMaxVolume(property);
let prev_muted = this[property].is_muted;
if (volume < 1) {
this[property].volume = 0;
@ -193,13 +208,15 @@ Indicator.prototype = {
},
_notifyVolumeChange: function() {
global.play_theme_sound('audio-volume-change');
global.cancel_theme_sound(VOLUME_NOTIFY_ID);
global.play_theme_sound(VOLUME_NOTIFY_ID, 'audio-volume-change');
},
_mutedChanged: function(object, param_spec, property) {
let muted = this[property].is_muted;
let slider = this[property+'Slider'];
slider.setValue(muted ? 0 : (this[property].volume / VOLUME_MAX));
let maxVolume = this._getMaxVolume(property);
slider.setValue(muted ? 0 : (this[property].volume / maxVolume));
if (property == '_output') {
if (muted)
this.setIcon('audio-volume-muted');
@ -209,7 +226,8 @@ Indicator.prototype = {
},
_volumeChanged: function(object, param_spec, property) {
this[property+'Slider'].setValue(this[property].volume / VOLUME_MAX);
let maxVolume = this._getMaxVolume(property);
this[property+'Slider'].setValue(this[property].volume / maxVolume);
if (property == '_output' && !this._output.is_muted)
this.setIcon(this._volumeToIcon(this._output.volume));
}

View File

@ -6,6 +6,7 @@ const Signals = imports.signals;
const MessageTray = imports.ui.messageTray;
const NotificationDaemon = imports.ui.notificationDaemon;
const Util = imports.misc.util;
const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'bluetooth-applet': 'bluetooth',
@ -15,7 +16,11 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'nm-applet': 'network',
'gnome-power-manager': 'battery',
'keyboard': 'keyboard',
'gnome-settings-daemon': 'display'
'a11y-keyboard': 'a11y',
'kbd-scrolllock': 'keyboard',
'kbd-numlock': 'keyboard',
'kbd-capslock': 'keyboard',
'ibus-ui-gtk': 'input-method'
};
function StatusIconDispatcher() {
@ -27,14 +32,16 @@ StatusIconDispatcher.prototype = {
this._traymanager = new Shell.TrayManager();
this._traymanager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
this._traymanager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
this._traymanager.manage_stage(global.stage);
// Yet-another-Ubuntu-workaround - we have to kill their
// app-indicators, so that applications fall back to normal
// status icons
// http://bugzilla.gnome.org/show_bug.cgi=id=621382
let p = new Shell.Process({ args: ['pkill', '-f', '^([^ ]*/)?indicator-application-service$']});
p.run();
Util.killall('indicator-application-service');
},
start: function(themeWidget) {
this._traymanager.manage_stage(global.stage, themeWidget);
},
_onTrayIconAdded: function(o, icon) {

View File

@ -1,10 +1,14 @@
/* -*- 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;
@ -12,6 +16,22 @@ const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
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
//
@ -26,17 +46,24 @@ StatusMenuButton.prototype = {
__proto__: PanelMenu.Button.prototype,
_init: function() {
PanelMenu.Button.prototype._init.call(this, St.Align.START);
PanelMenu.Button.prototype._init.call(this, 0.0);
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._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();
@ -60,6 +87,17 @@ 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));
},
_onDestroy: function() {
@ -74,11 +112,56 @@ 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() {
this._haveSuspend = this._upClient.get_can_suspend();
if (!this._suspendOrPowerOffItem)
return;
// If we can't suspend show Power Off... instead
// and disable the alt key
if (!this._haveSuspend) {
this._suspendOrPowerOffItem.updateText(_("Power Off..."), null);
} else {
this._suspendOrPowerOffItem.updateText(_("Suspend"), _("Power Off..."));
}
},
_updatePresenceIcon: function(presence, status) {
@ -98,12 +181,12 @@ StatusMenuButton.prototype = {
_createSubMenu: function() {
let item;
item = new PopupMenu.PopupImageMenuItem(_("Available"), 'user-available', true);
item = new PopupMenu.PopupImageMenuItem(_("Available"), 'user-available');
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.AVAILABLE));
this.menu.addMenuItem(item);
this._presenceItems[GnomeSession.PresenceStatus.AVAILABLE] = item;
item = new PopupMenu.PopupImageMenuItem(_("Busy"), 'user-busy', true);
item = new PopupMenu.PopupImageMenuItem(_("Busy"), 'user-busy');
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.BUSY));
this.menu.addMenuItem(item);
this._presenceItems[GnomeSession.PresenceStatus.BUSY] = item;
@ -125,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));
@ -134,36 +218,41 @@ 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.PopupMenuItem(_("Suspend..."));
item.connect('activate', Lang.bind(this, this._onShutDownActivate));
this.menu.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Shut Down..."));
item.connect('activate', Lang.bind(this, this._onShutDownActivate));
item = new PopupMenu.PopupAlternatingMenuItem(_("Suspend"),
_("Power Off..."));
this.menu.addMenuItem(item);
this._suspendOrPowerOffItem = item;
item.connect('activate', Lang.bind(this, this._onSuspendOrPowerOffActivate));
this._updateSuspendOrPowerOff();
},
_setPresenceStatus: function(item, event, status) {
this._presence.setStatus(status);
this._setIMStatus(status);
},
_onMyAccountActivate: function() {
Main.overview.hide();
this._spawn(['gnome-control-center', 'user-accounts']);
let app = Shell.AppSystem.get_default().get_app('gnome-user-accounts-panel.desktop');
app.activate(-1);
},
_onPreferencesActivate: function() {
Main.overview.hide();
this._spawn(['gnome-control-center']);
let app = Shell.AppSystem.get_default().get_app('gnome-control-center.desktop');
app.activate(-1);
},
_onLockScreenActivate: function() {
Main.overview.hide();
this._spawn(['gnome-screensaver-command', '--lock']);
this._screenSaverProxy.LockRemote();
},
_onLoginScreenActivate: function() {
@ -174,19 +263,45 @@ StatusMenuButton.prototype = {
_onQuitSessionActivate: function() {
Main.overview.hide();
this._spawn(['gnome-session-save', '--logout-dialog']);
this._session.LogoutRemote(0);
},
_onShutDownActivate: function() {
_onSuspendOrPowerOffActivate: function() {
Main.overview.hide();
this._spawn(['gnome-session-save', '--shutdown-dialog']);
if (this._haveSuspend &&
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
this._screenSaverProxy.LockRemote(Lang.bind(this, function() {
this._upClient.suspend_sync(null);
}));
} else {
this._session.ShutdownRemote();
}
},
_spawn: function(args) {
// FIXME: once Shell.Process gets support for signalling
// errors we should pop up an error dialog or something here
// on failure
let p = new Shell.Process({'args' : args});
p.run();
_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);
}
};

File diff suppressed because it is too large Load Diff

View File

@ -62,9 +62,16 @@ function addTween(target, tweeningParameters) {
function _wrapTweening(target, tweeningParameters) {
let state = _getTweenState(target);
if (target instanceof Clutter.Actor && !state.destroyedId)
state.destroyedId = target.connect('destroy', _actorDestroyed);
if (!state.destroyedId) {
if (target instanceof Clutter.Actor) {
state.actor = target;
state.destroyedId = target.connect('destroy', _actorDestroyed);
} else if (target.actor && target.actor instanceof Clutter.Actor) {
state.actor = target.actor;
state.destroyedId = target.actor.connect('destroy', function() { _actorDestroyed(target); });
}
}
_addHandler(target, tweeningParameters, 'onStart', _tweenStarted);
_addHandler(target, tweeningParameters, 'onComplete', _tweenCompleted);
}
@ -82,7 +89,7 @@ function _resetTweenState(target) {
if (state) {
if (state.destroyedId)
target.disconnect(state.destroyedId);
state.actor.disconnect(state.destroyedId);
if (state.idleCompletedId)
Mainloop.source_remove(state.idleCompletedId);
}

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,163 +16,12 @@ const Search = imports.ui.search;
const SearchDisplay = imports.ui.searchDisplay;
const Tweener = imports.ui.tweener;
function SearchEntry() {
this._init();
}
SearchEntry.prototype = {
_init : function() {
this.actor = new St.Entry({ name: 'searchEntry',
hint_text: _("Search your computer") });
this.entry = this.actor.clutter_text;
this.actor.clutter_text.connect('text-changed', Lang.bind(this,
function() {
if (this.isActive())
this.actor.set_secondary_icon_from_file(global.imagedir +
'close-black.svg');
else
this.actor.set_secondary_icon_from_file(null);
}));
this.actor.connect('secondary-icon-clicked', Lang.bind(this,
function() {
this.reset();
}));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
this.pane = null;
this._capturedEventId = 0;
},
_updateCursorVisibility: function() {
let focus = global.stage.get_key_focus();
if (focus == global.stage || focus == this.entry)
this.entry.set_cursor_visible(true);
else
this.entry.set_cursor_visible(false);
},
show: function() {
if (this._capturedEventId == 0)
this._capturedEventId = global.stage.connect('captured-event',
Lang.bind(this, this._onCapturedEvent));
this.entry.set_cursor_visible(true);
this.entry.set_selection(0, 0);
},
hide: function() {
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
},
reset: function () {
let [x, y, mask] = global.get_pointer();
let actor = global.stage.get_actor_at_pos (Clutter.PickMode.REACTIVE,
x, y);
// this.actor is never hovered directly, only its clutter_text and icon
let hovered = this.actor == actor.get_parent();
this.actor.set_hover(hovered);
this.entry.text = '';
// Return focus to the stage
global.stage.set_key_focus(null);
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 neither the stage nor our entry have key focus, 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 != global.stage && focus != this.entry)
return false;
let sym = event.get_key_symbol();
// If we have an active search, Escape cancels it - if we
// haven't, the key is ignored
if (sym == Clutter.Escape)
if (this._isActivated()) {
this.reset();
return true;
} else {
return false;
}
// Ignore non-printable keys
if (!Clutter.keysym_to_unicode(sym))
return false;
// Search started - move the key focus to the entry and
// "repeat" the event
if (!this._isActivated()) {
global.stage.set_key_focus(this.entry);
this.entry.event(event, false);
}
return false;
default:
// Suppress all other events outside the panel while the entry
// is activated and no search has been entered - any click
// outside the entry will cancel the search
return (this.entry.text == '' && !panelEvent);
}
},
_onDestroy: function() {
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
}
};
Signals.addSignalMethods(SearchEntry.prototype);
function BaseTab(titleActor, pageActor) {
this._init(titleActor, pageActor);
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,
@ -180,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,
@ -207,6 +68,11 @@ BaseTab.prototype = {
});
},
_a11yFocus: function() {
this._activate();
this.page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
_activate: function() {
this.emit('activated');
}
@ -214,19 +80,21 @@ 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);
}
};
@ -239,21 +107,43 @@ SearchTab.prototype = {
__proto__: BaseTab.prototype,
_init: function() {
this._searchActive = false;
this.active = false;
this._searchPending = false;
this._keyPressId = 0;
this._searchTimeoutId = 0;
this._searchSystem = new Search.SearchSystem();
this._openSearchSystem = new Search.OpenSearchSystem();
this._searchEntry = new SearchEntry();
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
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();
@ -261,31 +151,51 @@ SearchTab.prototype = {
this._searchResults.activateSelected();
return true;
}));
},
setFindAsYouType: function(enabled) {
if (enabled)
this._searchEntry.show();
else
this._searchEntry.hide();
},
this._entry.connect('secondary-icon-clicked', Lang.bind(this,
function() {
this._reset();
}));
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
show: function() {
BaseTab.prototype.show.call(this);
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
if (this._keyPressId == 0)
this._keyPressId = global.stage.connect('key-press-event',
Lang.bind(this, this._onKeyPress));
this._capturedEventId = 0;
},
hide: function() {
BaseTab.prototype.hide.call(this);
if (this._keyPressId > 0) {
global.stage.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) {
@ -293,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;
@ -317,34 +250,46 @@ SearchTab.prototype = {
this._searchTimeoutId = Mainloop.timeout_add(150, Lang.bind(this, this._doSearch));
},
_onKeyPress: function(stage, event) {
// If neither the stage nor the search entry have key focus, some
// "special" actor grabbed the focus (run dialog, looking glass);
// we don't want to interfere with that
let focus = stage.get_key_focus();
if (focus != stage && focus != this._searchEntry.entry)
return false;
_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;
@ -402,9 +347,24 @@ ViewSelector.prototype = {
this._switchTab(this._activeTab);
}));
this._keyPressId = 0;
this._itemDragBeginId = 0;
this._overviewHidingId = 0;
Main.overview.connect('item-drag-begin',
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
@ -428,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;
@ -451,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,
@ -478,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]);
@ -559,70 +531,31 @@ ViewSelector.prototype = {
}));
},
_onKeyPress: function(stage, event) {
// Only process events if the stage has key focus - search is handled
// by the search tab, and we do not want to interfere with "special"
// actors grabbing focus (run dialog, looking glass, notifications).
let focus = stage.get_key_focus();
if (focus != stage)
return false;
_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;
},
addSearchProvider: function(provider) {
this._searchTab.addSearchProvider(provider);
},
show: function() {
this._searchTab.setFindAsYouType(true);
if (this._itemDragBeginId == 0)
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
Lang.bind(this, this._switchDefaultTab));
if (this._overviewHidingId == 0)
this._overviewHidingId = Main.overview.connect('hiding',
Lang.bind(this, this._switchDefaultTab));
if (this._keyPressId == 0)
this._keyPressId = global.stage.connect('key-press-event',
Lang.bind(this, this._onKeyPress));
this._switchDefaultTab();
},
hide: function() {
this._searchTab.setFindAsYouType(false);
if (this._keyPressId > 0) {
global.stage.disconnect(this._keyPressId);
this._keyPressId = 0;
}
if (this._itemDragBeginId > 0) {
Main.overview.disconnect(this._itemDragBeginId);
this._itemDragBeginId = 0;
}
if (this._overviewHidingId > 0) {
Main.overview.disconnect(this._overviewHidingId);
this._overviewHidingId = 0;
}
}
};
Signals.addSignalMethods(ViewSelector.prototype);

View File

@ -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) {
@ -116,14 +118,16 @@ WindowManager.prototype = {
this.setKeybindingHandler('switch_to_workspace_up', Lang.bind(this, this._showWorkspaceSwitcher));
this.setKeybindingHandler('switch_to_workspace_down', Lang.bind(this, this._showWorkspaceSwitcher));
this.setKeybindingHandler('switch_windows', Lang.bind(this, this._startAppSwitcher));
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);
}));
},
@ -137,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;
@ -222,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,
@ -267,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,
@ -292,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();
@ -362,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;
@ -497,6 +511,8 @@ WindowManager.prototype = {
for (let i = 0; i < switchData.windows.length; i++) {
let w = switchData.windows[i];
if (w.window.is_destroyed()) // Window gone
continue;
if (w.window.get_parent() == switchData.outGroup) {
w.window.reparent(w.parent);
w.window.hide();
@ -518,49 +534,88 @@ WindowManager.prototype = {
let tabPopup = new AltTab.AltTabPopup();
if (!tabPopup.show(backwards))
if (!tabPopup.show(backwards, binding == 'switch_group'))
tabPopup.destroy();
},
_showWorkspaceSwitcher : function(shellwm, binding, window, backwards) {
/* We don't support this kind of layout */
if (binding == 'switch_to_workspace_up' || binding == 'switch_to_workspace_down')
return;
_startA11ySwitcher : function(shellwm, binding, window, backwards) {
Main.ctrlAltTabManager.popup(backwards);
},
_showWorkspaceSwitcher : function(shellwm, binding, window, backwards) {
if (global.screen.n_workspaces == 1)
return;
if (this._workspaceSwitcherPopup == null)
this._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup();
if (binding == 'switch_to_workspace_left') {
this.actionMoveWorkspaceLeft();
}
if (binding == 'switch_to_workspace_right') {
this.actionMoveWorkspaceRight();
}
if (binding == 'switch_to_workspace_up')
this.actionMoveWorkspaceUp();
else if (binding == 'switch_to_workspace_down')
this.actionMoveWorkspaceDown();
// left/right would effectively act as synonyms for up/down if we enabled them;
// but that could be considered confusing.
// else if (binding == 'switch_to_workspace_left')
// this.actionMoveWorkspaceLeft();
// else if (binding == 'switch_to_workspace_right')
// this.actionMoveWorkspaceRight();
},
actionMoveWorkspaceLeft: function() {
let rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
if (activeWorkspaceIndex > 0) {
global.screen.get_workspace_by_index(activeWorkspaceIndex - 1).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.LEFT, activeWorkspaceIndex - 1);
} else if (!Main.overview.visible) {
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.LEFT, activeWorkspaceIndex);
}
let indexToActivate = activeWorkspaceIndex;
if (rtl && activeWorkspaceIndex < global.screen.n_workspaces - 1)
indexToActivate++;
else if (!rtl && activeWorkspaceIndex > 0)
indexToActivate--;
if (indexToActivate != activeWorkspaceIndex)
global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.UP, indexToActivate);
},
actionMoveWorkspaceRight: function() {
let rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
if (activeWorkspaceIndex < global.screen.n_workspaces - 1) {
global.screen.get_workspace_by_index(activeWorkspaceIndex + 1).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.RIGHT, activeWorkspaceIndex + 1);
} else if (!Main.overview.visible) {
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.RIGHT, activeWorkspaceIndex);
}
let indexToActivate = activeWorkspaceIndex;
if (rtl && activeWorkspaceIndex > 0)
indexToActivate--;
else if (!rtl && activeWorkspaceIndex < global.screen.n_workspaces - 1)
indexToActivate++;
if (indexToActivate != activeWorkspaceIndex)
global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.DOWN, indexToActivate);
},
actionMoveWorkspaceUp: function() {
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let indexToActivate = activeWorkspaceIndex;
if (activeWorkspaceIndex > 0)
indexToActivate--;
if (indexToActivate != activeWorkspaceIndex)
global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.UP, indexToActivate);
},
actionMoveWorkspaceDown: function() {
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let indexToActivate = activeWorkspaceIndex;
if (activeWorkspaceIndex < global.screen.n_workspaces - 1)
indexToActivate++;
if (indexToActivate != activeWorkspaceIndex)
global.screen.get_workspace_by_index(indexToActivate).activate(global.get_current_time());
if (!Main.overview.visible)
this._workspaceSwitcherPopup.display(WorkspaceSwitcherPopup.DOWN, indexToActivate);
}
};

View File

@ -104,6 +104,12 @@ WindowClone.prototype = {
this._stackAbove = null;
this._sizeChangedId = this.realWindow.connect('size-changed', Lang.bind(this, function() {
this.emit('size-changed');
}));
this._realWindowDestroyId = this.realWindow.connect('destroy',
Lang.bind(this, this._disconnectRealWindowSignals));
this.actor.connect('button-release-event',
Lang.bind(this, this._onButtonRelease));
@ -119,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;
@ -156,7 +163,19 @@ WindowClone.prototype = {
}
},
_disconnectRealWindowSignals: function() {
if (this._sizeChangedId > 0)
this.realWindow.disconnect(this._sizeChangedId);
this._sizeChangedId = 0;
if (this._realWindowDestroyId > 0)
this.realWindow.disconnect(this._realWindowDestroyId);
this._realWindowDestroyId = 0;
},
_onDestroy: function() {
this._disconnectRealWindowSignals();
this.metaWindow._delegate = null;
this.actor._delegate = null;
if (this._zoomLightbox)
@ -202,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 () {
@ -270,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;
@ -309,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 });
@ -354,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,
@ -396,13 +425,18 @@ WindowOverlay.prototype = {
// These parameters are not the values retrieved with
// get_transformed_position() and get_transformed_size(),
// as windowClone might be moving.
// See Workspace._fadeInWindowOverlay
// See Workspace._showWindowOverlay
updatePositions: function(cloneX, cloneY, cloneWidth, cloneHeight) {
let button = this.closeButton;
let title = this.title;
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)
@ -457,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');
@ -497,56 +537,47 @@ 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({ reactive: true });
this.actor._delegate = this;
this.actor = new Clutter.Group();
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));
this.actor.connect('button-release-event', Lang.bind(this,
function(actor, event) {
// Only switch to the workspace when there's no application
// windows open. The problem is that it's too easy to miss
// an app window and get the wrong one focused.
if (this._windows.length == 0) {
this.metaWorkspace.activate(event.get_time());
Main.overview.hide();
}
}));
// 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 = global.get_window_actors().filter(this._isMyWindow, this);
// Create clones for remaining windows that should be
// Create clones for windows that should be
// visible in the Overview
this._windows = [];
this._windowOverlays = [];
@ -556,21 +587,38 @@ Workspace.prototype = {
}
}
// A filter for what windows we display
this._showOnlyWindows = null;
// 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._visible = false;
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) {
@ -580,73 +628,12 @@ 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);
},
/**
* lookupCloneForMetaWindow:
* @metaWindow: A #MetaWindow
*
* Given a #MetaWindow instance, find the WindowClone object
* which represents it in the workspaces display.
*/
lookupCloneForMetaWindow: function (metaWindow) {
let index = this._lookupIndex (metaWindow);
return index < 0 ? null : this._windows[index];
},
containsMetaWindow: function (metaWindow) {
return this._lookupIndex(metaWindow) >= 0;
},
setShowOnlyWindows: function(showOnlyWindows, reposition) {
this._showOnlyWindows = showOnlyWindows;
this._resetCloneVisibility();
if (reposition)
this.positionWindows(WindowPositionFlags.ANIMATE);
},
/**
* setLightboxMode:
* @showLightbox: If true, dim background and allow highlighting a specific window
*
* This function also resets the highlighted window state.
*/
setLightboxMode: function (showLightbox) {
if (!this._lightbox)
this._lightbox = new Lightbox.Lightbox(this.actor,
{ fadeTime: LIGHTBOX_FADE_TIME });
if (showLightbox)
this._lightbox.show();
else
this._lightbox.hide();
},
/**
* setHighlightWindow:
* @metaWindow: A #MetaWindow
*
* Draw the user's attention to the given window @metaWindow.
*/
setHighlightWindow: function (metaWindow) {
if (!this._lightbox)
return;
let actor;
if (metaWindow != null) {
let clone = this.lookupCloneForMetaWindow(metaWindow);
actor = clone.actor;
}
this._lightbox.highlight(actor);
isEmpty: function() {
return this._windows.length == 0;
},
/**
@ -659,47 +646,6 @@ Workspace.prototype = {
this.actor.reactive = reactive;
},
_isCloneVisible: function(clone) {
return this._showOnlyWindows == null || (clone.metaWindow in this._showOnlyWindows);
},
/**
* _getVisibleClones:
*
* Returns a list WindowClone objects where the clone isn't filtered
* out by any application filter.
* The returned array will always be newly allocated; it is not in any
* defined order, and thus it's convenient to call .sort() with your
* choice of sorting function.
*/
_getVisibleClones: function() {
let visible = [];
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
if (!this._isCloneVisible(clone))
continue;
visible.push(clone);
}
return visible;
},
_resetCloneVisibility: function () {
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
let overlay = this._windowOverlays[i];
if (!this._isCloneVisible(clone)) {
clone.actor.hide();
overlay.hide();
} else {
clone.actor.show();
}
}
},
// Only use this for n <= 20 say
_factorial: function(n) {
let result = 1;
@ -760,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;
@ -788,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) {
@ -848,63 +810,55 @@ 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);
_computeWindowLayout: function(metaWindow, slot) {
let [x, y, width, height] = this._getSlotGeometry(slot);
xCenter = xCenter * global.screen_width;
let rect = new Meta.Rectangle();
metaWindow.get_outer_rect(rect);
let rect = metaWindow.get_outer_rect();
let buttonOuterHeight, captionHeight;
let buttonOuterWidth = 0;
if (this._windowOverlays[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);
@ -912,6 +866,9 @@ Workspace.prototype = {
},
setReservedSlot: function(clone) {
if (this._reservedSlot == clone)
return;
if (clone && this.containsMetaWindow(clone.metaWindow)) {
this._reservedSlot = null;
this.positionWindows(WindowPositionFlags.ANIMATE);
@ -927,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) {
@ -936,22 +893,23 @@ Workspace.prototype = {
this._repositionWindowsId = 0;
}
let totalVisible = 0;
let visibleClones = this._getVisibleClones();
let clones = this._windows.slice();
if (this._reservedSlot)
visibleClones.push(this._reservedSlot);
clones.push(this._reservedSlot);
let workspaceZooming = flags & WindowPositionFlags.ZOOM;
let initialPositioning = flags & WindowPositionFlags.INITIAL;
let animate = flags & WindowPositionFlags.ANIMATE;
// Start the animations
let slots = this._computeAllWindowSlots(visibleClones.length);
visibleClones = this._orderWindowsByMotionAndStartup(visibleClones, slots);
let slots = this._computeAllWindowSlots(clones.length);
clones = this._orderWindowsByMotionAndStartup(clones, slots);
for (let i = 0; i < visibleClones.length; i++) {
let currentWorkspace = global.screen.get_active_workspace();
let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
for (let i = 0; i < clones.length; i++) {
let slot = slots[i];
let clone = visibleClones[i];
let clone = clones[i];
let metaWindow = clone.metaWindow;
let mainIndex = this._lookupIndex(metaWindow);
let overlay = this._windowOverlays[mainIndex];
@ -961,16 +919,16 @@ 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();
if (animate) {
if (animate && isOnCurrentWorkspace) {
if (!metaWindow.showing_on_its_workspace()) {
/* Hidden windows should fade in and grow
* therefore we need to resize them now so they
* can be scaled up later */
if (workspaceZooming) {
if (initialPositioning) {
clone.actor.opacity = 0;
clone.actor.scale_x = 0;
clone.actor.scale_y = 0;
@ -991,38 +949,37 @@ 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() {
this._fadeInWindowOverlay(clone, overlay);
this._showWindowOverlay(clone, overlay, true);
})
});
} else {
clone.actor.set_position(x, y);
clone.actor.set_scale(scale, scale);
this._fadeInWindowOverlay(clone, overlay);
this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
}
}
},
syncStacking: function(stackIndices) {
let visibleClones = this._getVisibleClones();
visibleClones.sort(function (a, b) { return stackIndices[a.metaWindow.get_stable_sequence()] - stackIndices[b.metaWindow.get_stable_sequence()]; });
let clones = this._windows.slice();
clones.sort(function (a, b) { return stackIndices[a.metaWindow.get_stable_sequence()] - stackIndices[b.metaWindow.get_stable_sequence()]; });
for (let i = 0; i < visibleClones.length; i++) {
let clone = visibleClones[i];
for (let i = 0; i < clones.length; i++) {
let clone = clones[i];
let metaWindow = clone.metaWindow;
if (i == 0) {
clone.setStackAbove(null);
clone.setStackAbove(this._dropRect);
} else {
let previousClone = visibleClones[i - 1];
let previousClone = clones[i - 1];
clone.setStackAbove(previousClone.actor);
}
}
},
_fadeInWindowOverlay: function(clone, overlay) {
_showWindowOverlay: function(clone, overlay, fade) {
if (clone.inDrag)
return;
@ -1034,34 +991,25 @@ 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;
if (!this._windowOverlaysGroup.visible)
this._windowOverlaysGroup.show();
cloneWidth = clone.actor.scale_x * cloneWidth;
cloneHeight = clone.actor.scale_y * cloneHeight;
if (overlay) {
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
overlay.fadeIn();
if (fade)
overlay.fadeIn();
else
overlay.show();
}
},
_fadeInAllOverlays: function() {
_showAllOverlays: function() {
let currentWorkspace = global.screen.get_active_workspace();
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
let overlay = this._windowOverlays[i];
if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows))
continue;
this._fadeInWindowOverlay(clone, overlay);
}
},
_hideAllOverlays: function() {
for (let i = 0; i < this._windows.length; i++) {
let overlay = this._windowOverlays[i];
overlay.hide();
this._showWindowOverlay(clone, overlay,
this.metaWorkspace == null || this.metaWorkspace == currentWorkspace);
}
},
@ -1070,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
@ -1089,15 +1035,18 @@ Workspace.prototype = {
},
showWindowsOverlays: function() {
if (this.leavingOverview)
return;
this._windowOverlaysGroup.show();
this._fadeInAllOverlays();
this._showAllOverlays();
},
hideWindowsOverlays: function() {
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
@ -1106,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);
@ -1149,7 +1102,7 @@ Workspace.prototype = {
Lang.bind(this, this._delayedWindowRepositioning));
},
_windowAdded : function(metaWorkspace, metaWin) {
_doAddWindow : function(metaWin) {
if (this.leavingOverview)
return;
@ -1161,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++) {
@ -1199,23 +1184,20 @@ 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._visible = true;
this.positionWindows(WindowPositionFlags.INITIAL);
},
// Animates the return from Overview mode
zoomFromOverview : function() {
let currentWorkspace = global.screen.get_active_workspace();
this.leavingOverview = true;
this._hideAllOverlays();
this.hideWindowsOverlays();
if (this._repositionWindowsId > 0) {
Mainloop.source_remove(this._repositionWindowsId);
@ -1224,6 +1206,9 @@ Workspace.prototype = {
this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
this._doneLeavingOverview));
if (this.metaWorkspace != null && this.metaWorkspace != currentWorkspace)
return;
// Position and scale the windows.
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
@ -1236,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'
@ -1247,14 +1231,12 @@ Workspace.prototype = {
{ scale_x: 0,
scale_y: 0,
opacity: 0,
workspace_relative: this,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
}
this._visible = false;
},
destroy : function() {
@ -1268,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);
@ -1288,10 +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 win.get_workspace() == this.metaWorkspace.index() ||
(win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
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
@ -1312,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();
@ -1325,6 +1315,10 @@ Workspace.prototype = {
Lang.bind(this, function() {
this._windowIsZooming = false;
}));
clone.connect('size-changed',
Lang.bind(this, function() {
this.positionWindows(0);
}));
this.actor.add_actor(clone.actor);
@ -1371,18 +1365,15 @@ Workspace.prototype = {
},
_onCloneSelected : function (clone, time) {
Main.activateWindow(clone.metaWindow, time,
this.metaWorkspace.index());
},
_removeSelf : function(actor, event) {
screen.remove_workspace(this.metaWorkspace, event.get_time());
return true;
let wsIndex = undefined;
if (this.metaWorkspace)
wsIndex = this.metaWorkspace.index();
Main.activateWindow(clone.metaWindow, time, wsIndex);
},
// Draggable target interface
handleDragOver : function(source, actor, x, y, time) {
if (source instanceof WindowClone)
if (source.realWindow && !this._isMyWindow(source.realWindow))
return DND.DragMotionResult.MOVE_DROP;
if (source.shellWorkspaceLaunch)
return DND.DragMotionResult.COPY_DROP;
@ -1391,7 +1382,7 @@ Workspace.prototype = {
},
acceptDrop : function(source, actor, x, y, time) {
if (source instanceof WindowClone) {
if (source.realWindow) {
let win = source.realWindow;
if (this._isMyWindow(win))
return false;
@ -1405,13 +1396,21 @@ 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;
} else if (source.shellWorkspaceLaunch) {
this.metaWorkspace.activate(time);
source.shellWorkspaceLaunch();
source.shellWorkspaceLaunch({ workspace: this.metaWorkspace,
timestamp: time });
return true;
}
@ -1420,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

@ -12,8 +12,8 @@ const Tweener = imports.ui.tweener;
const ANIMATION_TIME = 0.1;
const DISPLAY_TIMEOUT = 600;
const LEFT = -1;
const RIGHT = 1;
const UP = -1;
const DOWN = 1;
function WorkspaceSwitcherPopup() {
this._init();
@ -32,6 +32,8 @@ WorkspaceSwitcherPopup.prototype = {
this._container = new St.BoxLayout({ style_class: 'workspace-switcher-container' });
this._list = new Shell.GenericContainer({ style_class: 'workspace-switcher' });
this._itemSpacing = 0;
this._childHeight = 0;
this._childWidth = 0;
this._list.connect('style-changed', Lang.bind(this, function() {
this._itemSpacing = this._list.get_theme_node().get_length('spacing');
}));
@ -47,57 +49,59 @@ WorkspaceSwitcherPopup.prototype = {
this._position();
this.actor.show();
this.actor.hide();
this._timeoutId = Mainloop.timeout_add(DISPLAY_TIMEOUT, Lang.bind(this, this._onTimeout));
},
_getPreferredWidth : function (actor, forHeight, alloc) {
_getPreferredHeight : function (actor, forWidth, alloc) {
let children = this._list.get_children();
let primary = global.get_primary_monitor();
let availwidth = primary.width;
availwidth -= this.actor.get_theme_node().get_horizontal_padding();
availwidth -= this._container.get_theme_node().get_horizontal_padding();
availwidth -= this._list.get_theme_node().get_horizontal_padding();
let availHeight = primary.height;
availHeight -= Main.panel.actor.height;
availHeight -= this.actor.get_theme_node().get_vertical_padding();
availHeight -= this._container.get_theme_node().get_vertical_padding();
availHeight -= this._list.get_theme_node().get_vertical_padding();
let width = 0;
let height = 0;
for (let i = 0; i < children.length; i++) {
let [childMinWidth, childNaturalWidth] = children[i].get_preferred_width(-1);
let [childMinHeight, childNaturalHeight] = children[i].get_preferred_height(childNaturalWidth);
width += childNaturalHeight * primary.width / primary.height;
let [childMinHeight, childNaturalHeight] = children[i].get_preferred_height(-1);
let [childMinWidth, childNaturalWidth] = children[i].get_preferred_width(childNaturalHeight);
height += childNaturalHeight * primary.width / primary.height;
}
let spacing = this._itemSpacing * (global.screen.n_workspaces - 1);
width += spacing;
width = Math.min(width, availwidth);
height += spacing;
height = Math.min(height, availHeight);
this._childWidth = (width - spacing) / global.screen.n_workspaces;
this._childHeight = (height - spacing) / global.screen.n_workspaces;
alloc.min_size = width;
alloc.natural_size = width;
alloc.min_size = height;
alloc.natural_size = height;
},
_getPreferredHeight : function (actor, forWidth, alloc) {
_getPreferredWidth : function (actor, forHeight, alloc) {
let primary = global.get_primary_monitor();
this._childHeight = Math.round(this._childWidth * primary.height / primary.width);
this._childWidth = Math.round(this._childHeight * primary.width / primary.height);
alloc.min_size = this._childHeight;
alloc.natural_size = this._childHeight;
alloc.min_size = this._childWidth;
alloc.natural_size = this._childWidth;
},
_allocate : function (actor, box, flags) {
let children = this._list.get_children();
let childBox = new Clutter.ActorBox();
let x = box.x1;
let prevChildBoxX2 = box.x1 - this._itemSpacing;
let y = box.y1;
let prevChildBoxY2 = box.y1 - this._itemSpacing;
for (let i = 0; i < children.length; i++) {
childBox.x1 = prevChildBoxX2 + this._itemSpacing;
childBox.x2 = Math.round(x + this._childWidth);
childBox.y1 = box.y1;
childBox.y2 = box.y1 + this._childHeight;
x += this._childWidth + this._itemSpacing;
prevChildBoxX2 = childBox.x2;
childBox.x1 = box.x1;
childBox.x2 = box.x1 + this._childWidth;
childBox.y1 = prevChildBoxY2 + this._itemSpacing;
childBox.y2 = Math.round(y + this._childHeight);
y += this._childHeight + this._itemSpacing;
prevChildBoxY2 = childBox.y2;
children[i].allocate(childBox, flags);
}
},
@ -108,10 +112,10 @@ WorkspaceSwitcherPopup.prototype = {
for (let i = 0; i < global.screen.n_workspaces; i++) {
let indicator = null;
if (i == activeWorkspaceIndex && direction == LEFT)
indicator = new St.Bin({ style_class: 'ws-switcher-active-left' });
else if(i == activeWorkspaceIndex && direction == RIGHT)
indicator = new St.Bin({ style_class: 'ws-switcher-active-right' });
if (i == activeWorkspaceIndex && direction == UP)
indicator = new St.Bin({ style_class: 'ws-switcher-active-up' });
else if(i == activeWorkspaceIndex && direction == DOWN)
indicator = new St.Bin({ style_class: 'ws-switcher-active-down' });
else
indicator = new St.Bin({ style_class: 'ws-switcher-box' });
@ -123,7 +127,8 @@ WorkspaceSwitcherPopup.prototype = {
_position: function() {
let primary = global.get_primary_monitor();
this._container.x = primary.x + Math.floor((primary.width - this._container.width) / 2);
this._container.y = primary.y + Math.floor((primary.height - this._container.height) / 2);
this._container.y = primary.y + Main.panel.actor.height +
Math.floor(((primary.height - Main.panel.actor.height) - this._container.height) / 2);
},
_show : function() {

885
js/ui/workspaceThumbnail.js Normal file
View File

@ -0,0 +1,885 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const WorkspacesView = imports.ui.workspacesView;
// The maximum size of a thumbnail is 1/8 the width and height of the screen
let MAX_THUMBNAIL_SCALE = 1/8.;
const RESCALE_ANIMATION_TIME = 0.2;
const SLIDE_ANIMATION_TIME = 0.2;
function WindowClone(realWindow) {
this._init(realWindow);
}
WindowClone.prototype = {
_init : function(realWindow) {
this.actor = new Clutter.Clone({ source: realWindow.get_texture(),
reactive: true });
this.actor._delegate = this;
this.realWindow = realWindow;
this.metaWindow = realWindow.meta_window;
this._positionChangedId = this.realWindow.connect('position-changed',
Lang.bind(this, this._onPositionChanged));
this._realWindowDestroyedId = this.realWindow.connect('destroy',
Lang.bind(this, this._disconnectRealWindowSignals));
this._onPositionChanged();
this.actor.connect('button-release-event',
Lang.bind(this, this._onButtonRelease));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._draggable = DND.makeDraggable(this.actor,
{ restoreOnSuccess: true,
dragActorMaxSize: Workspace.WINDOW_DND_SIZE,
dragActorOpacity: Workspace.DRAGGING_WINDOW_OPACITY });
this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
this.inDrag = false;
},
setStackAbove: function (actor) {
this._stackAbove = actor;
if (this._stackAbove == null)
this.actor.lower_bottom();
else
this.actor.raise(this._stackAbove);
},
destroy: function () {
this.actor.destroy();
},
_onPositionChanged: function() {
let rect = this.metaWindow.get_outer_rect();
this.actor.set_position(this.realWindow.x, this.realWindow.y);
},
_disconnectRealWindowSignals: function() {
if (this._positionChangedId != 0) {
this.realWindow.disconnect(this._positionChangedId);
this._positionChangedId = 0;
}
if (this._realWindowDestroyedId != 0) {
this.realWindow.disconnect(this._realWindowDestroyedId);
this._realWindowDestroyedId = 0;
}
},
_onDestroy: function() {
this._disconnectRealWindowSignals();
this.actor._delegate = null;
if (this.inDrag) {
this.emit('drag-end');
this.inDrag = false;
}
this.disconnectAll();
},
_onButtonRelease : function (actor, event) {
this.emit('selected', event.get_time());
return true;
},
_onDragBegin : function (draggable, time) {
this.inDrag = true;
this.emit('drag-begin');
},
_onDragEnd : function (draggable, time, snapback) {
this.inDrag = false;
// We may not have a parent if DnD completed successfully, in
// which case our clone will shortly be destroyed and replaced
// with a new one on the target workspace.
if (this.actor.get_parent() != null) {
if (this._stackAbove == null)
this.actor.lower_bottom();
else
this.actor.raise(this._stackAbove);
}
this.emit('drag-end');
}
};
Signals.addSignalMethods(WindowClone.prototype);
const ThumbnailState = {
NEW : 0,
ANIMATING_IN : 1,
NORMAL: 2,
REMOVING : 3,
ANIMATING_OUT : 4,
ANIMATED_OUT : 5,
COLLAPSING : 6,
DESTROYED : 7
};
/**
* @metaWorkspace: a #Meta.Workspace
*/
function WorkspaceThumbnail(metaWorkspace) {
this._init(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,
style_class: 'workspace-thumbnail' });
this.actor._delegate = this;
this._contents = new Clutter.Group();
this.actor.add_actor(this._contents);
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('button-press-event', Lang.bind(this,
function(actor, event) {
return true;
}));
this.actor.connect('button-release-event', Lang.bind(this,
function(actor, event) {
this._activate();
return true;
}));
this._background = new Clutter.Clone({ source: global.background_actor });
this._contents.add_actor(this._background);
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);
// Create clones for windows that should be visible in the Overview
this._windows = [];
for (let i = 0; i < windows.length; i++) {
if (this._isOverviewWindow(windows[i])) {
this._addWindowClone(windows[i]);
}
}
// 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));
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
this._collapseFraction = 0; // Not collapsed
},
setPorthole: function(x, y, width, height) {
this._portholeX = x;
this._portholeY = y;
this.actor.set_size(width, height);
this._contents.set_position(-x, -y);
},
_lookupIndex: function (metaWindow) {
for (let i = 0; i < this._windows.length; i++) {
if (this._windows[i].metaWindow == metaWindow) {
return i;
}
}
return -1;
},
syncStacking: function(stackIndices) {
this._windows.sort(function (a, b) { return stackIndices[a.metaWindow.get_stable_sequence()] - stackIndices[b.metaWindow.get_stable_sequence()]; });
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
let metaWindow = clone.metaWindow;
if (i == 0) {
clone.setStackAbove(this._background);
} else {
let previousClone = this._windows[i - 1];
clone.setStackAbove(previousClone.actor);
}
}
},
set slidePosition(slidePosition) {
this._slidePosition = slidePosition;
this.actor.queue_relayout();
},
get slidePosition() {
return this._slidePosition;
},
set collapseFraction(collapseFraction) {
this._collapseFraction = collapseFraction;
this.actor.queue_relayout();
},
get collapseFraction() {
return this._collapseFraction;
},
_doRemoveWindow : function(metaWin) {
let win = metaWin.get_compositor_private();
// find the position of the window in our list
let index = this._lookupIndex (metaWin);
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();
},
_doAddWindow : function(metaWin) {
if (this.leavingOverview)
return;
let win = metaWin.get_compositor_private();
if (!win) {
// Newly-created windows are added to a workspace before
// the compositor finds out about them...
Mainloop.idle_add(Lang.bind(this,
function () {
if (this.actor && metaWin.get_compositor_private())
this._doAddWindow(metaWin);
return false;
}));
return;
}
// 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();
},
_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 workspace and monitor
_isMyWindow : function (win) {
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
_isOverviewWindow : function (win) {
let tracker = Shell.WindowTracker.get_default();
return tracker.is_window_interesting(win.get_meta_window());
},
// Create a clone of a (non-desktop) window and add it to the window list
_addWindowClone : function(win) {
let clone = new WindowClone(win);
clone.connect('selected',
Lang.bind(this, this._activate));
clone.connect('drag-begin',
Lang.bind(this, function(clone) {
Main.overview.beginWindowDrag();
}));
clone.connect('drag-end',
Lang.bind(this, function(clone) {
Main.overview.endWindowDrag();
}));
this._contents.add_actor(clone.actor);
if (this._windows.length == 0)
clone.setStackAbove(this._background);
else
clone.setStackAbove(this._windows[this._windows.length - 1].actor);
this._windows.push(clone);
return clone;
},
_activate : function (clone, time) {
if (this.state > ThumbnailState.NORMAL)
return;
// a click on the already current workspace should go back to the main view
if (this.metaWorkspace == global.screen.get_active_workspace())
Main.overview.hide();
else
this.metaWorkspace.activate(time);
},
// 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;
if (source.realWindow && !this._isMyWindow(source.realWindow))
return DND.DragMotionResult.MOVE_DROP;
if (source.shellWorkspaceLaunch)
return DND.DragMotionResult.COPY_DROP;
return DND.DragMotionResult.CONTINUE;
},
acceptDrop : function(source, actor, x, y, time) {
if (this.state > ThumbnailState.NORMAL)
return false;
if (source.realWindow) {
let win = source.realWindow;
if (this._isMyWindow(win))
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);
return true;
} else if (source.shellWorkspaceLaunch) {
source.shellWorkspaceLaunch({ workspace: this.metaWorkspace,
timestamp: time });
return true;
}
return false;
}
};
Signals.addSignalMethods(WorkspaceThumbnail.prototype);
function ThumbnailsBox() {
this._init();
}
ThumbnailsBox.prototype = {
_init: function() {
this.actor = new Shell.GenericContainer({ style_class: 'workspace-thumbnails',
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT });
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));
// When we animate the scale, we don't animate the requested size of the thumbnails, rather
// we ask for our final size and then animate within that size. This slightly simplifies the
// interaction with the main workspace windows (instead of constantly reallocating them
// to a new size, they get a new size once, then use the standard window animation code
// allocate the windows to their new positions), however it causes problems for drawing
// the background and border wrapped around the thumbnail as we animate - we can't just pack
// the container into a box and set style properties on the box since that box would wrap
// around the final size not the animating size. So instead we fake the background with
// an actor underneath the content and adjust the allocation of our children to leave space
// for the border and padding of the background actor.
this._background = new St.Bin({ style_class: 'workspace-thumbnails-background' });
this.actor.add_actor(this._background);
let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator' });
// We don't want the indicator to affect drag-and-drop
Shell.util_set_hidden_from_pick(indicator, true);
this._indicator = indicator;
this.actor.add_actor(indicator);
this._targetScale = 0;
this._scale = 0;
this._pendingScaleUpdate = false;
this._stateUpdateQueued = false;
this._animatingIndicator = false;
this._indicatorY = 0; // only used when _animatingIndicator is true
this._stateCounts = {};
for (let key in ThumbnailState)
this._stateCounts[ThumbnailState[key]] = 0;
this._thumbnails = [];
},
show: function() {
this._switchWorkspaceNotifyId =
global.window_manager.connect('switch-workspace',
Lang.bind(this, this._activeWorkspaceChanged));
this._targetScale = 0;
this._scale = 0;
this._pendingScaleUpdate = false;
this._stateUpdateQueued = false;
this._stateCounts = {};
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: monitor.x,
y: monitor.y + panelHeight,
width: monitor.width,
height: monitor.height - panelHeight
};
this.addThumbnails(0, global.screen.n_workspaces);
},
hide: function() {
if (this._switchWorkspaceNotifyId > 0) {
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
this._switchWorkspaceNotifyId = 0;
}
for (let w = 0; w < this._thumbnails.length; w++)
this._thumbnails[w].destroy();
this._thumbnails = [];
},
addThumbnails: function(start, count) {
for (let k = start; k < start + count; k++) {
let metaWorkspace = global.screen.get_workspace_by_index(k);
let thumbnail = new WorkspaceThumbnail(metaWorkspace);
thumbnail.setPorthole(this._porthole.x, this._porthole.y,
this._porthole.width, this._porthole.height);
this._thumbnails.push(thumbnail);
this.actor.add_actor(thumbnail.actor);
if (start > 0) { // not the initial fill
thumbnail.state = ThumbnailState.NEW;
thumbnail.slidePosition = 1; // start slid out
this._haveNewThumbnails = true;
} else {
thumbnail.state = ThumbnailState.NORMAL;
}
this._stateCounts[thumbnail.state]++;
}
this._queueUpdateStates();
// The thumbnails indicator actually needs to be on top of the thumbnails
this._indicator.raise_top();
},
removeThumbmails: function(start, count) {
let currentPos = 0;
for (let k = 0; k < this._thumbnails.length; k++) {
let thumbnail = this._thumbnails[k];
if (thumbnail.state > ThumbnailState.NORMAL)
continue;
if (currentPos >= start && currentPos < start + count)
this._setThumbnailState(thumbnail, ThumbnailState.REMOVING);
currentPos++;
}
this._queueUpdateStates();
},
syncStacking: function(stackIndices) {
for (let i = 0; i < this._thumbnails.length; i++)
this._thumbnails[i].syncStacking(stackIndices);
},
set scale(scale) {
this._scale = scale;
this.actor.queue_relayout();
},
get scale() {
return this._scale;
},
set indicatorY(indicatorY) {
this._indicatorY = indicatorY;
this.actor.queue_relayout();
},
get indicatorY() {
return this._indicatorY;
},
_setThumbnailState: function(thumbnail, state) {
this._stateCounts[thumbnail.state]--;
thumbnail.state = state;
this._stateCounts[thumbnail.state]++;
},
_iterateStateThumbnails: function(state, callback) {
if (this._stateCounts[state] == 0)
return;
for (let i = 0; i < this._thumbnails.length; i++) {
if (this._thumbnails[i].state == state)
callback.call(this, this._thumbnails[i]);
}
},
_tweenScale: function() {
Tweener.addTween(this,
{ scale: this._targetScale,
time: RESCALE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._queueUpdateStates,
onCompleteScope: this });
},
_updateStates: function() {
this._stateUpdateQueued = false;
// If we are animating the indicator, wait
if (this._animatingIndicator)
return;
// Then slide out any thumbnails that have been destroyed
this._iterateStateThumbnails(ThumbnailState.REMOVING,
function(thumbnail) {
this._setThumbnailState(thumbnail, ThumbnailState.ANIMATING_OUT);
Tweener.addTween(thumbnail,
{ slidePosition: 1,
time: SLIDE_ANIMATION_TIME,
transition: 'linear',
onComplete: function() {
this._setThumbnailState(thumbnail, ThumbnailState.ANIMATED_OUT);
this._queueUpdateStates();
},
onCompleteScope: this
});
});
// As long as things are sliding out, don't proceed
if (this._stateCounts[ThumbnailState.ANIMATING_OUT] > 0)
return;
// Once that's complete, we can start scaling to the new size and collapse any removed thumbnails
this._iterateStateThumbnails(ThumbnailState.ANIMATED_OUT,
function(thumbnail) {
this.actor.set_skip_paint(thumbnail.actor, true);
this._setThumbnailState(thumbnail, ThumbnailState.COLLAPSING);
Tweener.addTween(thumbnail,
{ collapseFraction: 1,
time: RESCALE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: function() {
this._stateCounts[thumbnail.state]--;
thumbnail.state = ThumbnailState.DESTROYED;
let index = this._thumbnails.indexOf(thumbnail);
this._thumbnails.splice(index, 1);
thumbnail.destroy();
this._queueUpdateStates();
},
onCompleteScope: this
});
});
if (this._pendingScaleUpdate) {
this._tweenScale();
this._pendingScaleUpdate = false;
}
// Wait until that's done
if (this._scale != this._targetScale || this._stateCounts[ThumbnailState.COLLAPSING] > 0)
return;
// And then slide in any new thumbnails
this._iterateStateThumbnails(ThumbnailState.NEW,
function(thumbnail) {
this._setThumbnailState(thumbnail, ThumbnailState.ANIMATING_IN);
Tweener.addTween(thumbnail,
{ slidePosition: 0,
time: SLIDE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: function() {
this._setThumbnailState(thumbnail, ThumbnailState.NORMAL);
},
onCompleteScope: this
});
});
},
_queueUpdateStates: function() {
if (this._stateUpdateQueued)
return;
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
Lang.bind(this, this._updateStates));
this._stateUpdateQueued = true;
},
_getPreferredHeight: function(actor, forWidth, alloc) {
// See comment about this._background in _init()
let themeNode = this._background.get_theme_node();
forWidth = themeNode.adjust_for_width(forWidth);
// Note that for getPreferredWidth/Height we cheat a bit and skip propagating
// the size request to our children because we know how big they are and know
// that the actors aren't depending on the virtual functions being called.
if (this._thumbnails.length == 0)
return;
let spacing = this.actor.get_theme_node().get_length('spacing');
let nWorkspaces = global.screen.n_workspaces;
let totalSpacing = (nWorkspaces - 1) * spacing;
[alloc.min_size, alloc.natural_size] =
themeNode.adjust_preferred_height(totalSpacing,
totalSpacing + nWorkspaces * this._porthole.height * MAX_THUMBNAIL_SCALE);
},
_getPreferredWidth: function(actor, forHeight, alloc) {
// See comment about this._background in _init()
let themeNode = this._background.get_theme_node();
if (this._thumbnails.length == 0)
return;
// We don't animate our preferred width, which is always reported according
// to the actual number of current workspaces, we just animate within that
let spacing = this.actor.get_theme_node().get_length('spacing');
let nWorkspaces = global.screen.n_workspaces;
let totalSpacing = (nWorkspaces - 1) * spacing;
let avail = forHeight - totalSpacing;
let scale = (avail / nWorkspaces) / this._porthole.height;
scale = Math.min(scale, MAX_THUMBNAIL_SCALE);
let width = Math.round(this._porthole.width * scale);
[alloc.min_size, alloc.natural_size] =
themeNode.adjust_preferred_width(width, width);
},
_allocate: function(actor, box, flags) {
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
// See comment about this._background in _init()
let themeNode = this._background.get_theme_node();
let contentBox = themeNode.get_content_box(box);
if (this._thumbnails.length == 0) // not visible
return;
let portholeWidth = this._porthole.width;
let portholeHeight = this._porthole.height;
let spacing = this.actor.get_theme_node().get_length('spacing');
// Compute the scale we'll need once everything is updated
let nWorkspaces = global.screen.n_workspaces;
let totalSpacing = (nWorkspaces - 1) * spacing;
let avail = (contentBox.y2 - contentBox.y1) - totalSpacing;
let newScale = (avail / nWorkspaces) / portholeHeight;
newScale = Math.min(newScale, MAX_THUMBNAIL_SCALE);
if (newScale != this._targetScale) {
if (this._targetScale > 0) {
// We don't do the tween immediately because we need to observe the ordering
// in queueUpdateStates - if workspaces have been removed we need to slide them
// out as the first thing.
this._targetScale = newScale;
this._pendingScaleUpdate = true;
} else {
this._targetScale = this._scale = newScale;
}
this._queueUpdateStates();
}
let thumbnailHeight = portholeHeight * this._scale;
let thumbnailWidth = Math.round(portholeWidth * this._scale);
let roundedHScale = thumbnailWidth / portholeWidth;
let slideOffset; // X offset when thumbnail is fully slid offscreen
if (rtl)
slideOffset = - (thumbnailWidth + themeNode.get_padding(St.Side.LEFT));
else
slideOffset = thumbnailWidth + themeNode.get_padding(St.Side.RIGHT);
let childBox = new Clutter.ActorBox();
// The background is horizontally restricted to correspond to the current thumbnail size
// but otherwise covers the entire allocation
if (rtl) {
childBox.x1 = box.x1;
childBox.x2 = box.x2 - ((contentBox.x2 - contentBox.x1) - thumbnailWidth);
} else {
childBox.x1 = box.x1 + ((contentBox.x2 - contentBox.x1) - thumbnailWidth);
childBox.x2 = box.x2;
}
childBox.y1 = box.y1;
childBox.y2 = box.y2;
this._background.allocate(childBox, flags);
let indicatorY = this._indicatorY;
// when not animating, the workspace position overrides this._indicatorY
let indicatorWorkspace = !this._animatingIndicator ? global.screen.get_active_workspace() : null;
let y = contentBox.y1;
for (let i = 0; i < this._thumbnails.length; i++) {
let thumbnail = this._thumbnails[i];
if (i > 0)
y += spacing - Math.round(thumbnail.collapseFraction * spacing);
// We might end up with thumbnailHeight being something like 99.33
// pixels. To make this work and not end up with a gap at the bottom,
// we need some thumbnails to be 99 pixels and some 100 pixels height;
// we compute an actual scale separately for each thumbnail.
let y1 = Math.round(y);
let y2 = Math.round(y + thumbnailHeight);
let roundedVScale = (y2 - y1) / portholeHeight;
let x1, x2;
if (rtl) {
x1 = contentBox.x1 + slideOffset * thumbnail.slidePosition;
x2 = x1 + thumbnailWidth;
} else {
x1 = contentBox.x2 - thumbnailWidth + slideOffset * thumbnail.slidePosition;
x2 = x1 + thumbnailWidth;
}
if (thumbnail.metaWorkspace == indicatorWorkspace)
indicatorY = y1;
// Allocating a scaled actor is funny - x1/y1 correspond to the origin
// of the actor, but x2/y2 are increased by the *unscaled* size.
childBox.x1 = x1;
childBox.x2 = x1 + portholeWidth;
childBox.y1 = y1;
childBox.y2 = y1 + portholeHeight;
thumbnail.actor.set_scale(roundedHScale, roundedVScale);
thumbnail.actor.allocate(childBox, flags);
// We round the collapsing portion so that we don't get thumbnails resizing
// during an animation due to differences in rounded, but leave the uncollapsed
// portion unrounded so that non-animating we end up with the right total
y += thumbnailHeight - Math.round(thumbnailHeight * thumbnail.collapseFraction);
}
if (rtl) {
childBox.x1 = contentBox.x1;
childBox.x2 = contentBox.x1 + thumbnailWidth;
} else {
childBox.x1 = contentBox.x2 - thumbnailWidth;
childBox.x2 = contentBox.x2;
}
childBox.y1 = indicatorY;
childBox.y2 = childBox.y1 + thumbnailHeight;
this._indicator.allocate(childBox, flags);
},
_activeWorkspaceChanged: function(wm, from, to, direction) {
let thumbnail;
let activeWorkspace = global.screen.get_active_workspace();
for (let i = 0; i < this._thumbnails.length; i++) {
if (this._thumbnails[i].metaWorkspace == activeWorkspace) {
thumbnail = this._thumbnails[i];
break;
}
}
this._animatingIndicator = true;
this.indicatorY = this._indicator.allocation.y1;
Tweener.addTween(this,
{ indicatorY: thumbnail.actor.allocation.y1,
time: WorkspacesView.WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad',
onComplete: function() {
this._animatingIndicator = false;
this._queueUpdateStates();
},
onCompleteScope: this
});
}
};

File diff suppressed because it is too large Load Diff

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

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

View File

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

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