Compare commits

...

126 Commits

Author SHA1 Message Date
3124e82838 search: make sure to pass a timestamp to LaunchSearch()
Do not repeat past mistakes while we're still in time.

https://bugzilla.gnome.org/show_bug.cgi?id=690009
2012-12-10 17:44:28 -05:00
6c4daaaa71 overview: streamline sides state change
Instead of dirty tricks like connecting to "notify::visible" on the dash
after we hide it, split the page-change signal into
before/after-page-change, and turn setSideControlsVisibility() into a
better state machine.
2012-12-10 15:51:02 -05:00
3768e85673 workspaceThumbnails: restore previous slide-out behavior
Start with the workspace selector half-visible, then slide it out either
on hover, when in drag, or when showing multiple workspaces/when using
an external monitor with windows on it.
2012-12-10 15:51:02 -05:00
d1c72e1e4c overview: also hide the messsage tray ghost when switching to search 2012-12-10 15:51:02 -05:00
2498497cc1 overview, viewSelector: show/hide workspaces on apps button 2012-12-10 15:51:02 -05:00
7c3c6da368 overview: Connect item-drag signals to show/hide overview elements
Anytime we begin dragging an app launcher, ensure the overview elements are
showing. While searching, if an item-drag ends or is cancelled, hide the
overview elements, but don't switch back to windows (which was the old
behavior).

https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:02 -05:00
09e7ab5611 overview: hide side controls when searching
Hide the elements when the search is active. Show them if the search
is cancelled.

https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:02 -05:00
53cff07eef messageTray: don't assume we're always visible in the overview
Since we'll hide the message tray when searching in a future commit.

https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:02 -05:00
cfed6e401d viewSelector: this.active --> this._searchActive
'active' isn't terribly clear about just what is active; also, make it
private, remove an useless extra object state we were saving, and
refactor some messy code.

https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:02 -05:00
12b041a569 dash: Add show/hide methods
https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:02 -05:00
f2dd94776c overview: Center the main overview group accordingly
Using the same logic as the panel which smartly centers everything,
smartly center the overview contents if we have enough space to do so.
2012-12-10 15:51:02 -05:00
c0f9c52ba6 panel: Abstract the centered panel logic out into a ClutterLayoutManager
Since we want to use this in the overview as well, put it into centerLayout.js
2012-12-10 15:51:02 -05:00
2ee8b0e427 workspaceThumbnail: Add keyboard nav to ThumbnailsBox
https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:02 -05:00
b250a72fcf overview, workspacesView: Use ThumbnailsBox for independent workspace thumbnails
Both WorkspacesDisplay and ThumbnailsBox need to know when windows have been
restacked. Instead of each tracking changes on their own or trying to call
each other, have the overview keep track and do the calculations, emitting
a signal with the result.

https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:01 -05:00
cf08745f6c workspaceThumbnail: Rename show(), hide() and add new methods
show() and hide() now slide the thumbnails in and out, respectively. The old
show and hide are now _createThumbnails and _destroyThumbnails. We only care
about these thumbnails while in the overview, so create them when entering and
destroy them on exit.

https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:01 -05:00
58023c81ad workspaceThumbnail: React to scroll event
https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:01 -05:00
7e8968da52 workspaceThumbnail: Make ThumbnailsBox track workspace changes itself
https://bugzilla.gnome.org/show_bug.cgi?id=682050
2012-12-10 15:51:01 -05:00
fce1d8157e overview: overview as boxlayouts
https://bugzilla.gnome.org/show_bug.cgi?id=682286
2012-12-10 15:51:00 -05:00
3b5de01ed6 search: remove more dead code
https://bugzilla.gnome.org/show_bug.cgi?id=681797
2012-12-10 15:49:04 -05:00
a61da42aa7 search: remove SearchProvider base class
This is causing more confusion than anything else these days; the DBus
API is properly documented now and that's what people are expected to
use, the rest are implementation details we're not interested in
exposing.

https://bugzilla.gnome.org/show_bug.cgi?id=681797
2012-12-10 15:49:04 -05:00
81acfdbfc3 search: remove SearchResultDisplay base class
It's unused, and the clear() method is just wrong. Remove it.

https://bugzilla.gnome.org/show_bug.cgi?id=681797
2012-12-10 15:49:04 -05:00
159b789443 appDisplay: Don't use icons in results for settings
The search results are not necessarily improved by including icons, so don't.

https://bugzilla.gnome.org/show_bug.cgi?id=681797
2012-12-10 15:49:04 -05:00
c07b715a3a remoteSearch: We do not need a fallback for createIcon
Remote providers no longer have access to a grid layout, where an icon is
a requirement. If they don't specify an icon, don't create one.

https://bugzilla.gnome.org/show_bug.cgi?id=681797
2012-12-10 15:49:04 -05:00
1bb09fd0f1 searchDisplay: Add ListSearchResult and ListSearchResults
These are for all search results except apps (and Wanda).
We also simplify a bit the packing of search results, which removes some
ugly code in navigateFocus() where we needed to call
st_widget_navigate_focus() twice, since the grid icon was composed by
two nested boxes, both focusable.

https://bugzilla.gnome.org/show_bug.cgi?id=681797
2012-12-10 15:49:04 -05:00
4441541da6 searchDisplay: simplify drag actor source code
Make sure this._dragActorSource is always set from _init() to siplify
code.

https://bugzilla.gnome.org/show_bug.cgi?id=681797
2012-12-10 15:49:04 -05:00
afee4d6925 popupMenu: Break separator drawing code out of PopupSeparatorMenuItem
And into a separate HorizontalSeparatorClass.

https://bugzilla.gnome.org/show_bug.cgi?id=681797
2012-12-10 15:49:04 -05:00
b62bd0e62f searchDisplay, and others: Switch from provider title to provider icon
Display a '+' icon on the provider icon if there are more results that are
hidden. If the provider icon is clicked, ask the provider to launch itself and
perform a search with the current terms.

https://bugzilla.gnome.org/show_bug.cgi?id=681797
2012-12-10 15:49:04 -05:00
13b83c95b7 build: Remove Makefile-gvc.am
This is now unused, and potentially confusing.

https://bugzilla.gnome.org/show_bug.cgi?id=689955
2012-12-10 14:38:07 -05:00
e48dbe65f1 overview: Clean up overview code
The comment here is a liar. We certainly can handle failure
using _syncInputMode().

https://bugzilla.gnome.org/show_bug.cgi?id=688589
2012-12-10 14:38:07 -05:00
14fb51e6d7 overview: Fix stuck grabs when mashing the overlay-key
When pressing the overlay key three times, things went like this:

  * show(), push a modal
  * hide(), will pop a modal after hiding is done
  * show(), push a modal

Thus, when the showing is done, and then it activated the hiding,
it popped one modal, but not the other. This patch changes things
to be:

  * show(), push a modal
  * hide(), will pop a modal after hiding is done
  * hide(), no-op

That is, mashing the overlay-key when it's showing will always make
it hide, not mashing an odd number of times.

https://bugzilla.gnome.org/show_bug.cgi?id=688589
2012-12-10 14:38:07 -05:00
b42af9aa99 popupMenu: Don't slide menus when we're changing them
As calling close() will drop the grab, we were inadverdently
re-closing menus, causing them to re-animate with a full animation.

https://bugzilla.gnome.org/show_bug.cgi?id=689954
2012-12-10 14:38:07 -05:00
ca2ee22827 popupMenu: Display the proper animations for popup menus
BoxPointer's API changed to take a BoxPointer.PopupAnimation
enumeration value, but the code was accidentally replaced with
older code when porting the PopupMenuManager code to GrabHelper.

https://bugzilla.gnome.org/show_bug.cgi?id=689954
2012-12-10 14:38:07 -05:00
13a2b28bf1 popupMenu: Complete the dummy fake menu
"toggle" is used when clicking on the source actor. As we don't
actually have a menu, we don't want to actually take any grabs
through the menu system, so make it a no-op rather than have it
toggle the menu state.

https://bugzilla.gnome.org/show_bug.cgi?id=689954
2012-12-10 14:38:06 -05:00
04bf75d137 panel: Remove a dead check
With the dummy menu item now in place, we will always have a menu.

https://bugzilla.gnome.org/show_bug.cgi?id=689954
2012-12-10 14:38:06 -05:00
76c589702f Assamese translation updated 2012-12-10 18:24:06 +05:30
c11f89e72a messageTray: Don't add ourselves more than once to CtrlAltTabManager
This way _sessionUpdated() can be called multiple times without side
effects.

https://bugzilla.gnome.org/show_bug.cgi?id=689959
2012-12-10 11:50:05 +01:00
cfacb05461 gnome-shell-jhbuild: Allow passing args to gnome-shell
$ ./gnome-shell -- --list-modes

https://bugzilla.gnome.org/show_bug.cgi?id=689778
2012-12-09 18:30:46 -05:00
c4ba31cb23 Updated POTFILES.in
Yes, it has to be there. Run:

git submodule init && git submodule update

to make it work.
2012-12-09 19:13:01 +01:00
db0eacddc5 Updated Norwegian bokmål translation 2012-12-09 14:02:59 +01:00
62972f5138 Update Arabic translation 2012-12-09 04:53:24 +02:00
6fe263f19f Drop removed file 2012-12-09 04:46:09 +02:00
b6a87acb71 gvc: Update git submodule
This fixes the build.
2012-12-08 13:38:43 -05:00
784b04b191 VolumeMenu: show headphone icon when headphones are plugged in
This will show the user where sound will come out, and should
help if he forgets them plugged, or forgets to plug them before
playing music.

https://bugzilla.gnome.org/show_bug.cgi?id=675902
2012-12-08 15:54:05 +01:00
3af9f636af Use libgnome-volume-control from a submodule
To be shared with gnome-control-center and gnome-settings-daemon
2012-12-08 15:53:46 +01:00
16c0585b95 fileUtils: correctly determine file type for symbolic links
Extensions in a folder that is a symbolic link do not get loaded,
since the returned file type is unknown.

https://bugzilla.gnome.org/show_bug.cgi?id=689868
2012-12-08 02:53:21 -05:00
fc9a96ac85 popupMenu: Introduce PopupDummyMenu
This is designed for things like the activities button that sort of
need a menu to make navigation work, but not really have it do anything.

https://bugzilla.gnome.org/show_bug.cgi?id=689109
2012-12-07 19:55:28 -05:00
9dfc3af9d7 popupMenu: Port to GrabHelper
https://bugzilla.gnome.org/show_bug.cgi?id=689109
2012-12-07 19:55:28 -05:00
8dc63932fc grabHelper: Fix up event handling for ignoring releases
We need to return 'true' to signify that we handled the event.

https://bugzilla.gnome.org/show_bug.cgi?id=689109
2012-12-07 19:55:23 -05:00
066e5cddb5 grabHelper: Drop to the actor clicked on
This is necessary for child popups in menus, e.g. while in a combo box,
clicking outside of the user menu should drop the entire menu, but
clicking on the user menu itself should only drop the combo box.

https://bugzilla.gnome.org/show_bug.cgi?id=689109
2012-12-07 19:54:46 -05:00
27ffad2148 grabHelper: Treat the current grabbed actor as a grabbed actor
This should be obvious, but I guess it wasn't necessary for the
message tray case.

https://bugzilla.gnome.org/show_bug.cgi?id=689109
2012-12-07 19:53:47 -05:00
41db363b06 grabHelper: Use captured-event for escape ungrabs
I have no idea why we used 'event' rather than 'captured-event' before.
'event' has some really strange quirks that came up when porting PopupMenu
to the GrabHelper

https://bugzilla.gnome.org/show_bug.cgi?id=689109
2012-12-07 19:53:46 -05:00
184ac11c93 ctrlAltTab: Remove leftover
Accidentally forgot to remove this before pushing.
2012-12-07 13:02:57 -05:00
673aa3c5f2 Updated Kannada Translations 2012-12-07 16:12:16 +05:30
2dd1c04bf3 Updated Kannada Translations 2012-12-07 15:37:39 +05:30
4df1222ce7 screen-shield: disconnect from title-changed on destroy
https://bugzilla.gnome.org/show_bug.cgi?id=689820
2012-12-06 19:07:27 -05:00
208121646c St: recompute all theme nodes when the icon theme changes
StWidget considers "same theme node" as an indication that the style
did not change, and skips emitting style-changed in that case. This
means that icon theme changes are not picked up by StIcon.

https://bugzilla.gnome.org/show_bug.cgi?id=689353
2012-12-06 17:42:07 -05:00
f47a11f792 Updated POTFILES.in 2012-12-06 22:37:41 +01:00
36fc3a5c96 st: fix rendering of corners in the box-shadow
https://bugzilla.gnome.org/show_bug.cgi?id=689789
2012-12-06 18:42:37 +00:00
ed12c9d611 fileUtils: Don't fail if we can't find an error
We need to make sure that we decrement the number of dirs that
we've loaded, and call the callback on error.

https://bugzilla.gnome.org/show_bug.cgi?id=689749
2012-12-06 13:32:12 -05:00
4153feeb15 grabHelper: Use focus_default_window
This prevents us from having to track the previously focused window.

https://bugzilla.gnome.org/show_bug.cgi?id=689653
2012-12-06 12:25:37 -05:00
349c642d10 ctrlAltTab: Add a "Windows" option to Ctrl+Alt+Tab
This lets accessibility users easily access the desktop after focusing the panel.

https://bugzilla.gnome.org/show_bug.cgi?id=689653
2012-12-06 12:25:37 -05:00
4728105f43 ctrlAltTab: Only add to the focus manager if we have an StWidget.
https://bugzilla.gnome.org/show_bug.cgi?id=689653
2012-12-06 12:25:37 -05:00
1f46a0dc26 ctrlAltTab: Remove some dead code for a "window" parameter
This isn't set on any item, so we can safely remove it.

https://bugzilla.gnome.org/show_bug.cgi?id=689653
2012-12-06 12:25:37 -05:00
7ff7ced504 switcherPopup: Add a timestamp argument to _finish()
And use it elsewhere.

https://bugzilla.gnome.org/show_bug.cgi?id=689653
2012-12-06 12:25:37 -05:00
a43ee41b0b app-display: use a GAppInfo for the settings provider
this._gnomecc is currently unused; we actually need a GAppInfo for this
provider if we want to display an icon next to it (see future commits),
so just turn it into one.
We might move this to an external provider altogether in the future.

https://bugzilla.gnome.org/show_bug.cgi?id=689735
2012-12-06 12:15:13 -05:00
ec7ade4ee6 remote-search: implement new ActivateResult() method
This allows us to fix the shortcomings of the original ActivateResult()
method. In particular:
- allow to pass the search terms to the provider
- allow to pass a user interaction timestamp

https://bugzilla.gnome.org/show_bug.cgi?id=689735
2012-12-06 12:15:13 -05:00
9b846cbb83 search: remove additional params from activateResult() call
The only case when we're interested in using those parameters nowadays
is for DnD, which is handled in a separate method already.
Since we're not going to support DnD for non-app search results anyway,
drop the params from all the activateResults() calls; this will be
useful later since we're going to add another parameter to it.

https://bugzilla.gnome.org/show_bug.cgi?id=689735
2012-12-06 12:15:13 -05:00
2cc7fd07f8 remote-search: implement LaunchSearch() DBus method
This will be used to launch a search in the application itself.

https://bugzilla.gnome.org/show_bug.cgi?id=689735
2012-12-06 12:15:13 -05:00
72d54d9915 remote-search: first implementation of SearchProvider2
We read the implemented version from the search provider's keyfile, and
then create a RemoteSearchProvider object from the right class
accordingly.
Wire ActivateResult() to the new method (without actually passing the
new parameters along) - an actual implementation will be added in a
future commit.

https://bugzilla.gnome.org/show_bug.cgi?id=689735
2012-12-06 12:15:12 -05:00
b390b82e9d remote-search: add an org.gnome.ShellSearchProvider2 dbus interface
We are going to change the interface, so add a new version of it.
Providers will need to opt-in to the new API.
A summary of the differences compared to the previous API:
- ActivateResult() now also takes the search terms and a timestamp as
  parameters
- a new LaunchSearch() method is added

https://bugzilla.gnome.org/show_bug.cgi?id=689735
2012-12-06 12:13:24 -05:00
1ef9ee13a3 remote-search: properly document the DBus interface
Use real annotations in the XML, and use gdbus-codegen to extract those
into docbook. We then include it in the Shell's gtk-doc.

https://bugzilla.gnome.org/show_bug.cgi?id=689735
2012-12-06 12:13:24 -05:00
6822795bb8 build: Fix distcheck 2012-12-05 23:35:35 +01:00
187dec2816 sessionMode: Add support for 'parentMode' property
Defining a mode that differs significantly from the default one
can get rather cumbersome. For convenience, allow mode definitions
to inherit from an existing mode.

https://bugzilla.gnome.org/show_bug.cgi?id=689308
2012-12-05 21:56:57 +01:00
31f75e4607 extensionSystem: Add support for mode-specific extensions
As currently envisioned, the fallback replacement in 3.8 should be
a separate session at the login screen. As we will use extensions
to implement this mode, we need a way to specify extensions per
session rather than per user, so add a session-mode property for
extensions that should be loaded in addition to the user-defined
ones.

https://bugzilla.gnome.org/show_bug.cgi?id=689305
2012-12-05 21:56:57 +01:00
92083eaf76 sessionMode: Make loading of external modes asynchronous
Blocking IO on startup is bad m'kay ...

https://bugzilla.gnome.org/show_bug.cgi?id=689304
2012-12-05 21:56:57 +01:00
6b40c3974d extensionUtils: Load extensions asynchronously
Use the new collectFromDatadirsAsync() function for extension
loading as well.

https://bugzilla.gnome.org/show_bug.cgi?id=689304
2012-12-05 21:56:21 +01:00
c528401b62 remoteSearch: Factor out collectFromDatadirsAsync() utility function
Processing files from a subdirectory of various share/gnome-shell
directories asynchronously is a common enough pattern to share
the common code.

https://bugzilla.gnome.org/show_bug.cgi?id=689304
2012-12-05 21:56:20 +01:00
8a17f512f4 sessionMode: Add support for external mode definitions
Currently adding a new session mode requires patching the sources.
As defining custom modes can be desirable in some circumstances
(for instance for administrators of kiosk setups), load additional
modes from JSON files.

https://bugzilla.gnome.org/show_bug.cgi?id=689304
2012-12-05 21:56:17 +01:00
e725f8a0fe altTab: Re-implement 'switch-windows' keybinding
Now that we use the new 'switch-applications' keybinding for the
application-based alt-tab popup, we can use the 'switch-windows'
keybinding for a more traditional switcher.

Based heavily on the alternate-tab extension from Giovanni Campagna.

https://bugzilla.gnome.org/show_bug.cgi?id=688913
2012-12-05 18:42:08 +01:00
525d3c2619 altTab: Factor out thumbnail creation
https://bugzilla.gnome.org/show_bug.cgi?id=688913
2012-12-05 18:42:08 +01:00
aba46720c0 altTab: Rename AltTabPopup to AppSwitcherPopup
We will add support for a window-based popup in addition to the
current application-based one, so use a more descriptive name.

https://bugzilla.gnome.org/show_bug.cgi?id=688913
2012-12-05 18:42:08 +01:00
2fb1d707fe altTab: Use 'switch-applications' for app switcher
The Shell's alt-tab popup is application-based, so using the
'switch-windows' keybinding for it never really made sense.
Use the newly added 'switch-applications' keybinding instead.

https://bugzilla.gnome.org/show_bug.cgi?id=688913
2012-12-05 18:42:07 +01:00
dd06aa98ad gnome-shell.doap: belatedly remove me as a maintainer 2012-12-05 07:48:55 -05:00
cfb66ca153 update Punjabi Translation for master 2012-12-05 07:40:56 +05:30
0b4660702b switcherPopup: Add missing Meta declaration
This is used in the edge case if we fail a pointer grab.
2012-12-04 13:18:51 -05:00
9760227c66 Assamese translation updated 2012-12-04 15:55:17 +05:30
5faeaa2028 AppSwitcher: Remove a lost timeout on destroy
Doesn't look harmful but there's no point in running this code after
we're destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=689528
2012-12-04 10:06:37 +01:00
cd58f9f9e5 windowManager: Make use of the switch-panels-backward keybinding
We have it in the schema so there's no reason for it not to work.

https://bugzilla.gnome.org/show_bug.cgi?id=689528
2012-12-04 10:06:37 +01:00
00338bbc4b switcherPopup: Factor out altTab and ctrlAltTab's common code
https://bugzilla.gnome.org/show_bug.cgi?id=689528
2012-12-04 10:06:37 +01:00
31d14a2fb0 panel: Update the hot corner when the panel box allocation changes
This fixes the missing hotcorner in the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=689537
2012-12-03 16:09:46 -05:00
49fa0ddebc layout: Use translation_y for panel animation
The anchor point is deprecated.

https://bugzilla.gnome.org/show_bug.cgi?id=689537
2012-12-03 16:06:34 -05:00
d50c3e6c67 panel: Don't create a menu for the ActivitiesButton
A "dontCreateMenu" item was created for the lock screen; we should
just use that instead of having a hacked up menu.

https://bugzilla.gnome.org/show_bug.cgi?id=689537
2012-12-03 16:06:34 -05:00
b39f56e813 messageTray: Remove an unused instance variable 2012-12-03 16:06:34 -05:00
ead0286ca6 st-private: Don't round-trip through a font-string
ClutterText can support a PangoFontDescription directly.

https://bugzilla.gnome.org/show_bug.cgi?id=689568
2012-12-03 15:56:59 -05:00
6eb05af306 workspacesView: Restore activation of (empty) workspaces
Clicking empty workspaces to leave the overview was broken by
commit 830e701d13, restore the previous behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=689552
2012-12-03 19:40:29 +01:00
6b1e632621 NetworkMenu: don't notify for failed connections if cancelled by the user
If the user cancels the secret dialog, the NM will report the connection
failure, but we should not notify it as it is a user-initiated action.

https://bugzilla.gnome.org/show_bug.cgi?id=684823
2012-12-03 19:02:16 +01:00
29cb10fed8 iconGrid: Handle preferred height requests for infinite widths
Request enough height to fit all children in a single line instead of
requesting 0.

https://bugzilla.gnome.org/show_bug.cgi?id=679168
2012-12-03 12:43:46 -05:00
a88433dba6 st-private: Fix style 2012-12-02 20:11:36 -05:00
7e5f1fe411 st-private: Don't create attr lists if we don't need them
Decorations are fairly uncommon in gnome-shell, so it's
worthwhile to avoid effort creating empty attr lists. This
can also help prevent a relayout.

https://bugzilla.gnome.org/show_bug.cgi?id=689400
2012-12-02 20:11:10 -05:00
00c78d33e4 MessageTray, ScreenShield: adjust missed message counter
Fix counter size and position and add some padding in
ScreenShield notifications to not obscure the items below
the missed message counter.

https://bugzilla.gnome.org/show_bug.cgi?id=686472
2012-12-02 23:20:10 +01:00
50fbf9982e MessageTray: clean-up chat timestamps
Change the text for design reasons and correct some English issues
in the timestamp string.

https://bugzilla.gnome.org/show_bug.cgi?id=680989
2012-12-02 23:12:28 +01:00
71ad39b6e3 Add a setting for the default state of 'Remember Password'
https://bugzilla.gnome.org/show_bug.cgi?id=688039
2012-12-02 23:01:56 +01:00
3d329cdf2d Updated Tamil translation 2012-12-02 17:10:13 +05:30
21af5c8f73 Added Norwegian bokmål translation 2012-12-01 11:33:46 +01:00
716d7bb93e shell-app-usage: Fix several problems in xml parsing
Coverity rightly complained about the context < 0 comparison.
In addition, context was shadowing the parameter of the same
name, and the loops over the attributes were unnecessarily
running all the way.

https://bugzilla.gnome.org/show_bug.cgi?id=689325
2012-11-30 20:16:50 -05:00
98f4b99446 overview: Remove custom swipe scrolling implementation
https://bugzilla.gnome.org/show_bug.cgi?id=689062
2012-11-30 16:03:35 -05:00
830e701d13 workspacesView: Don't use the overview swipe scrolling system
Switch to a ClutterPanAction instead too.

https://bugzilla.gnome.org/show_bug.cgi?id=689062
2012-11-30 16:03:34 -05:00
57d9e7d5aa workspacesView: Clean up scroll code a bit
There's no code path that results in us not animating.

https://bugzilla.gnome.org/show_bug.cgi?id=689062
2012-11-30 16:03:34 -05:00
5fc16bb05b searchDisplay, appDisplay: Use ClutterPanAction for re-swipe scrolling
The sooner we can kill off the custom overview swipe scroll code, the
better.

https://bugzilla.gnome.org/show_bug.cgi?id=689062
2012-11-30 16:03:34 -05:00
cb08bd2e2e altTab: Minor code cleanup
https://bugzilla.gnome.org/show_bug.cgi?id=688913
2012-11-30 20:04:22 +01:00
961dba7faa MessageTray: don't close the tray when interacting with the right click menu
If the chosen action is not open, the tray should not be closed, to
let the user further interact with it (for example to mute or remove
more sources)

https://bugzilla.gnome.org/show_bug.cgi?id=689296
2012-11-30 18:43:57 +01:00
41f933b89e MessageTray: fix notification height expansion
MessageTray._tween removes all tweens now, so it removes also
those setting the height to expanded for critical notifications.

This is a regression from 1a27d7dfc0

https://bugzilla.gnome.org/show_bug.cgi?id=689295
2012-11-30 18:42:18 +01:00
d4dc1c87c5 dbus: Add a read-only org.gnome.Shell.Mode property
This is meant to expose the global.session_mode to applications such
as the gnome-tweak-tool, which would need it to differentiate between
the vanilla GNOME Shell mode and the fallback replacement mode.

https://bugzilla.gnome.org/show_bug.cgi?id=689300
2012-11-30 17:28:34 +01:00
e58fbeea17 appDisplay: don't increment counter if we didn't add a category
Or we'll later try to jump to the wrong category when clicking on it.
2012-11-29 19:21:41 -05:00
2492dc50db scroll-bar: Remove jitter on the scroll bar when moving the mouse
This was due to incorrect pixel clamping, which bounced the height
of the actor between values. Just remove pixel clamping, as Clutter
will correctly do it for us.

https://bugzilla.gnome.org/show_bug.cgi?id=689243
2012-11-29 16:43:47 -05:00
b4f5f1e461 scroll-view-fade: Fade gradients when near edges
Rather than sharply transitioning to gradients, fade them out when
near the edge of the scroll view.

https://bugzilla.gnome.org/show_bug.cgi?id=689249
2012-11-29 16:17:09 -05:00
69347fff09 scroll-view-fade: Only calculate the ratios if they're needed
This prevents some calculations being done for poor drivers with
bad optimizers.

https://bugzilla.gnome.org/show_bug.cgi?id=689249
2012-11-29 16:17:09 -05:00
5c439f4e9c scroll-view-fade: Do the offset math in the shader
This doesn't (or shouldn't) change the visual appearance of the fade
effect, but does do all the testing math inside the shader, rather
than on the CPU. This will make fading the offset much easier in
the future.

https://bugzilla.gnome.org/show_bug.cgi?id=689249
2012-11-29 16:17:09 -05:00
c84236ed73 scroll-view-fade: Use GLSL 1.20
GLSL 1.20 is a better language, and we'll rely on it in future updates.
This doesn't have any additional constraints, since GLSL 1.20 was
standardized before GLSL-supporting drivers came out.

https://bugzilla.gnome.org/show_bug.cgi?id=689249
2012-11-29 16:17:09 -05:00
ae1a3a0cb2 scroll-view-fade: Clean up GLSL
Basic cleanup of what we're doing already. This moves a bunch
of the "inside the fade area" checks to the top, before doing
any calculations.

https://bugzilla.gnome.org/show_bug.cgi?id=689249
2012-11-29 16:17:09 -05:00
b3fea016f1 scroll-view-fade: Put the shader in another file
This doesn't make any changes to the shader outside of adding
a header; it simply makes changes in the future easier to edit.

https://bugzilla.gnome.org/show_bug.cgi?id=689249
2012-11-29 16:17:09 -05:00
7c93639e59 scroll-view-sizing: Enable vfade by default
https://bugzilla.gnome.org/show_bug.cgi?id=689249
2012-11-29 16:17:09 -05:00
affcd5c7de scroll-view-sizing: Add a lot more boxes
https://bugzilla.gnome.org/show_bug.cgi?id=689249
2012-11-29 16:17:08 -05:00
e00eb06f66 overview: Handle sessionMode.hasOverview changes
Currently we assume that either the initial sessionMode will have
the overview or none of the pushed modes - starting without the
overview and pushing a mode that adds it fails spectacularly.
However this is exactly what we are going to do when loading external
modes asynchronously - we'll initially use the default mode while
the modes are loading, and switch to the mode passed on the command
line when finished. So make sure that the overview UI gets initialized
properly in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=689304
2012-11-29 21:31:06 +01:00
5ecc204d57 main: Fix signal name
It's SessionMode::updated, not SessionMode::update ...
2012-11-29 21:26:45 +01:00
2a5eed1eb4 viewSelector: Ignore key-presses during non-overview modals
Since commit 0c807bddaf, the run dialog no longer handles Escape
key presses itself but uses the action key mechanism of modal dialogs.
As the latter uses key-release events, our own handling of the Escape
key runs on key-press.
Fix this by bailing out early if anything has pushed a modal in addition
to the overview (like system modals, looking glass, ...).

https://bugzilla.gnome.org/show_bug.cgi?id=688196
2012-11-28 21:15:09 +01:00
94 changed files with 5227 additions and 10052 deletions

3
.gitignore vendored
View File

@ -38,6 +38,7 @@ docs/reference/*/*.txt
docs/reference/*/*.types
docs/reference/*/html/
docs/reference/*/xml/
docs/reference/shell/doc-gen-*
gtk-doc.make
js/misc/config.js
intltool-extract.in
@ -85,6 +86,8 @@ src/test-theme
src/st.h
src/stamp-st.h
src/stamp-st.h.tmp
src/st-scroll-view-fade-generated.c
src/stamp-st-scroll-view-fade-generated.c
stamp-h1
tests/run-test.sh
xmldocs.make

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "src/gvc"]
path = src/gvc
url = git://git.gnome.org/libgnome-volume-control

View File

@ -13,6 +13,14 @@ PKG_NAME="gnome-shell"
exit 1
}
# Fetch submodules if needed
if test ! -f src/gvc/Makefile.am;
then
echo "+ Setting up submodules"
git submodule init
fi
git submodule update
which gnome-autogen.sh || {
echo "You need to install gnome-common from GNOME Git (or from"
echo "your OS vendor's package manager)."

View File

@ -269,6 +269,7 @@ AC_CONFIG_FILES([
js/Makefile
src/calendar-server/evolution-calendar.desktop.in
src/Makefile
src/gvc/Makefile
browser-plugin/Makefile
tests/Makefile
po/Makefile.in

View File

@ -11,7 +11,9 @@ desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
@INTLTOOL_DESKTOP_RULE@
introspectiondir = $(datadir)/dbus-1/interfaces
introspection_DATA = org.gnome.ShellSearchProvider.xml
introspection_DATA = \
org.gnome.ShellSearchProvider.xml \
org.gnome.ShellSearchProvider2.xml
themedir = $(pkgdatadir)/theme
dist_theme_DATA = \
@ -32,6 +34,7 @@ dist_theme_DATA = \
theme/gnome-shell.css \
theme/logged-in-indicator.svg \
theme/message-tray-background.png \
theme/more-results.svg \
theme/noise-texture.png \
theme/panel-button-border.svg \
theme/panel-button-highlight-narrow.svg \

View File

@ -2,146 +2,72 @@
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
<node>
<!--
org.gnome.Shell.SearchProvider:
@short_description: Search provider interface
The interface used for integrating into GNOME Shell's search
interface. This interface is deprecated, and org.gnome.Shell.SearchProvider2 should be used instead.
-->
<interface name="org.gnome.Shell.SearchProvider">
<doc:doc>
<doc:description>
<doc:para>
The interface used for integrating into GNOME Shell's search
interface.
</doc:para>
</doc:description>
</doc:doc>
<!--
GetInitialResultSet:
@terms: Array of search terms, which the provider should treat as logical AND.
@results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
Called when the user first begins a search.
-->
<method name="GetInitialResultSet">
<doc:doc>
<doc:description>
<doc:para>
Called when the user first begins a search.
</doc:para>
</doc:description>
</doc:doc>
<arg type="as" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
Array of search terms, which the provider should treat as
logical AND.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="as" direction="out">
<doc:doc>
<doc:summary>
<doc:para>
An array of result identifier strings representing items which
match the given search terms. Identifiers must be unique within
the provider's domain, but other than that may be chosen freely
by the provider.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
</method>
<!--
GetSubsearchResultSet:
@previous_results: Array of results previously returned by GetInitialResultSet().
@terms: Array of updated search terms, which the provider should treat as logical AND.
@results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
Called when a search is performed which is a "subsearch" of
the previous search, e.g. the method may return less results, but
not more or different results.
This allows search providers to only search through the previous
result set, rather than possibly performing a full re-query.
-->
<method name="GetSubsearchResultSet">
<doc:doc>
<doc:description>
<doc:para>
Called when a search is performed which is a "subsearch" of
the previous search, e.g. the method may return less results, but
not more or different results.
This allows search providers to only search through the previous
result set, rather than possibly performing a full re-query.
</doc:para>
</doc:description>
</doc:doc>
<arg type="as" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
Array of item identifiers
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="as" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
Array of updated search terms, which the provider should treat as
logical AND.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="as" direction="out">
<doc:doc>
<doc:summary>
<doc:para>
An array of result identifier strings representing items which
match the given search terms. Identifiers must be unique within
the provider's domain, but other than that may be chosen freely
by the provider.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="as" name="previous_results" direction="in" />
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
</method>
<!--
GetResultMetas:
@identifiers: An array of result identifiers as returned by GetInitialResultSet() or GetSubsearchResultSet()
@metas: A dictionary describing the given search result, containing 'id' and 'name' (both strings). Optionally, either 'gicon' (a serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) can be specified if the result can be better served with a thumbnail of the content (such as with images).
Return an array of meta data used to display each given result
-->
<method name="GetResultMetas">
<doc:doc>
<doc:description>
<doc:para>
Return an array of meta data used to display each given result
</doc:para>
</doc:description>
</doc:doc>
<arg type="as" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
An array of result identifiers as returned by
GetInitialResultSet() or GetSubsearchResultSet()
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="aa{sv}" direction="out">
<doc:doc>
<doc:summary>
<doc:para>
A dictionary describing the given search result, containing
'id', 'name' (both strings) and either 'icon' (a serialized
GIcon) or 'icon-data' (raw image data as (iiibiiay) - width,
height, rowstride, has-alpha, bits per sample, channels, data)
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="as" name="identifiers" direction="in" />
<arg type="aa{sv}" name="metas" direction="out" />
</method>
<!--
ActivateResult:
@identifier: A result identifier as returned by GetInitialResultSet() or GetSubsearchResultSet()
Called when the users chooses a given result. The result should
be displayed in the application associated with the corresponding
provider.
This method is deprecated, and providers should implement ActivateResult2()
instead.
-->
<method name="ActivateResult">
<doc:doc>
<doc:description>
<doc:para>
Called when the users chooses a given result. The result should
be displayed in the application associated with the corresponding
provider.
</doc:para>
</doc:description>
</doc:doc>
<arg type="s" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
A result identifier as returned by GetInitialResultSet() or
GetSubsearchResultSet()
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="s" name="identifier" direction="in" />
</method>
</interface>
</node>

View File

@ -0,0 +1,87 @@
<!DOCTYPE node PUBLIC
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
<node>
<!--
org.gnome.Shell.SearchProvider2:
@short_description: Search provider interface
The interface used for integrating into GNOME Shell's search
interface (version 2).
-->
<interface name="org.gnome.Shell.SearchProvider2">
<!--
GetInitialResultSet:
@terms: Array of search terms, which the provider should treat as logical AND.
@results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
Called when the user first begins a search.
-->
<method name="GetInitialResultSet">
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
</method>
<!--
GetSubsearchResultSet:
@previous_results: Array of results previously returned by GetInitialResultSet().
@terms: Array of updated search terms, which the provider should treat as logical AND.
@results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
Called when a search is performed which is a "subsearch" of
the previous search, e.g. the method may return less results, but
not more or different results.
This allows search providers to only search through the previous
result set, rather than possibly performing a full re-query.
-->
<method name="GetSubsearchResultSet">
<arg type="as" name="previous_results" direction="in" />
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
</method>
<!--
GetResultMetas:
@identifiers: An array of result identifiers as returned by GetInitialResultSet() or GetSubsearchResultSet()
@metas: A dictionary describing the given search result, containing 'id' and 'name' (both strings). Optionally, either 'gicon' (a serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) can be specified if the result can be better served with a thumbnail of the content (such as with images). A 'description' field (string) may also be specified if more context would help the user find the desired result.
Return an array of meta data used to display each given result
-->
<method name="GetResultMetas">
<arg type="as" name="identifiers" direction="in" />
<arg type="aa{sv}" name="metas" direction="out" />
</method>
<!--
ActivateResult:
@identifier: A result identifier as returned by GetInitialResultSet() or GetSubsearchResultSet()
@terms: Array of search terms, which the provider should treat as logical AND.
@timestamp: A timestamp of the user interaction that triggered this call
Called when the users chooses a given result. The result should
be displayed in the application associated with the corresponding
provider. The provided search terms can be used to allow launching a full search in
the application.
-->
<method name="ActivateResult">
<arg type="s" name="identifier" direction="in" />
<arg type="as" name="terms" direction="in" />
<arg type="u" name="timestamp" direction="in" />
</method>
<!--
LaunchSearch:
@terms: Array of search terms, which the provider should treat as logical AND.
@timestamp: A timestamp of the user interaction that triggered this call
Asks the search provider to launch a full search in the application for the provided terms.
-->
<method name="LaunchSearch">
<arg type="as" name="terms" direction="in" />
<arg type="u" name="timestamp" direction="in" />
</method>
</interface>
</node>

View File

@ -70,6 +70,16 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
<_summary>Show full name in the user menu</_summary>
<_description>Whether the users full name is shown in the user menu or not.</_description>
</key>
<key name="remember-mount-password" type="b">
<default>false</default>
<_summary>Whether to remember password for mounting encrypted or remote filesystems</_summary>
<_description>
The shell will request a password when an encrypted device or a
remote filesystem is mounted. If the password can be saved for
future use a 'Remember Password' checkbox will be present.
This key sets the default state of the checkbox.
</_description>
</key>
<child name="calendar" schema="org.gnome.shell.calendar"/>
<child name="recorder" schema="org.gnome.shell.recorder"/>
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
@ -176,6 +186,33 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
</key>
</schema>
<enum id="org.gnome.shell.window-switcher.AppIconMode">
<value value="1" nick="thumbnail-only"/>
<value value="2" nick="app-icon-only"/>
<value value="3" nick="both"/>
</enum>
<schema id="org.gnome.shell.window-switcher"
path="/org/gnome/shell/window-switcher/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="app-icon-mode" enum="org.gnome.shell.window-switcher.AppIconMode">
<default>'both'</default>
<_summary>The application icon mode.</_summary>
<_description>
Configures how the windows are shown in the switcher. Valid possibilities
are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-only'
(shows only the application icon) or 'both'.
</_description>
</key>
<key type="b" name="current-workspace-only">
<default>false</default>
<summary>Limit switcher to current workspace.</summary>
<description>
If true, only windows from the current workspace are shown in the switcher.
Otherwise, all windows are included.
</description>
</key>
</schema>
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="attach-modal-dialogs" type="b">

View File

@ -49,7 +49,7 @@ stage {
.switcher-list,
.app-well-app > .overview-icon,
.show-apps > .overview-icon,
.search-result-content > .overview-icon {
.grid-search-result .overview-icon {
font-size: 9pt;
font-weight: bold;
}
@ -616,12 +616,12 @@ StScrollBar StButton#vhandle:active {
spacing: 40px;
}
.window-caption {
spacing: 25px;
#overview-group {
spacing: 32px;
}
.workspace-controls {
visible-width: 32px; /* Amount visible before hovering */
.window-caption {
spacing: 25px;
}
.workspace-thumbnails-background {
@ -641,6 +641,7 @@ StScrollBar StButton#vhandle:active {
.workspace-thumbnails {
spacing: 11px;
visible-width: 96px;
}
.workspace-thumbnail-indicator {
@ -754,25 +755,33 @@ StScrollBar StButton#vhandle:active {
/* Search Results */
#searchResults {
padding: 20px 10px 10px 10px;
spacing: 18px;
}
#searchResultsContent {
padding-right: 20px;
spacing: 36px;
}
spacing: 16px;
#searchResultsContent:rtl {
padding-right: 0px;
/* for scrollbars */
padding-left: 20px;
padding-right: 20px;
}
.search-section-header {
padding: 4px 12px;
spacing: 4px;
color: #6f6f6f;
font-size: .8em;
.search-section {
/* This should be equal to #searchResultsContent spacing */
spacing: 16px;
}
.search-section-separator {
-gradient-height: 1px;
-gradient-start: rgba(255,255,255,0);
-gradient-end: rgba(255,255,255,0.5);
-margin-horizontal: 1.5em;
height: 1px;
}
.search-section-content {
/* This is the space between the provider icon and the results container */
spacing: 32px;
}
.search-statustext {
@ -781,16 +790,8 @@ StScrollBar StButton#vhandle:active {
font-weight: bold;
}
.search-section-results {
padding: 6px;
}
.search-section-list-results {
spacing: 4px;
}
.results-container {
spacing: 4px;
.list-search-results {
spacing: 3px;
}
/* Text labels are an odd number of pixels tall. The uneven top and bottom
@ -819,7 +820,7 @@ StScrollBar StButton#vhandle:active {
-x-offset: 8px;
}
/* Application Launchers and Grid */
/* Application Launchers, Grid and List results */
.icon-grid {
spacing: 36px;
@ -832,15 +833,10 @@ StScrollBar StButton#vhandle:active {
}
.all-app {
padding: 16px 25px 16px 16px;
padding: 16px;
spacing: 20px;
}
.all-app:rtl {
padding-right: 16px;
padding-left: 25px;
}
.app-filter {
font-weight: bold;
height: 2.85em;
@ -871,9 +867,34 @@ StScrollBar StButton#vhandle:active {
padding: 4px 8px;
}
.list-search-result-content {
spacing: 12px;
padding: 12px;
}
.list-search-result-title {
font-weight: bold;
font-size: 14pt;
color: white;
}
.list-search-result-description {
font-weight: bold;
font-size: 12pt;
color: #eeeeec;
}
.search-provider-icon-more {
width: 16px;
height: 16px;
background-image: url("more-results.svg");
}
.app-well-app > .overview-icon,
.show-apps > .overview-icon,
.search-result-content > .overview-icon {
.search-provider-icon,
.list-search-result,
.grid-search-result .overview-icon {
border-radius: 4px;
padding: 3px;
border: 1px rgba(0,0,0,0);
@ -889,7 +910,9 @@ StScrollBar StButton#vhandle:active {
.app-well-app:hover > .overview-icon,
.show-apps:hover > .overview-icon,
.search-result-content:hover > .overview-icon {
.search-provider-icon:hover,
.list-search-result:hover,
.grid-search-result:hover .overview-icon {
background-color: rgba(255,255,255,0.1);
text-shadow: black 0px 2px 2px;
transition-duration: 100;
@ -924,10 +947,14 @@ StScrollBar StButton#vhandle:active {
}
.app-well-app:focus > .overview-icon,
.search-result-content:focus > .overview-icon,
.grid-search-result:focus .overview-icon,
.show-apps:focus > .overview-icon,
.search-provider-icon:focus,
.list-search-result:focus,
.app-well-app:selected > .overview-icon,
.search-result-content:selected > .overview-icon {
.grid-search-result:selected .overview-icon,
.search-provider-icon:selected,
.list-search-result:selected {
background-color: rgba(255,255,255,0.33);
}
@ -1532,17 +1559,17 @@ StScrollBar StButton#vhandle:active {
.summary-source-counter {
background-image: url("summary-counter.svg");
background-size: 2.5em;
background-size: 2.4em;
font-size: 10pt;
font-weight: bold;
height: 2.5em;
width: 2.5em;
-shell-counter-overlap-x: 4px;
-shell-counter-overlap-y: 4px;
height: 2.4em;
width: 2.4em;
-shell-counter-overlap-x: 13px;
-shell-counter-overlap-y: 13px;
}
/* App Switcher */
#altTabPopup {
.switcher-popup {
padding: 8px;
spacing: 16px;
}
@ -2359,16 +2386,21 @@ StScrollBar StButton#vhandle:active {
}
.screen-shield-notification-source {
padding: 0 24px;
padding: 13px 24px;
spacing: 5px;
}
.screen-shield-notification-label {
font-size: 1.2em;
font-weight: bold;
padding: 0px 18px;
color: #babdb6;
}
.screen-shield-notification-count-text {
padding: 0px 18px;
}
/* Remove background from notifications, otherwise
opacity is doubled and they look darker
*/

View File

@ -0,0 +1,93 @@
<?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="16"
height="16"
id="svg12430"
version="1.1"
inkscape:version="0.48+devel r11908 custom"
sodipodi:docname="more-results.svg">
<defs
id="defs12432" />
<sodipodi:namedview
id="base"
pagecolor="#7a7a7a"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="7.4498765"
inkscape:cy="9.9072581"
inkscape:document-units="px"
inkscape:current-layer="g14642-3-0"
showgrid="false"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:window-width="2560"
inkscape:window-height="1376"
inkscape:window-x="1600"
inkscape:window-y="27"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid13002" />
</sodipodi:namedview>
<metadata
id="metadata12435">
<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)">
<g
style="display:inline"
transform="translate(-141.99984,638.37113)"
inkscape:label="zoom-in"
id="g14642-3-0">
<path
sodipodi:type="inkscape:offset"
inkscape:radius="0"
inkscape:original="M 145.1875 400 C 144.5248 400 144 400.54899 144 401.21875 L 144 410.78125 C 144 411.45101 144.5248 412 145.1875 412 L 154.8125 412 C 155.4752 412 156 411.45101 156 410.78125 L 156 401.21875 C 156 400.54899 155.4752 400 154.8125 400 L 145.1875 400 z M 149 403 L 151 403 L 151 405 L 153 405 L 153 407 L 151 407 L 151 409 L 149 409 L 149 407 L 147 407 L 147 405 L 149 405 L 149 403 z "
xlink:href="#rect11749-5-0-1-8"
style="color:#bebebe;fill:#000000;fill-opacity:0.38207546;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible"
id="path13004"
inkscape:href="#rect11749-5-0-1-8"
d="M 145.1875,400 C 144.5248,400 144,400.54899 144,401.21875 l 0,9.5625 c 0,0.66976 0.5248,1.21875 1.1875,1.21875 l 9.625,0 c 0.6627,0 1.1875,-0.54899 1.1875,-1.21875 l 0,-9.5625 C 156,400.54899 155.4752,400 154.8125,400 L 145.1875,400 z m 3.8125,3 2,0 0,2 2,0 0,2 -2,0 0,2 -2,0 0,-2 -2,0 0,-2 2,0 L 149,403 Z"
transform="translate(0,1)" />
<path
inkscape:connector-curvature="0"
style="color:#bebebe;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible"
d="M 145.1875,400 C 144.5248,400 144,400.54899 144,401.21875 l 0,9.5625 c 0,0.66976 0.5248,1.21875 1.1875,1.21875 l 9.625,0 c 0.6627,0 1.1875,-0.54899 1.1875,-1.21875 l 0,-9.5625 C 156,400.54899 155.4752,400 154.8125,400 L 145.1875,400 z m 3.8125,3 2,0 0,2 2,0 0,2 -2,0 0,2 -2,0 0,-2 -2,0 0,-2 2,0 L 149,403 Z"
id="rect11749-5-0-1-8" />
<rect
style="fill:none;stroke:none"
id="rect3620-5-4"
width="15.981825"
height="16"
x="142"
y="398"
rx="0"
ry="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -76,9 +76,23 @@ endif
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES=
doc-gen-org.gnome.Shell.SearchProvider.xml: $(top_srcdir)/data/org.gnome.ShellSearchProvider.xml
gdbus-codegen \
--interface-prefix org.gnome.ShellSearchProvider. \
--generate-docbook doc-gen \
$(top_srcdir)/data/org.gnome.ShellSearchProvider.xml
doc-gen-org.gnome.Shell.SearchProvider2.xml: $(top_srcdir)/data/org.gnome.ShellSearchProvider2.xml
gdbus-codegen \
--interface-prefix org.gnome.ShellSearchProvider2. \
--generate-docbook doc-gen \
$(top_srcdir)/data/org.gnome.ShellSearchProvider2.xml
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
content_files=
content_files= \
doc-gen-org.gnome.Shell.SearchProvider.xml \
doc-gen-org.gnome.Shell.SearchProvider2.xml
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
# These files must be listed here *and* in content_files

View File

@ -43,6 +43,8 @@
</chapter>
<chapter>
<title>Integration helpers and utilities</title>
<xi:include href="doc-gen-org.gnome.Shell.SearchProvider.xml"/>
<xi:include href="doc-gen-org.gnome.Shell.SearchProvider2.xml"/>
<xi:include href="xml/shell-global.xml"/>
<xi:include href="xml/shell-wm.xml"/>
<xi:include href="xml/shell-xfixes-cursor.xml"/>

View File

@ -52,13 +52,6 @@ its dependencies to build from tarballs.</description>
<gnome:userid>walters</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Dan Winship</foaf:name>
<foaf:mbox rdf:resource="mailto:danw@gnome.org" />
<gnome:userid>danw</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Marina Zhurakhinskaya</foaf:name>

View File

@ -41,6 +41,7 @@ nobase_dist_js_DATA = \
ui/boxpointer.js \
ui/calendar.js \
ui/checkBox.js \
ui/centerLayout.js \
ui/ctrlAltTab.js \
ui/dash.js \
ui/dateMenu.js \
@ -62,6 +63,7 @@ nobase_dist_js_DATA = \
ui/main.js \
ui/messageTray.js \
ui/modalDialog.js \
ui/separator.js \
ui/sessionMode.js \
ui/shellEntry.js \
ui/shellMountOperation.js \
@ -85,6 +87,7 @@ nobase_dist_js_DATA = \
ui/status/power.js \
ui/status/volume.js \
ui/status/bluetooth.js \
ui/switcherPopup.js \
ui/tweener.js \
ui/unlockDialog.js \
ui/userMenu.js \

View File

@ -11,6 +11,7 @@ const Gio = imports.gi.Gio;
const ShellJS = imports.gi.ShellJS;
const Config = imports.misc.config;
const FileUtils = imports.misc.fileUtils;
const ExtensionType = {
SYSTEM: 1,
@ -150,53 +151,35 @@ function installImporter(extension) {
const ExtensionFinder = new Lang.Class({
Name: 'ExtensionFinder',
_scanExtensionsInDirectory: function(dir, type) {
let fileEnum;
let file, info;
try {
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
} catch(e) {
if (e.domain != Gio.io_error_quark() || e.code != Gio.IOErrorEnum.NOT_FOUND)
logError(e, 'Could not enumerate extensions directory');
_loadExtension: function(extensionDir, info, perUserDir) {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
return;
let uuid = info.get_name();
let existing = extensions[uuid];
if (existing) {
log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path()));
return;
}
while ((info = fileEnum.next_file(null)) != null) {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
continue;
let uuid = info.get_name();
let extensionDir = dir.get_child(uuid);
let existing = extensions[uuid];
if (existing) {
log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path()));
continue;
}
let extension;
try {
extension = createExtensionObject(uuid, extensionDir, type);
} catch(e) {
logError(e, 'Could not load extension %s'.format(uuid));
continue;
}
this.emit('extension-found', extension);
let extension;
let type = extensionDir.has_prefix(perUserDir) ? ExtensionType.PER_USER
: ExtensionType.SYSTEM;
try {
extension = createExtensionObject(uuid, extensionDir, type);
} catch(e) {
logError(e, 'Could not load extension %s'.format(uuid));
return;
}
fileEnum.close(null);
this.emit('extension-found', extension);
},
scanExtensions: function() {
let userExtensionsDir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions']));
this._scanExtensionsInDirectory(userExtensionsDir, ExtensionType.PER_USER);
let systemDataDirs = GLib.get_system_data_dirs();
for (let i = 0; i < systemDataDirs.length; i++) {
let dirPath = GLib.build_filenamev([systemDataDirs[i], 'gnome-shell', 'extensions']);
let dir = Gio.file_new_for_path(dirPath);
if (dir.query_exists(null))
this._scanExtensionsInDirectory(dir, ExtensionType.SYSTEM);
}
let perUserDir = Gio.File.new_for_path(global.userdatadir);
FileUtils.collectFromDatadirsAsync('extensions',
{ processFile: Lang.bind(this, this._loadExtension),
includeUserDir: true,
data: perUserDir });
}
});
Signals.addSignalMethods(ExtensionFinder.prototype);

View File

@ -2,10 +2,12 @@
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Params = imports.misc.params;
function listDirAsync(file, callback) {
let allFiles = [];
file.enumerate_children_async(Gio.FILE_ATTRIBUTE_STANDARD_NAME,
file.enumerate_children_async('standard::name,standard::type',
Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_LOW, null, function (obj, res) {
let enumerator = obj.enumerate_children_finish(res);
@ -23,6 +25,63 @@ function listDirAsync(file, callback) {
});
}
function _collectFromDirectoryAsync(dir, loadState) {
function done() {
loadState.numLoading--;
if (loadState.loadedCallback &&
loadState.numLoading == 0)
loadState.loadedCallback(loadState.data);
}
dir.query_info_async('standard::type', Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_DEFAULT, null, function(object, res) {
try {
object.query_info_finish(res);
} catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
log(e.message);
done();
return;
}
listDirAsync(dir, Lang.bind(this, function(infos) {
for (let i = 0; i < infos.length; i++)
loadState.processFile(dir.get_child(infos[i].get_name()),
infos[i], loadState.data);
done();
}));
});
}
function collectFromDatadirsAsync(subdir, params) {
params = Params.parse(params, { includeUserDir: false,
processFile: null,
loadedCallback: null,
data: null });
let loadState = { data: params.data,
numLoading: 0,
loadedCallback: params.loadedCallback,
processFile: params.processFile };
if (params.processFile == null) {
if (params.loadedCallback)
params.loadedCallback(params.data);
return;
}
let dataDirs = GLib.get_system_data_dirs();
if (params.includeUserDir)
dataDirs.unshift(GLib.get_user_data_dir());
loadState.numLoading = dataDirs.length;
for (let i = 0; i < dataDirs.length; i++) {
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', subdir]);
let dir = Gio.File.new_for_path(path);
_collectFromDirectoryAsync(dir, loadState);
}
}
function deleteGFile(file) {
// Work around 'delete' being a keyword in JS.
return file['delete'](null);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const GMenu = imports.gi.GMenu;
@ -18,7 +19,6 @@ const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const Search = imports.ui.search;
const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const Params = imports.misc.params;
@ -48,18 +48,16 @@ const AlphabeticalView = new Lang.Class({
style_class: 'vfade' });
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 action = new Clutter.PanAction({ interpolate: true });
action.connect('pan', Lang.bind(this, this._onPan));
this.actor.add_action(action);
},
let adjustment = this.actor.vscroll.adjustment;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(adjustment, direction);
// Reset scroll on mapping
adjustment.value = 0;
}));
_onPan: function(action) {
let [dist, dx, dy] = action.get_motion_delta(0);
let adjustment = this.actor.vscroll.adjustment;
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
return false;
},
removeAll: function() {
@ -223,7 +221,7 @@ const ViewByCategories = new Lang.Class({
this._loadCategory(dir, apps);
if (apps.length == 0)
return;
return false;
}
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
@ -244,6 +242,7 @@ const ViewByCategories = new Lang.Class({
}
this._categoryBox.add(button, { expand: true, x_fill: true, y_fill: false });
return true;
},
_removeAll: function() {
@ -269,8 +268,9 @@ const ViewByCategories = new Lang.Class({
var dir = iter.get_directory();
if (dir.get_is_nodisplay())
continue;
this._addCategory(dir.get_name(), i, dir);
i++;
if (this._addCategory(dir.get_name(), i, dir))
i++;
}
}
@ -311,11 +311,10 @@ const AllAppDisplay = new Lang.Class({
const AppSearchProvider = new Lang.Class({
Name: 'AppSearchProvider',
Extends: Search.SearchProvider,
_init: function() {
this.parent(_("APPLICATIONS"));
this._appSys = Shell.AppSystem.get_default();
this.id = 'applications';
},
getResultMetas: function(apps, callback) {
@ -340,18 +339,15 @@ const AppSearchProvider = new Lang.Class({
this.searchSystem.pushResults(this, this._appSys.subsearch(previousResults, terms));
},
activateResult: function(app, params) {
params = Params.parse(params, { workspace: -1,
timestamp: 0 });
activateResult: function(app) {
let event = Clutter.get_current_event();
let modifiers = event ? event.get_state() : 0;
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
if (openNewWindow)
app.open_new_window(params.workspace);
app.open_new_window(-1);
else
app.activate_full(params.workspace, params.timestamp);
app.activate();
},
dragActivateResult: function(id, params) {
@ -371,13 +367,10 @@ const AppSearchProvider = new Lang.Class({
const SettingsSearchProvider = new Lang.Class({
Name: 'SettingsSearchProvider',
Extends: Search.SearchProvider,
_init: function() {
this.parent(_("SETTINGS"));
this.appInfo = Gio.DesktopAppInfo.new('gnome-control-center.desktop');
this._appSys = Shell.AppSystem.get_default();
this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
},
getResultMetas: function(prefs, callback) {
@ -386,9 +379,7 @@ const SettingsSearchProvider = new Lang.Class({
let pref = prefs[i];
metas.push({ 'id': pref,
'name': pref.get_name(),
'createIcon': function(size) {
return pref.create_icon_texture(size);
}
'createIcon': function() { return null; }
});
}
callback(metas);
@ -402,21 +393,13 @@ const SettingsSearchProvider = new Lang.Class({
this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
},
activateResult: function(pref, params) {
params = Params.parse(params, { workspace: -1,
timestamp: 0 });
pref.activate_full(params.workspace, params.timestamp);
activateResult: function(pref) {
pref.activate();
},
dragActivateResult: function(pref, params) {
this.activateResult(pref, params);
},
createResultActor: function (resultMeta, terms) {
let app = resultMeta['id'];
let icon = new AppWellIcon(app);
return icon.actor;
launchSearch: function(terms) {
// FIXME: this should be a remote search provider
this.appInfo.launch([], global.create_app_launch_context());
}
});
@ -571,6 +554,7 @@ const AppWellIcon = new Lang.Class({
this.actor.set_hover(true);
this._menu.popup();
this._menuManager.ignoreRelease();
return false;
},

60
js/ui/centerLayout.js Normal file
View File

@ -0,0 +1,60 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang;
const Clutter = imports.gi.Clutter;
const CenterLayout = new Lang.Class({
Name: 'CenterLayout',
Extends: Clutter.BoxLayout,
vfunc_allocate: function(container, box, flags) {
let rtl = container.get_text_direction() == Clutter.TextDirection.RTL;
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
// Assume that these are the first three widgets and they are all visible.
let [left, center, right] = container.get_children();
// Only support horizontal layouts for now.
let [leftMinWidth, leftNaturalWidth] = left.get_preferred_width(availHeight);
let [centerMinWidth, centerNaturalWidth] = center.get_preferred_width(availHeight);
let [rightMinWidth, rightNaturalWidth] = right.get_preferred_width(availHeight);
let sideWidth = (availWidth - centerMinWidth) / 2;
let childBox = new Clutter.ActorBox();
childBox.y1 = box.y1;
childBox.y2 = box.y1 + availHeight;
let leftSide = Math.min(Math.floor(sideWidth), leftNaturalWidth);
let rightSide = Math.min(Math.floor(sideWidth), rightNaturalWidth);
if (rtl) {
childBox.x1 = availWidth - leftSide;
childBox.x2 = availWidth;
} else {
childBox.x1 = 0;
childBox.x2 = leftSide;
}
childBox.x1 += box.x1;
left.allocate(childBox, flags);
let maxSide = Math.max(leftSide, rightSide);
let sideWidth = Math.max((availWidth - centerNaturalWidth) / 2, maxSide);
childBox.x1 = box.x1 + Math.ceil(sideWidth);
childBox.x2 = box.x2 - Math.ceil(sideWidth);
center.allocate(childBox, flags);
if (rtl) {
childBox.x1 = 0;
childBox.x2 = rightSide;
} else {
childBox.x1 = availWidth - rightSide;
childBox.x2 = availWidth;
}
childBox.x1 += box.x1;
right.allocate(childBox, flags);
}
});

View File

@ -478,7 +478,7 @@ const ChatSource = new Lang.Class({
}));
item.connect('activate', Lang.bind(this, function() {
this.setMuted(!this.isMuted);
this.emit('done-displaying-content');
this.emit('done-displaying-content', false);
}));
rightClickMenu.add(item.actor);
return rightClickMenu;
@ -926,26 +926,24 @@ const ChatNotification = new Lang.Class({
}
// Show the word "Yesterday" and time if date is on yesterday
else if(daysAgo <2){
/* Translators: this is a time format string followed by the word "Yesterday". i.e. "14:30 on Yesterday"*/
/* Translators: this is the word "Yesterday" followed by a time string. i.e. "Yesterday, 14:30"*/
// xgettext:no-c-format
format = _("<b>%H:%M</b> on Yesterday");
format = _("<b>Yesterday</b>, <b>%H:%M</b>");
}
// Show a week day and time if date is in the last week
else if (daysAgo < 7) {
/* Translators: this is a time format string followed by a week day name. i.e. "14:30 on Monday*/
/* Translators: this is the week day name followed by a time string. i.e. "Monday, 14:30*/
// xgettext:no-c-format
format = _("<b>%H:%M</b> on <b>%A</b>");
format = _("<b>%A</b>, <b>%H:%M</b>");
} else if (date.getYear() == now.getYear()) {
/* Translators: this is a time format in the style of "14:30 on Wednesday, May 25",
shown when you get a chat message in the same year */
/* Translators: this is the month name and day number followed by a time string. i.e. "May 25, 14:30"*/
// xgettext:no-c-format
format = _("<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>");
format = _("<b>%B</b> <b>%d</b>, <b>%H:%M</b>");
} else {
/* Translators: this is a time format in the style of "14:30 on Wednesday, May 25, 2012",
shown when you get a chat message in a different year */
/* Translators: this is the month name, day number, year number followed by a time string. i.e. "May 25 2012, 14:30"*/
// xgettext:no-c-format
format = _("<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>, %Y");
format = _("<b>%B</b> <b>%d</b> <b>%Y</b>, <b>%H:%M</b> ");
}
return date.toLocaleFormat(format);

View File

@ -1,15 +1,14 @@
// -*- mode: js; js-indent-level: 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 SwitcherPopup = imports.ui.switcherPopup;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
@ -27,6 +26,9 @@ const CtrlAltTabManager = new Lang.Class({
_init: function() {
this._items = [];
this.addGroup(global.window_group, _("Windows"),
'emblem-documents-symbolic', { sortGroup: SortGroup.TOP,
focusCallback: Lang.bind(this, this._focusWindows) });
},
addGroup: function(root, name, icon, params) {
@ -40,11 +42,13 @@ const CtrlAltTabManager = new Lang.Class({
this._items.push(item);
root.connect('destroy', Lang.bind(this, function() { this.removeGroup(root); }));
global.focus_manager.add_group(root);
if (root instanceof St.Widget)
global.focus_manager.add_group(root);
},
removeGroup: function(root) {
global.focus_manager.remove_group(root);
if (root instanceof St.Widget)
global.focus_manager.remove_group(root);
for (let i = 0; i < this._items.length; i++) {
if (this._items[i].root == root) {
this._items.splice(i, 1);
@ -53,11 +57,9 @@ const CtrlAltTabManager = new Lang.Class({
}
},
focusGroup: function(item) {
if (item.window) {
Main.activateWindow(item.window);
} else if (item.focusCallback) {
item.focusCallback();
focusGroup: function(item, timestamp) {
if (item.focusCallback) {
item.focusCallback(timestamp);
} else {
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
global.stage_input_mode == Shell.StageInputMode.NORMAL)
@ -75,24 +77,14 @@ const CtrlAltTabManager = new Lang.Class({
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();
}
let ax, bx, y;
[ax, y] = a.proxy.get_transformed_position();
[bx, y] = b.proxy.get_transformed_position();
return a.x - b.x;
return ax - bx;
},
popup: function(backwards, mask) {
popup: function(backward, binding, mask) {
// Start with the set of focus groups that are currently mapped
let items = this._items.filter(function (item) { return item.proxy.mapped; });
@ -123,187 +115,63 @@ const CtrlAltTabManager = new Lang.Class({
items.sort(Lang.bind(this, this._sortItems));
if (!this._popup) {
this._popup = new CtrlAltTabPopup();
this._popup.show(items, backwards, mask);
this._popup = new CtrlAltTabPopup(items);
this._popup.show(backward, binding, mask);
this._popup.actor.connect('destroy',
Lang.bind(this, function() {
this._popup = null;
}));
}
},
_focusWindows: function(timestamp) {
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
global.stage.key_focus = null;
global.screen.focus_default_window(timestamp);
}
});
function mod(a, b) {
return (a + b) % b;
}
const CtrlAltTabPopup = new Lang.Class({
Name: 'CtrlAltTabPopup',
Extends: SwitcherPopup.SwitcherPopup,
_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._modifierMask = 0;
this._selection = 0;
Main.uiGroup.add_actor(this.actor);
_createSwitcher: function() {
this._switcherList = new CtrlAltTabSwitcher(this._items);
return true;
},
_getPreferredWidth: function (actor, forHeight, alloc) {
let primary = Main.layoutManager.primaryMonitor;
alloc.min_size = primary.width;
alloc.natural_size = primary.width;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
let primary = Main.layoutManager.primaryMonitor;
alloc.min_size = primary.height;
alloc.natural_size = primary.height;
},
_allocate: function (actor, box, flags) {
let childBox = new Clutter.ActorBox();
let primary = Main.layoutManager.primaryMonitor;
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.x + 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, mask) {
if (!Main.pushModal(this.actor))
return false;
this._haveModal = true;
this._modifierMask = AltTab.primaryModifier(mask);
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 & this._modifierMask)) {
this._finish();
return false;
_initialSelection: function(backward, binding) {
if (binding == 'switch-panels') {
if (backward)
this._selectedIndex = this._items.length - 1;
} else if (binding == 'switch-panels-backward') {
if (!backward)
this._selectedIndex = this._items.length - 1;
}
this.actor.opacity = 0;
this.actor.show();
Tweener.addTween(this.actor,
{ opacity: 255,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad'
});
return true;
this._select(this._selectedIndex);
},
_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 = (event.get_state() & 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)
_keyPressHandler: function(keysym, backwards, action) {
if (action == Meta.KeyBindingAction.SWITCH_PANELS)
this._select(backwards ? this._previous() : this._next());
else if (action == Meta.KeyBindingAction.SWITCH_PANELS_BACKWARD)
this._select(backwards ? this._next() : this._previous());
else if (keysym == Clutter.Left)
this._select(this._previous());
else if (keysym == Clutter.KEY_Left)
this._select(this._previous());
else if (keysym == Clutter.KEY_Right)
else if (keysym == Clutter.Right)
this._select(this._next());
return true;
},
_keyReleaseEvent : function(actor, event) {
let [x, y, mods] = global.get_pointer();
let state = mods & this._modifierMask;
if (state == 0)
this._finish();
return true;
_finish : function(time) {
this.parent(time);
Main.ctrlAltTabManager.focusGroup(this._items[this._selectedIndex], time);
},
_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);
}
});
const CtrlAltTabSwitcher = new Lang.Class({
Name: 'CtrlAltTabSwitcher',
Extends: AltTab.SwitcherList,
Extends: SwitcherPopup.SwitcherList,
_init : function(items) {
this.parent(true);

View File

@ -371,6 +371,7 @@ const Dash = new Lang.Class({
this._maxHeight = -1;
this.iconSize = 64;
this._shownInitially = false;
this._ignoreHeight = false;
this._dragPlaceholder = null;
this._dragPlaceholderPos = -1;
@ -396,7 +397,10 @@ const Dash = new Lang.Class({
this.actor = new St.Bin({ child: this._container });
this.actor.connect('notify::height', Lang.bind(this,
function() {
if (this._maxHeight != this.actor.height)
if (this._ignoreHeight)
return;
if (this._maxHeight != this.actor.height);
this._queueRedisplay();
this._maxHeight = this.actor.height;
}));
@ -421,6 +425,8 @@ const Dash = new Lang.Class({
Lang.bind(this, this._onDragCancelled));
Main.overview.connect('window-drag-end',
Lang.bind(this, this._onDragEnd));
Main.overview.connect('showing',
Lang.bind(this, this._onOverviewShowing));
},
_onDragBegin: function() {
@ -923,6 +929,65 @@ const Dash = new Lang.Class({
}));
return true;
},
_computeTranslation: function() {
let rtl = (this.actor.get_text_direction() == Clutter.TextDirection.RTL);
if (rtl)
return this.actor.width;
else
return - this.actor.width;
},
_onOverviewShowing: function() {
// reset any translation and make sure the actor is visible when
// entering the overview
this.slideX = 0;
this.actor.show();
},
get slideX() {
return this._slideX;
},
set slideX(value) {
this._slideX = value;
this.actor.translation_x = this._slideX;
if (this._slideX > 0) {
let rect = new Clutter.Rect();
rect.size.width = this.actor.width - this._slideX;
rect.size.height = this.actor.height;
this.actor.clip_rect = rect;
} else {
this.actor.clip_rect = null;
}
},
show: function() {
this.actor.show();
Tweener.addTween(this, { slideX: 0,
transition: 'easeOutQuad',
time: DASH_ANIMATION_TIME,
onComplete: Lang.bind(this,
function() {
this._ignoreHeight = false;
})
});
},
hide: function() {
this._ignoreHeight = true;
let hiddenX = this._computeTranslation();
Tweener.addTween(this, { slideX: hiddenX,
transition: 'easeOutQuad',
time: DASH_ANIMATION_TIME,
onComplete: Lang.bind(this,
function() {
this.actor.hide();
})
});
}
});

View File

@ -234,7 +234,7 @@ const _Draggable = new Lang.Class({
this._dragY = this._dragStartY = stageY;
if (this.actor._delegate && this.actor._delegate.getDragActor) {
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
this._dragActor = this.actor._delegate.getDragActor();
this._dragActor.reparent(Main.uiGroup);
this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true);

View File

@ -211,8 +211,16 @@ function initExtension(uuid) {
_signals.emit('extension-loaded', uuid);
}
function getEnabledExtensions() {
let extensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
if (!Array.isArray(Main.sessionMode.enabledExtensions))
return extensions;
return Main.sessionMode.enabledExtensions.concat(extensions);
}
function onEnabledExtensionsChanged() {
let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
let newEnabledExtensions = getEnabledExtensions();
if (!enabled)
return;
@ -246,7 +254,7 @@ function onEnabledExtensionsChanged() {
function _loadExtensions() {
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
enabledExtensions = getEnabledExtensions();
let finder = new ExtensionUtils.ExtensionFinder();
finder.connect('extension-found', function(signals, extension) {
@ -288,10 +296,17 @@ function disableAllExtensions() {
}
function _sessionUpdated() {
if (Main.sessionMode.allowExtensions)
// For now sessionMode.allowExtensions controls extensions from both the
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
// property; it might make sense to make enabledExtensions independent
// from allowExtensions in the future
if (Main.sessionMode.allowExtensions) {
if (initted)
onEnabledExtensionsChanged();
enableAllExtensions();
else
} else {
disableAllExtensions();
}
}
function init() {

View File

@ -43,7 +43,6 @@ const GrabHelper = new Lang.Class({
this._actors = [];
this._capturedEventId = 0;
this._eventId = 0;
this._keyFocusNotifyId = 0;
this._focusWindowChangedId = 0;
this._ignoreRelease = false;
@ -78,9 +77,12 @@ const GrabHelper = new Lang.Class({
},
_isWithinGrabbedActor: function(actor) {
let currentActor = this.currentGrab.actor;
while (actor) {
if (this._actors.indexOf(actor) != -1)
return true;
if (actor == currentActor)
return true;
actor = actor.get_parent();
}
return false;
@ -90,6 +92,14 @@ const GrabHelper = new Lang.Class({
return this._grabStack[this._grabStack.length - 1] || {};
},
get grabbed() {
return this._grabStack.length > 0;
},
get grabStack() {
return this._grabStack;
},
_findStackIndex: function(actor) {
if (!actor)
return -1;
@ -101,6 +111,16 @@ const GrabHelper = new Lang.Class({
return -1;
},
_actorInGrabStack: function(actor) {
while (actor) {
let idx = this._findStackIndex(actor);
if (idx >= 0)
return idx;
actor = actor.get_parent();
}
return -1;
},
isActorGrabbed: function(actor) {
return this._findStackIndex(actor) >= 0;
},
@ -140,6 +160,7 @@ const GrabHelper = new Lang.Class({
params = Params.parse(params, { actor: null,
modal: false,
grabFocus: false,
focus: null,
onUngrab: null });
let focus = global.stage.key_focus;
@ -157,7 +178,9 @@ const GrabHelper = new Lang.Class({
if (params.grabFocus && !this._takeFocusGrab(hadFocus))
return false;
if (hadFocus || params.grabFocus)
if (params.focus)
params.focus.grab_key_focus();
else if (hadFocus || params.grabFocus)
_navigateActor(newFocus);
this._grabStack.push(params);
@ -171,7 +194,6 @@ const GrabHelper = new Lang.Class({
return false;
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this._eventId = global.stage.connect('event', Lang.bind(this, this._onEvent));
}
this._modalCount++;
@ -188,11 +210,6 @@ const GrabHelper = new Lang.Class({
this._capturedEventId = 0;
}
if (this._eventId > 0) {
global.stage.disconnect(this._eventId);
this._eventId = 0;
}
Main.popModal(this._owner);
global.sync_pointer();
},
@ -204,7 +221,6 @@ const GrabHelper = new Lang.Class({
this._grabbedFromKeynav = hadFocus;
this._preGrabInputMode = global.stage_input_mode;
this._prevFocusedWindow = metaDisplay.focus_window;
if (this._preGrabInputMode == Shell.StageInputMode.NONREACTIVE ||
this._preGrabInputMode == Shell.StageInputMode.NORMAL) {
@ -243,13 +259,7 @@ const GrabHelper = new Lang.Class({
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
}
if (this._prevFocusedWindow) {
let metaDisplay = global.screen.get_display();
if (!metaDisplay.focus_window) {
metaDisplay.set_input_focus_window(this._prevFocusedWindow,
false, global.get_current_time());
}
}
global.screen.focus_default_window(global.get_current_time());
},
// ignoreRelease:
@ -270,7 +280,8 @@ const GrabHelper = new Lang.Class({
// If the actor that was popped from the grab stack was not the actor
// That was passed in, this call is ignored.
ungrab: function(params) {
params = Params.parse(params, { actor: this.currentGrab.actor });
params = Params.parse(params, { actor: this.currentGrab.actor,
isUser: false });
let grabStackIndex = this._findStackIndex(params.actor);
if (grabStackIndex < 0)
@ -288,7 +299,7 @@ const GrabHelper = new Lang.Class({
let poppedGrab = poppedGrabs[i];
if (poppedGrab.onUngrab)
poppedGrab.onUngrab();
poppedGrab.onUngrab(params.isUser);
if (poppedGrab.modal)
this._releaseModalGrab();
@ -311,12 +322,18 @@ const GrabHelper = new Lang.Class({
if (release && this._ignoreRelease) {
this._ignoreRelease = false;
return false;
return true;
}
if (!button && this._modalCount == 0)
return false;
if (type == Clutter.EventType.KEY_PRESS &&
event.get_key_symbol() == Clutter.KEY_Escape) {
this.ungrab({ isUser: true });
return true;
}
if (this._isWithinGrabbedActor(event.get_source()))
return false;
@ -328,33 +345,22 @@ const GrabHelper = new Lang.Class({
// which should be a release event.
if (press)
this._ignoreRelease = true;
this.ungrab({ actor: this._grabStack[0].actor });
let i = this._actorInGrabStack(event.get_source()) + 1;
this.ungrab({ actor: this._grabStack[i].actor, isUser: true });
}
return this._modalCount > 0;
},
// We catch 'event' rather than 'key-press-event' so that we get
// a chance to run before the overview's own Escape check
_onEvent: function(actor, event) {
if (event.type() == Clutter.EventType.KEY_PRESS &&
event.get_key_symbol() == Clutter.KEY_Escape) {
this.ungrab();
return true;
}
return false;
},
_onKeyFocusChanged: function() {
let focus = global.stage.key_focus;
if (!focus || !this._isWithinGrabbedActor(focus))
this.ungrab();
this.ungrab({ isUser: true });
},
_focusWindowChanged: function() {
let metaDisplay = global.screen.get_display();
if (metaDisplay.focus_window != null)
this.ungrab();
this.ungrab({ isUser: true });
}
});

View File

@ -198,7 +198,11 @@ const IconGrid = new Lang.Class({
_getPreferredHeight: function (grid, forWidth, alloc) {
let children = this._getVisibleChildren();
let [nColumns, usedWidth] = this._computeLayout(forWidth);
let nColumns;
if (forWidth < 0)
nColumns = children.length;
else
nColumns = this._computeLayout(forWidth)[0];
let nRows;
if (nColumns > 0)
nRows = Math.ceil(children.length / nColumns);

View File

@ -124,7 +124,7 @@ const LayoutManager = new Lang.Class({
this.addChrome(this.panelBox, { affectsStruts: true,
trackFullscreen: true });
this.panelBox.connect('allocation-changed',
Lang.bind(this, this._updatePanelBarriers));
Lang.bind(this, this._panelBoxChanged));
this.trayBox = new St.Widget({ name: 'trayBox',
layout_manager: new Clutter.BinLayout() });
@ -256,6 +256,11 @@ const LayoutManager = new Lang.Class({
this.bottomMonitor.width, this.bottomMonitor.height);
},
_panelBoxChanged: function() {
this.emit('panel-box-changed');
this._updatePanelBarriers();
},
_updatePanelBarriers: function() {
if (this._leftPanelBarrier)
global.destroy_pointer_barrier(this._leftPanelBarrier);
@ -342,7 +347,7 @@ const LayoutManager = new Lang.Class({
},
_startupAnimation: function() {
this.panelBox.anchor_y = this.panelBox.height;
this.panelBox.translation_y = -this.panelBox.height;
let plymouthTransitionRunning = false;
@ -378,7 +383,7 @@ const LayoutManager = new Lang.Class({
}
Tweener.addTween(this.panelBox,
{ anchor_y: 0,
{ translation_y: 0,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._startupAnimationComplete,
@ -387,6 +392,7 @@ const LayoutManager = new Lang.Class({
},
_startupAnimationComplete: function() {
this.emit('panel-box-changed');
this._chrome.thawUpdateRegions();
},

View File

@ -180,7 +180,7 @@ function start() {
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
false, -1, 1);
global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
sessionMode.connect('update', _sessionUpdated);
sessionMode.connect('updated', _sessionUpdated);
_sessionUpdated();
// Provide the bus object for gnome-session to

View File

@ -1088,14 +1088,14 @@ const Source = new Lang.Class({
item = new PopupMenu.PopupMenuItem(_("Open"));
item.connect('activate', Lang.bind(this, function() {
this.open();
this.emit('done-displaying-content');
this.emit('done-displaying-content', true);
}));
rightClickMenu.add(item.actor);
item = new PopupMenu.PopupMenuItem(_("Remove"));
item.connect('activate', Lang.bind(this, function() {
this.destroy();
this.emit('done-displaying-content');
this.emit('done-displaying-content', false);
}));
rightClickMenu.add(item.actor);
return rightClickMenu;
@ -1341,7 +1341,7 @@ const SummaryItem = new Lang.Class({
},
_notificationDoneDisplaying: function() {
this.source.emit('done-displaying-content');
this.source.emit('done-displaying-content', true);
},
_notificationDestroyed: function(notification) {
@ -1441,7 +1441,6 @@ const MessageTray = new Lang.Class({
this._clickedSummaryItem = null;
this._clickedSummaryItemMouseButton = -1;
this._clickedSummaryItemAllocationChangedId = 0;
this._pointerBarrier = 0;
this._closeButton = makeCloseButton();
this._closeButton.hide();
@ -1486,6 +1485,7 @@ const MessageTray = new Lang.Class({
this._reNotifyAfterHideNotification = null;
this._inFullscreen = false;
this._desktopClone = null;
this._inCtrlAltTab = false;
this._lightbox = new Lightbox.Lightbox(global.window_group,
{ inhibitEvents: true,
@ -1507,7 +1507,7 @@ const MessageTray = new Lang.Class({
this._overviewVisible = true;
this._grabHelper.ungrab(); // drop modal grab if necessary
this.actor.add_style_pseudo_class('overview');
this._updateState();
this.show();
}));
Main.overview.connect('hiding', Lang.bind(this,
function() {
@ -1563,12 +1563,15 @@ const MessageTray = new Lang.Class({
},
_sessionUpdated: function() {
if (Main.sessionMode.isLocked || Main.sessionMode.isGreeter)
if ((Main.sessionMode.isLocked || Main.sessionMode.isGreeter) && this._inCtrlAltTab) {
Main.ctrlAltTabManager.removeGroup(this._summary);
else
this._inCtrlAltTab = false;
} else if (!this._inCtrlAltTab) {
Main.ctrlAltTabManager.addGroup(this._summary, _("Message Tray"), 'user-available-symbolic',
{ focusCallback: Lang.bind(this, this.toggleAndNavigate),
sortGroup: CtrlAltTab.SortGroup.BOTTOM });
this._inCtrlAltTab = true;
}
this._updateState();
},
@ -1787,6 +1790,11 @@ const MessageTray = new Lang.Class({
this._updateState();
},
show: function() {
this._traySummoned = true;
this._updateState();
},
_onNotify: function(source, notification) {
if (this._summaryBoxPointerItem && this._summaryBoxPointerItem.source == source) {
if (this._summaryBoxPointerState == State.HIDING) {
@ -2033,14 +2041,14 @@ const MessageTray = new Lang.Class({
}
// Summary
let summarySummoned = this._pointerInSummary || this._overviewVisible || this._traySummoned;
let summarySummoned = this._pointerInSummary || this._traySummoned;
let summaryPinned = this._pointerInTray || summarySummoned || this._locked;
let summaryHovered = this._pointerInTray || this._pointerInSummary;
let notificationsVisible = this._notificationState != State.HIDDEN;
let notificationsDone = !notificationsVisible && !notificationsPending;
let summaryOptionalInOverview = this._overviewVisible && !this._locked && !summaryHovered;
let summaryOptionalInOverview = !this._locked && !summaryHovered;
let mustHideSummary = (notificationsPending && (notificationUrgent || summaryOptionalInOverview))
|| notificationsVisible || !Main.sessionMode.hasNotifications;
@ -2263,40 +2271,28 @@ const MessageTray = new Lang.Class({
_updateShowingNotification: function() {
this._notification.acknowledged = true;
Tweener.removeTweens(this._notificationWidget);
// We auto-expand notifications with CRITICAL urgency.
// We use Tweener.removeTweens() to remove a tween that was hiding the notification we are
// updating, in case that notification was in the process of being hidden. However,
// Tweener.removeTweens() would also remove a tween that was updating the position of the
// notification we are updating, in case that notification was already expanded and its height
// changed. Therefore we need to call this._expandNotification() for expanded notifications
// to make sure their position is updated.
if (this._notification.urgency == Urgency.CRITICAL || this._notification.expanded)
if (this._notification.urgency == Urgency.CRITICAL)
this._expandNotification(true);
// We tween all notifications to full opacity. This ensures that both new notifications and
// notifications that might have been in the process of hiding get full opacity.
//
// We tween any notification showing in the banner mode to banner height
// (this._notificationWidget.y = -this._notificationWidget.height).
// We tween any notification showing in the banner mode to the appropriate height
// (which is banner height or expanded height, depending on the notification state)
// This ensures that both new notifications and notifications in the banner mode that might
// have been in the process of hiding are shown with the banner height.
// have been in the process of hiding are shown with the correct height.
//
// We use this._showNotificationCompleted() onComplete callback to extend the time the updated
// notification is being shown.
//
// We don't set the y parameter for the tween for expanded notifications because
// this._expandNotification() will result in getting this._notificationWidget.y set to the appropriate
// fully expanded value.
let tweenParams = { opacity: 255,
y: -this._notificationWidget.height,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._showNotificationCompleted,
onCompleteScope: this
};
if (!this._notification.expanded)
tweenParams.y = -this._notificationWidget.height;
this._tween(this._notificationWidget, '_notificationState', State.SHOWN, tweenParams);
},
@ -2466,12 +2462,21 @@ const MessageTray = new Lang.Class({
});
},
_onSourceDoneDisplayingContent: function(source, closeTray) {
if (closeTray) {
this._escapeTray();
} else {
this._setClickedSummaryItem(null);
this._updateState();
}
},
_showSummaryBoxPointer: function() {
this._summaryBoxPointerItem = this._clickedSummaryItem;
this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
Lang.bind(this, this._onSummaryBoxPointerContentUpdated));
this._sourceDoneDisplayingId = this._summaryBoxPointerItem.source.connect('done-displaying-content',
Lang.bind(this, this._escapeTray));
Lang.bind(this, this._onSourceDoneDisplayingContent));
let hasRightClickMenu = this._summaryBoxPointerItem.rightClickMenu != null;
if (this._clickedSummaryItemMouseButton == 1 || !hasRightClickMenu) {

View File

@ -10,6 +10,7 @@ const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Gdk = imports.gi.Gdk;
const CenterLayout = imports.ui.centerLayout;
const Dash = imports.ui.dash;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
@ -23,9 +24,6 @@ const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
// Time for initial animation going into Overview mode
const ANIMATION_TIME = 0.25;
// XXX -- grab this automatically. Hard to do.
const DASH_MAX_WIDTH = 96;
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
const GLSL_DIM_EFFECT_DECLARATIONS = '';
@ -46,18 +44,6 @@ const GLSL_DIM_EFFECT_CODE = '\
cogl_color_out.xyz = cogl_color_out.xyz * (1.0 - a); \
cogl_color_out.a = 1.0;';
const SwipeScrollDirection = {
NONE: 0,
HORIZONTAL: 1,
VERTICAL: 2
};
const SwipeScrollResult = {
CANCEL: 0,
SWIPE: 1,
CLICK: 2
};
const ShellInfo = new Lang.Class({
Name: 'ShellInfo',
@ -112,11 +98,19 @@ const ShellInfo = new Lang.Class({
}
});
const ControlsChange = {
BEFORE_PAGE: 1,
AFTER_PAGE: 2,
DND_START: 3,
DND_END: 4
};
const Overview = new Lang.Class({
Name: 'Overview',
_init: function() {
this._overviewCreated = false;
this._initCalled = false;
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
@ -147,26 +141,28 @@ const Overview = new Lang.Class({
this._desktopFade = new St.Bin();
global.overlay_group.add_actor(this._desktopFade);
this._spacing = 0;
/* Translators: This is the main view to select
activities. See also note for "Activities" string. */
this._group = new St.Widget({ name: 'overview',
accessible_name: _("Overview"),
reactive: true });
this._group._delegate = this;
this._overview = new St.BoxLayout({ name: 'overview',
accessible_name: _("Overview"),
reactive: true,
vertical: true });
this._overview._delegate = this;
let layout = new CenterLayout.CenterLayout();
this._group = new St.Widget({ name: 'overview-group',
layout_manager: layout });
this._spacing = 0;
this._group.connect('style-changed',
Lang.bind(this, function() {
let node = this._group.get_theme_node();
let spacing = node.get_length('spacing');
if (spacing != this._spacing) {
this._spacing = spacing;
this._relayout();
}
}));
this._scrollDirection = SwipeScrollDirection.NONE;
this._scrollAdjustment = null;
this._capturedEventId = 0;
this._buttonPressId = 0;
@ -182,12 +178,11 @@ const Overview = new Lang.Class({
// Dash elements, or mouseover handlers in the workspaces.
this._coverPane = new Clutter.Rectangle({ opacity: 0,
reactive: true });
this._group.add_actor(this._coverPane);
this._overview.add_actor(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
this._group.hide();
global.overlay_group.add_actor(this._group);
this._overview.hide();
global.overlay_group.add_actor(this._overview);
this._coverPane.hide();
@ -199,11 +194,16 @@ const Overview = new Lang.Class({
Main.xdndHandler.connect('drag-begin', Lang.bind(this, this._onDragBegin));
Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
global.screen.connect('restacked', Lang.bind(this, this._onRestacked));
this._windowSwitchTimeoutId = 0;
this._windowSwitchTimestamp = 0;
this._lastActiveWorkspaceIndex = -1;
this._lastHoveredWindow = null;
this._needsFakePointerEvent = false;
if (this._initCalled)
this.init();
},
_sessionUpdated: function() {
@ -216,11 +216,20 @@ const Overview = new Lang.Class({
// signal handlers and so forth. So we create them after
// construction in this init() method.
init: function() {
this._initCalled = true;
if (this.isDummy)
return;
this._shellInfo = new ShellInfo();
// Add a clone of the panel to the overview so spacing and such is
// automatic
this._panelGhost = new St.Bin({ child: new Clutter.Clone({ source: Main.panel.actor }),
reactive: false,
opacity: 0 });
this._overview.add_actor(this._panelGhost);
this._searchEntry = new St.Entry({ name: 'searchEntry',
/* Translators: this is the text displayed
in the search entry when no search is
@ -229,16 +238,13 @@ const Overview = new Lang.Class({
hint_text: _("Type to search..."),
track_hover: true,
can_focus: true });
this._group.add_actor(this._searchEntry);
this._dash = new Dash.Dash();
this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
this._dash.showAppsButton);
this._group.add_actor(this._viewSelector.actor);
this._group.add_actor(this._dash.actor);
this._searchEntryBin = new St.Bin({ child: this._searchEntry,
x_align: St.Align.MIDDLE });
this._overview.add_actor(this._searchEntryBin);
// TODO - recalculate everything when desktop size changes
this._dash.actor.add_constraint(this._viewSelector.constrainHeight);
this._dash = new Dash.Dash();
this._group.add_actor(this._dash.actor);
this.dashIconSize = this._dash.iconSize;
this._dash.connect('icon-size-changed',
Lang.bind(this, function() {
@ -249,10 +255,99 @@ const Overview = new Lang.Class({
// the left of the overview
Main.ctrlAltTabManager.addGroup(this._dash.actor, _("Dash"), 'user-bookmarks-symbolic');
this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
this._dash.showAppsButton);
this._group.add_actor(this._viewSelector.actor);
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
this._group.add_actor(this._thumbnailsBox.actor);
Main.ctrlAltTabManager.addGroup(this._thumbnailsBox.actor, _("Workspaces"), 'view-list-symbolic');
// Add our same-line elements after the search entry
this._overview.add_actor(this._group);
// Then account for message tray
this._messageTrayGhost = new St.Bin({ child: new Clutter.Clone({ source: Main.messageTray.actor }),
reactive: false,
opacity: 0,
x_fill: true,
y_fill: true });
this._overview.add_actor(this._messageTrayGhost);
this._viewSelector.connect('after-page-change', Lang.bind(this,
function() {
this._setSideControlsVisibility(ControlsChange.AFTER_PAGE);
}));
this._viewSelector.connect('before-page-change', Lang.bind(this,
function() {
this._setSideControlsVisibility(ControlsChange.BEFORE_PAGE);
}));
this.connect('item-drag-begin', Lang.bind(this,
function() {
this._setSideControlsVisibility(ControlsChange.DND_START);
}));
this.connect('item-drag-cancelled', Lang.bind(this,
function() {
this._setSideControlsVisibility(ControlsChange.DND_END);
}));
this.connect('item-drag-end', Lang.bind(this,
function() {
this._setSideControlsVisibility(ControlsChange.DND_END);
}));
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
this._relayout();
},
_setSideControlsVisibility: function(changeType) {
// Ignore the case when we're leaving the overview, since
// actors will be made visible again when entering the overview
// next time, and animating them while doing so is just
// unnecesary noise
if (!this.visible || this.animationInProgress)
return;
let appsActive = this._viewSelector.getAppsActive();
let searchActive = this._viewSelector.getSearchActive();
let dashVisible = !searchActive || (changeType == ControlsChange.DND_START);
let thumbnailsVisible = (!searchActive && !appsActive) || (changeType == ControlsChange.DND_START);
let trayVisible = !searchActive;
let trayGhostVisible = trayVisible || dashVisible;
if ((changeType == ControlsChange.BEFORE_PAGE) ||
(changeType == ControlsChange.DND_START)) {
if (dashVisible)
this._dash.show();
if (thumbnailsVisible)
this._thumbnailsBox.show();
}
if ((changeType == ControlsChange.BEFORE_PAGE) ||
(changeType == ControlsChange.DND_END)) {
if (!dashVisible) {
this._dash.hide();
}
if (!thumbnailsVisible)
this._thumbnailsBox.hide();
}
if (changeType == ControlsChange.BEFORE_PAGE ||
changeType == ControlsChange.DND_START) {
if (trayGhostVisible)
this._messageTrayGhost.show();
if (trayVisible)
Main.messageTray.show();
else
Main.messageTray.hide();
} else if (changeType == ControlsChange.AFTER_PAGE ||
changeType == ControlsChange.DND_END) {
if (!trayGhostVisible)
this._messageTrayGhost.hide();
}
},
addSearchProvider: function(provider) {
this._viewSelector.addSearchProvider(provider);
},
@ -341,159 +436,11 @@ const Overview = new Lang.Class({
return DND.DragMotionResult.CONTINUE;
},
setScrollAdjustment: function(adjustment, direction) {
addAction: function(action) {
if (this.isDummy)
return;
this._scrollAdjustment = adjustment;
if (this._scrollAdjustment == null)
this._scrollDirection = SwipeScrollDirection.NONE;
else
this._scrollDirection = direction;
},
_onButtonPress: function(actor, event) {
if (this._scrollDirection == SwipeScrollDirection.NONE
|| event.get_button() != 1)
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 (Clutter.get_default_text_direction() == Clutter.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 = Main.layoutManager.primaryMonitor;
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 (Clutter.get_default_text_direction() == Clutter.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;
this._overview.add_action(action);
},
_getDesktopClone: function() {
@ -519,41 +466,27 @@ const Overview = new Lang.Class({
this.hide();
let primary = Main.layoutManager.primaryMonitor;
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
let contentY = Main.panel.actor.height;
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
this._group.set_position(primary.x, primary.y);
this._group.set_size(primary.width, primary.height);
this._overview.set_position(primary.x, primary.y);
this._overview.set_size(primary.width, primary.height);
this._coverPane.set_position(0, contentY);
this._coverPane.set_size(primary.width, contentHeight);
},
let searchWidth = this._searchEntry.get_width();
let searchHeight = this._searchEntry.get_height();
let searchX = (primary.width - searchWidth) / 2;
let searchY = contentY + this._spacing;
_onRestacked: function() {
let stack = global.get_window_actors();
let stackIndices = {};
let dashWidth = DASH_MAX_WIDTH;
let dashY = searchY + searchHeight + this._spacing;
let dashX;
if (rtl) {
this._dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
dashX = primary.width;
} else {
dashX = 0;
for (let i = 0; i < stack.length; i++) {
// Use the stable sequence for an integer to use as a hash key
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
}
let viewX = rtl ? 0 : dashWidth + this._spacing;
let viewY = searchY + searchHeight + this._spacing;
let viewWidth = primary.width - dashWidth - this._spacing;
let viewHeight = contentHeight - this._spacing - viewY;
this._searchEntry.set_position(searchX, searchY);
this._dash.actor.set_position(dashX, dashY);
this._viewSelector.actor.set_position(viewX, viewY);
this._viewSelector.actor.set_size(viewWidth, viewHeight);
this.emit('sync-window-stacking', stackIndices);
},
//// Public methods ////
@ -590,15 +523,11 @@ const Overview = new Lang.Class({
return;
if (this._shown)
return;
// Do this manually instead of using _syncInputMode, to handle failure
if (!Main.pushModal(this._group, { keybindingMode: Main.KeybindingMode.OVERVIEW }))
return;
this._modal = true;
this._animateVisible();
this._shown = true;
this._buttonPressId = this._group.connect('button-press-event',
Lang.bind(this, this._onButtonPress));
this._syncInputMode();
if (!this._modal)
return;
this._animateVisible();
},
fadeInDesktop: function() {
@ -641,12 +570,13 @@ const Overview = new Lang.Class({
// Disable unredirection while in the overview
Meta.disable_unredirect_for_screen(global.screen);
global.window_group.hide();
this._group.show();
this._messageTrayGhost.show();
this._overview.show();
this._background.show();
this._viewSelector.show();
this._group.opacity = 0;
Tweener.addTween(this._group,
this._overview.opacity = 0;
Tweener.addTween(this._overview,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
@ -698,10 +628,6 @@ const Overview = new Lang.Class({
this._shown = false;
this._syncInputMode();
if (this._buttonPressId > 0)
this._group.disconnect(this._buttonPressId);
this._buttonPressId = 0;
},
// hideTemporarily:
@ -725,7 +651,7 @@ const Overview = new Lang.Class({
if (this.isDummy)
return;
if (this._shown)
if (this.visible)
this.hide();
else
this.show();
@ -742,7 +668,7 @@ const Overview = new Lang.Class({
if (this._shown) {
if (!this._modal) {
if (Main.pushModal(this._group,
if (Main.pushModal(this._overview,
{ keybindingMode: Main.KeybindingMode.OVERVIEW }))
this._modal = true;
else
@ -750,13 +676,13 @@ const Overview = new Lang.Class({
}
} else if (this._shownTemporarily) {
if (this._modal) {
Main.popModal(this._group);
Main.popModal(this._overview);
this._modal = false;
}
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
} else {
if (this._modal) {
Main.popModal(this._group);
Main.popModal(this._overview);
this._modal = false;
}
else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
@ -774,7 +700,7 @@ const Overview = new Lang.Class({
this._viewSelector.zoomFromOverview();
// Make other elements fade out.
Tweener.addTween(this._group,
Tweener.addTween(this._overview,
{ opacity: 0,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
@ -816,7 +742,7 @@ const Overview = new Lang.Class({
this._viewSelector.hide();
this._desktopFade.hide();
this._background.hide();
this._group.hide();
this._overview.hide();
this.visible = false;
this.animationInProgress = false;

View File

@ -15,6 +15,7 @@ const Signals = imports.signals;
const Atk = imports.gi.Atk;
const CenterLayout = imports.ui.centerLayout;
const Config = imports.misc.config;
const CtrlAltTab = imports.ui.ctrlAltTab;
const DND = imports.ui.dnd;
@ -599,11 +600,12 @@ const AppMenuButton = new Lang.Class({
menu = new PopupMenu.RemoteMenu(this.actor, this._targetApp.menu, this._targetApp.action_group);
} else {
if (this.menu && !(this.menu instanceof PopupMenu.RemoteMenu))
if (this.menu.isDummyQuitMenu)
return;
// fallback to older menu
menu = new PopupMenu.PopupMenu(this.actor, 0.0, St.Side.TOP, 0);
menu.isDummyQuitMenu = true;
menu.addAction(_("Quit"), Lang.bind(this, function() {
this._targetApp.request_quit();
}));
@ -616,15 +618,12 @@ const AppMenuButton = new Lang.Class({
Signals.addSignalMethods(AppMenuButton.prototype);
// Activities button. Because everything else in the top bar is a
// PanelMenu.Button, it simplifies some things to make this be one too.
// We just hack it up to not actually have a menu attached to it.
const ActivitiesButton = new Lang.Class({
Name: 'ActivitiesButton',
Extends: PanelMenu.Button,
_init: function() {
this.parent(0.0);
this.parent(0.0, null, true);
this.actor.accessible_role = Atk.Role.TOGGLE_BUTTON;
let container = new Shell.GenericContainer();
@ -644,27 +643,27 @@ const ActivitiesButton = new Lang.Class({
this.hotCorner = new Layout.HotCorner();
container.add_actor(this.hotCorner.actor);
// Hack up our menu...
this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
this.menu.close = Lang.bind(this, this._onMenuCloseRequest);
this.menu.toggle = Lang.bind(this, this._onMenuToggleRequest);
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this.actor.connect_after('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect_after('key-release-event', Lang.bind(this, this._onKeyRelease));
Main.overview.connect('showing', Lang.bind(this, function() {
this.actor.add_style_pseudo_class('overview');
this._escapeMenuGrab();
this.actor.add_accessible_state (Atk.StateType.CHECKED);
}));
Main.overview.connect('hiding', Lang.bind(this, function() {
this.actor.remove_style_pseudo_class('overview');
this._escapeMenuGrab();
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
}));
this._xdndTimeOut = 0;
// Since the hot corner uses stage coordinates, Clutter won't
// queue relayouts for us when the panel moves. Queue a relayout
// when that happens.
Main.layoutManager.connect('panel-box-changed', Lang.bind(this, function() {
container.queue_relayout();
}));
},
_containerGetPreferredWidth: function(actor, forHeight, alloc) {
@ -710,11 +709,6 @@ const ActivitiesButton = new Lang.Class({
return DND.DragMotionResult.CONTINUE;
},
_escapeMenuGrab: function() {
if (this.menu.isOpen)
this.menu.close();
},
_onCapturedEvent: function(actor, event) {
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
if (!this.hotCorner.shouldToggleOverviewOnClick())
@ -723,33 +717,13 @@ const ActivitiesButton = new Lang.Class({
return false;
},
_onMenuOpenRequest: function() {
this.menu.isOpen = true;
this.menu.emit('open-state-changed', true);
},
_onMenuCloseRequest: function() {
this.menu.isOpen = false;
this.menu.emit('open-state-changed', false);
},
_onMenuToggleRequest: function() {
this.menu.isOpen = !this.menu.isOpen;
this.menu.emit('open-state-changed', this.menu.isOpen);
},
_onButtonRelease: function() {
if (this.menu.isOpen) {
this.menu.close();
Main.overview.toggle();
}
Main.overview.toggle();
},
_onKeyRelease: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
if (this.menu.isOpen)
this.menu.close();
Main.overview.toggle();
}
},
@ -964,12 +938,47 @@ try {
log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
}
const PanelLayout = new Lang.Class({
Name: 'PanelLayout',
Extends: CenterLayout.CenterLayout,
vfunc_allocate: function(container, box, flags) {
this.parent(container, box, flags);
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [left, center, right, leftCorner, rightCorner] = container.get_children();
let childBox = new Clutter.ActorBox();
let cornerMinWidth, cornerMinHeight;
let cornerWidth, cornerHeight;
[cornerMinWidth, cornerWidth] = leftCorner.get_preferred_width(-1);
[cornerMinHeight, cornerHeight] = leftCorner.get_preferred_height(-1);
childBox.x1 = 0;
childBox.x2 = cornerWidth;
childBox.y1 = availHeight;
childBox.y2 = availHeight + cornerHeight;
leftCorner.allocate(childBox, flags);
[cornerMinWidth, cornerWidth] = rightCorner.get_preferred_width(-1);
[cornerMinHeight, cornerHeight] = rightCorner.get_preferred_height(-1);
childBox.x1 = availWidth - cornerWidth;
childBox.x2 = availWidth;
childBox.y1 = availHeight;
childBox.y2 = availHeight + cornerHeight;
rightCorner.allocate(childBox, flags);
}
});
const Panel = new Lang.Class({
Name: 'Panel',
_init : function() {
this.actor = new Shell.GenericContainer({ name: 'panel',
reactive: true });
this.actor = new St.Widget({ name: 'panel',
reactive: true,
layoutManager: new PanelLayout() });
this.actor._delegate = this;
this._sessionStyle = null;
@ -989,7 +998,6 @@ const Panel = new Lang.Class({
this._leftCorner = new PanelCorner(this._rightBox, St.Side.LEFT);
else
this._leftCorner = new PanelCorner(this._leftBox, St.Side.LEFT);
this.actor.add_actor(this._leftCorner.actor);
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
@ -998,9 +1006,6 @@ const Panel = new Lang.Class({
this._rightCorner = new PanelCorner(this._rightBox, St.Side.RIGHT);
this.actor.add_actor(this._rightCorner.actor);
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('button-press-event', Lang.bind(this, this._onButtonPress));
Main.layoutManager.panelBox.add(this.actor);
@ -1011,83 +1016,6 @@ const Panel = new Lang.Class({
this._updatePanel();
},
_getPreferredWidth: function(actor, forHeight, alloc) {
alloc.min_size = -1;
alloc.natural_size = Main.layoutManager.primaryMonitor.width;
},
_getPreferredHeight: function(actor, forWidth, alloc) {
// We don't need to implement this; it's forced by the CSS
alloc.min_size = -1;
alloc.natural_size = -1;
},
_allocate: function(actor, box, flags) {
let allocWidth = box.x2 - box.x1;
let allocHeight = box.y2 - box.y1;
let [leftMinWidth, leftNaturalWidth] = this._leftBox.get_preferred_width(-1);
let [centerMinWidth, centerNaturalWidth] = this._centerBox.get_preferred_width(-1);
let [rightMinWidth, rightNaturalWidth] = this._rightBox.get_preferred_width(-1);
let sideWidth, centerWidth;
centerWidth = centerNaturalWidth;
sideWidth = (allocWidth - centerWidth) / 2;
let childBox = new Clutter.ActorBox();
childBox.y1 = 0;
childBox.y2 = allocHeight;
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth),
leftNaturalWidth);
childBox.x2 = allocWidth;
} else {
childBox.x1 = 0;
childBox.x2 = Math.min(Math.floor(sideWidth),
leftNaturalWidth);
}
this._leftBox.allocate(childBox, flags);
childBox.x1 = Math.ceil(sideWidth);
childBox.y1 = 0;
childBox.x2 = childBox.x1 + centerWidth;
childBox.y2 = allocHeight;
this._centerBox.allocate(childBox, flags);
childBox.y1 = 0;
childBox.y2 = allocHeight;
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
childBox.x1 = 0;
childBox.x2 = Math.min(Math.floor(sideWidth),
rightNaturalWidth);
} else {
childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth),
rightNaturalWidth);
childBox.x2 = allocWidth;
}
this._rightBox.allocate(childBox, flags);
let cornerMinWidth, cornerMinHeight;
let cornerWidth, cornerHeight;
[cornerMinWidth, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1);
[cornerMinHeight, cornerHeight] = this._leftCorner.actor.get_preferred_height(-1);
childBox.x1 = 0;
childBox.x2 = cornerWidth;
childBox.y1 = allocHeight;
childBox.y2 = allocHeight + cornerHeight;
this._leftCorner.actor.allocate(childBox, flags);
[cornerMinWidth, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1);
[cornerMinHeight, cornerHeight] = this._rightCorner.actor.get_preferred_height(-1);
childBox.x1 = allocWidth - cornerWidth;
childBox.x2 = allocWidth;
childBox.y1 = allocHeight;
childBox.y2 = allocHeight + cornerHeight;
this._rightCorner.actor.allocate(childBox, flags);
},
_onButtonPress: function(actor, event) {
if (event.get_source() != actor)
return false;

View File

@ -112,7 +112,7 @@ const Button = new Lang.Class({
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
if (dontCreateMenu)
this.menu = null;
this.menu = new PopupMenu.PopupDummyMenu(this.actor);
else
this.setMenu(new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0));

View File

@ -1,6 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
@ -12,8 +11,10 @@ const St = imports.gi.St;
const Atk = imports.gi.Atk;
const BoxPointer = imports.ui.boxpointer;
const GrabHelper = imports.ui.grabHelper;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Separator = imports.ui.separator;
const Tweener = imports.ui.tweener;
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
@ -404,29 +405,8 @@ const PopupSeparatorMenuItem = new Lang.Class({
this.parent({ reactive: false,
can_focus: false});
this._drawingArea = new St.DrawingArea({ style_class: 'popup-separator-menu-item' });
this.addActor(this._drawingArea, { span: -1, expand: true });
this._drawingArea.connect('repaint', Lang.bind(this, this._onRepaint));
},
_onRepaint: function(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let margin = themeNode.get_length('-margin-horizontal');
let gradientHeight = themeNode.get_length('-gradient-height');
let startColor = themeNode.get_color('-gradient-start');
let endColor = themeNode.get_color('-gradient-end');
let gradientWidth = (width - margin * 2);
let gradientOffset = (height - gradientHeight) / 2;
let pattern = new Cairo.LinearGradient(margin, gradientOffset, width - margin, gradientOffset + gradientHeight);
pattern.addColorStopRGBA(0, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
pattern.addColorStopRGBA(0.5, endColor.red / 255, endColor.green / 255, endColor.blue / 255, endColor.alpha / 255);
pattern.addColorStopRGBA(1, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
cr.setSource(pattern);
cr.rectangle(margin, gradientOffset, gradientWidth, gradientHeight);
cr.fill();
this._separator = new Separator.HorizontalSeparator({ style_class: 'popup-separator-menu-item' });
this.addActor(this._separator.actor, { span: -1, expand: true });
}
});
@ -1204,7 +1184,6 @@ const PopupMenu = new Lang.Class({
this.actor = this._boxPointer.actor;
this.actor._delegate = this;
this.actor.style_class = 'popup-menu-boxpointer';
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this._boxWrapper = new Shell.GenericContainer();
this._boxWrapper.connect('get-preferred-width', Lang.bind(this, this._boxGetPreferredWidth));
@ -1234,15 +1213,6 @@ const PopupMenu = new Lang.Class({
this.box.allocate(box, flags);
},
_onKeyPressEvent: function(actor, event) {
if (event.get_key_symbol() == Clutter.Escape) {
this.close(BoxPointer.PopupAnimation.FULL);
return true;
}
return false;
},
setArrowOrigin: function(origin) {
this._boxPointer.setArrowOrigin(origin);
},
@ -1283,6 +1253,28 @@ const PopupMenu = new Lang.Class({
}
});
const PopupDummyMenu = new Lang.Class({
Name: 'PopupDummyMenu',
_init: function(sourceActor) {
this.sourceActor = sourceActor;
this.actor = sourceActor;
this.actor._delegate = this;
},
isChildMenu: function() {
return false;
},
open: function() { this.emit('open-state-changed', true); },
close: function() { this.emit('open-state-changed', false); },
toggle: function() {},
destroy: function() {
this.emit('destroy');
},
});
Signals.addSignalMethods(PopupDummyMenu.prototype);
const PopupSubMenu = new Lang.Class({
Name: 'PopupSubMenu',
Extends: PopupMenuBase,
@ -1537,7 +1529,6 @@ const PopupComboMenu = new Lang.Class({
this.actor = this.box;
this.actor._delegate = this;
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
sourceActor.connect('style-changed',
Lang.bind(this, this._onSourceActorStyleChanged));
@ -1545,15 +1536,6 @@ const PopupComboMenu = new Lang.Class({
global.focus_manager.add_group(this.actor);
},
_onKeyPressEvent: function(actor, event) {
if (event.get_key_symbol() == Clutter.Escape) {
this.close(BoxPointer.PopupAnimation.FULL);
return true;
}
return false;
},
_onKeyFocusIn: function(actor) {
let items = this._getMenuItems();
let activeItem = items[this._activeItemPos];
@ -2044,17 +2026,8 @@ const PopupMenuManager = new Lang.Class({
_init: function(owner) {
this._owner = owner;
this.grabbed = false;
this._eventCaptureId = 0;
this._enterEventId = 0;
this._leaveEventId = 0;
this._keyFocusNotifyId = 0;
this._activeMenu = null;
this._grabHelper = new GrabHelper.GrabHelper(owner.actor);
this._menus = [];
this._menuStack = [];
this._preGrabInputMode = null;
this._grabbedFromKeynav = false;
},
addMenu: function(menu, position) {
@ -2073,6 +2046,8 @@ const PopupMenuManager = new Lang.Class({
let source = menu.sourceActor;
if (source) {
if (!menu.blockSourceEvents)
this._grabHelper.addActor(source);
menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
menudata.focusInId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
}
@ -2085,7 +2060,7 @@ const PopupMenuManager = new Lang.Class({
removeMenu: function(menu) {
if (menu == this._activeMenu)
this._closeMenu();
this._closeMenu(menu);
let position = this._findMenu(menu);
if (position == -1) // not a menu we manage
@ -2102,79 +2077,29 @@ const PopupMenuManager = new Lang.Class({
if (menudata.focusInId)
menu.sourceActor.disconnect(menudata.focusInId);
if (menu.sourceActor)
this._grabHelper.removeActor(menu.sourceActor);
this._menus.splice(position, 1);
},
_grab: function() {
Main.pushModal(this._owner.actor);
this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
// captured-event doesn't see enter/leave events
this._enterEventId = global.stage.connect('enter-event', Lang.bind(this, this._onEventCapture));
this._leaveEventId = global.stage.connect('leave-event', Lang.bind(this, this._onEventCapture));
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
this.grabbed = true;
get activeMenu() {
let actor = this._grabHelper.currentGrab.actor;
if (actor)
return actor._delegate;
else
return null;
},
_ungrab: function() {
global.stage.disconnect(this._eventCaptureId);
this._eventCaptureId = 0;
global.stage.disconnect(this._enterEventId);
this._enterEventId = 0;
global.stage.disconnect(this._leaveEventId);
this._leaveEventId = 0;
global.stage.disconnect(this._keyFocusNotifyId);
this._keyFocusNotifyId = 0;
this.grabbed = false;
Main.popModal(this._owner.actor);
ignoreRelease: function() {
return this._grabHelper.ignoreRelease();
},
_onMenuOpenState: function(menu, open) {
if (open) {
if (this._activeMenu && this._activeMenu.isChildMenu(menu)) {
this._menuStack.push(this._activeMenu);
menu.actor.grab_key_focus();
}
this._activeMenu = menu;
this._grabHelper.grab({ actor: menu.actor, modal: true, focus: menu.sourceActor,
onUngrab: Lang.bind(this, this._closeMenu, menu) });
} else {
if (this._menuStack.length > 0) {
this._activeMenu = this._menuStack.pop();
if (menu.sourceActor)
menu.sourceActor.grab_key_focus();
this._didPop = true;
}
}
// Check what the focus was before calling pushModal/popModal
let focus = global.stage.key_focus;
let hadFocus = focus && this._activeMenuContains(focus);
if (open) {
if (!this.grabbed) {
this._preGrabInputMode = global.stage_input_mode;
this._grabbedFromKeynav = hadFocus;
this._grab();
}
if (hadFocus)
focus.grab_key_focus();
else
menu.actor.grab_key_focus();
} else if (menu == this._activeMenu) {
if (this.grabbed)
this._ungrab();
this._activeMenu = null;
if (this._grabbedFromKeynav) {
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED)
global.stage_input_mode = Shell.StageInputMode.FOCUSED;
if (hadFocus && menu.sourceActor)
menu.sourceActor.grab_key_focus();
else if (focus)
focus.grab_key_focus();
}
this._grabHelper.ungrab({ actor: menu.actor });
}
},
@ -2186,87 +2111,38 @@ const PopupMenuManager = new Lang.Class({
this.removeMenu(childMenu);
},
// change the currently-open menu without dropping grab
_changeMenu: function(newMenu) {
if (this._activeMenu) {
// _onOpenMenuState will drop the grab if it sees
// this._activeMenu being closed; so clear _activeMenu
// before closing it to keep that from happening
let oldMenu = this._activeMenu;
this._activeMenu = null;
for (let i = this._menuStack.length - 1; i >= 0; i--)
this._menuStack[i].close(BoxPointer.PopupAnimation.FADE);
let oldMenu = this.activeMenu;
if (oldMenu) {
oldMenu.close(BoxPointer.PopupAnimation.FADE);
newMenu.open(BoxPointer.PopupAnimation.FADE);
} else
} else {
newMenu.open(BoxPointer.PopupAnimation.FULL);
}
},
_onMenuSourceEnter: function(menu) {
if (!this.grabbed || menu == this._activeMenu)
if (!this._grabHelper.grabbed)
return false;
if (this._activeMenu && this._activeMenu.isChildMenu(menu))
if (this._grabHelper.isActorGrabbed(menu.actor))
return false;
if (this._menuStack.indexOf(menu) != -1)
return false;
if (this._menuStack.length > 0 && this._menuStack[0].isChildMenu(menu))
let isChildMenu = this._grabHelper.grabStack.some(function(grab) {
let existingMenu = grab.actor._delegate;
return existingMenu.isChildMenu(menu);
});
if (isChildMenu)
return false;
this._changeMenu(menu);
return false;
},
_onKeyFocusChanged: function() {
if (!this.grabbed || !this._activeMenu)
return;
let focus = global.stage.key_focus;
if (focus) {
if (this._activeMenuContains(focus))
return;
if (this._menuStack.length > 0)
return;
if (focus._delegate && focus._delegate.menu &&
this._findMenu(focus._delegate.menu) != -1)
return;
}
this._closeMenu();
},
_onMenuDestroy: function(menu) {
this.removeMenu(menu);
},
_activeMenuContains: function(actor) {
return this._activeMenu != null
&& (this._activeMenu.actor.contains(actor) ||
(this._activeMenu.sourceActor && this._activeMenu.sourceActor.contains(actor)));
},
_eventIsOnActiveMenu: function(event) {
return this._activeMenuContains(event.get_source());
},
_shouldBlockEvent: function(event) {
let src = event.get_source();
if (this._activeMenu != null && this._activeMenu.actor.contains(src))
return false;
for (let i = 0; i < this._menus.length; i++) {
let menu = this._menus[i].menu;
if (menu.sourceActor && !menu.blockSourceEvents && menu.sourceActor.contains(src)) {
return false;
}
}
return true;
},
_findMenu: function(item) {
for (let i = 0; i < this._menus.length; i++) {
let menudata = this._menus[i];
@ -2276,41 +2152,11 @@ const PopupMenuManager = new Lang.Class({
return -1;
},
_onEventCapture: function(actor, event) {
if (!this.grabbed)
return false;
if (this._owner.menuEventFilter &&
this._owner.menuEventFilter(event))
return true;
if (this._didPop) {
this._didPop = false;
return true;
}
let activeMenuContains = this._eventIsOnActiveMenu(event);
let eventType = event.type();
if (eventType == Clutter.EventType.BUTTON_RELEASE) {
if (activeMenuContains) {
return false;
} else {
this._closeMenu();
return true;
}
} else if (eventType == Clutter.EventType.BUTTON_PRESS && !activeMenuContains) {
this._closeMenu();
return true;
} else if (!this._shouldBlockEvent(event)) {
return false;
}
return true;
},
_closeMenu: function() {
if (this._activeMenu != null)
this._activeMenu.close(BoxPointer.PopupAnimation.FULL);
_closeMenu: function(isUser, menu) {
// If this isn't a user action, we called close()
// on the BoxPointer ourselves, so we shouldn't
// reanimate.
if (isUser)
menu.close(BoxPointer.PopupAnimation.FULL);
}
});

View File

@ -29,93 +29,96 @@ const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
</method>
</interface>;
const SearchProvider2Iface = <interface name="org.gnome.Shell.SearchProvider2">
<method name="GetInitialResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetSubsearchResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetResultMetas">
<arg type="as" direction="in" />
<arg type="aa{sv}" direction="out" />
</method>
<method name="ActivateResult">
<arg type="s" direction="in" />
<arg type="as" direction="in" />
<arg type="u" direction="in" />
</method>
<method name="LaunchSearch">
<arg type="as" direction="in" />
<arg type="u" direction="in" />
</method>
</interface>;
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
var SearchProvider2Proxy = Gio.DBusProxy.makeProxyWrapper(SearchProvider2Iface);
function loadRemoteSearchProviders(addProviderCallback) {
let loadState = { loadedProviders: [],
objectPaths: {},
numLoading: 0,
addProviderCallback: addProviderCallback };
let data = { loadedProviders: [],
objectPaths: {},
addProviderCallback: addProviderCallback };
FileUtils.collectFromDatadirsAsync('search-providers',
{ loadedCallback: remoteProvidersLoaded,
processFile: loadRemoteSearchProvider,
data: data
});
}
let dataDirs = GLib.get_system_data_dirs();
for (let i = 0; i < dataDirs.length; i++) {
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'search-providers']);
let dir = Gio.file_new_for_path(path);
function loadRemoteSearchProvider(file, info, data) {
let keyfile = new GLib.KeyFile();
let path = file.get_path();
dir.query_info_async('standard:type', Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_DEFAULT, null,
function(object, res) {
let exists = false;
try {
object.query_info_finish(res);
exists = true;
} catch (e) {
}
if (!exists)
return;
loadState.numLoading++;
loadRemoteSearchProvidersFromDir(dir, loadState);
});
try {
keyfile.load_from_file(path, 0);
} catch(e) {
return;
}
};
function loadRemoteSearchProvidersFromDir(dir, loadState) {
let dirPath = dir.get_path();
FileUtils.listDirAsync(dir, Lang.bind(this, function(files) {
for (let i = 0; i < files.length; i++) {
let keyfile = new GLib.KeyFile();
let path = GLib.build_filenamev([dirPath, files[i].get_name()]);
try {
keyfile.load_from_file(path, 0);
} catch(e) {
continue;
}
if (!keyfile.has_group(KEY_FILE_GROUP))
continue;
let remoteProvider;
try {
let group = KEY_FILE_GROUP;
let busName = keyfile.get_string(group, 'BusName');
let objectPath = keyfile.get_string(group, 'ObjectPath');
if (loadState.objectPaths[objectPath])
continue;
let appInfo = null;
try {
let desktopId = keyfile.get_string(group, 'DesktopId');
appInfo = Gio.DesktopAppInfo.new(desktopId);
} catch (e) {
log('Ignoring search provider ' + path + ': missing DesktopId');
continue;
}
remoteProvider = new RemoteSearchProvider(appInfo,
busName,
objectPath);
loadState.objectPaths[objectPath] = remoteProvider;
loadState.loadedProviders.push(remoteProvider);
} catch(e) {
log('Failed to add search provider %s: %s'.format(path, e.toString()));
continue;
}
}
remoteProvidersDirLoaded(loadState);
}));
};
function remoteProvidersDirLoaded(loadState) {
loadState.numLoading--;
if (loadState.numLoading > 0)
if (!keyfile.has_group(KEY_FILE_GROUP))
return;
let remoteProvider;
try {
let group = KEY_FILE_GROUP;
let busName = keyfile.get_string(group, 'BusName');
let objectPath = keyfile.get_string(group, 'ObjectPath');
if (data.objectPaths[objectPath])
return;
let appInfo = null;
try {
let desktopId = keyfile.get_string(group, 'DesktopId');
appInfo = Gio.DesktopAppInfo.new(desktopId);
} catch (e) {
log('Ignoring search provider ' + path + ': missing DesktopId');
return;
}
let version = '1';
try {
version = keyfile.get_string(group, 'Version');
} catch (e) {
// ignore error
}
if (version >= 2)
remoteProvider = new RemoteSearchProvider2(appInfo, busName, objectPath);
else
remoteProvider = new RemoteSearchProvider(appInfo, busName, objectPath);
data.objectPaths[objectPath] = remoteProvider;
data.loadedProviders.push(remoteProvider);
} catch(e) {
log('Failed to add search provider %s: %s'.format(path, e.toString()));
}
}
function remoteProvidersLoaded(loadState) {
let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
let sortOrder = searchSettings.get_strv('sort-order');
let numSorted = sortOrder.length;
@ -164,13 +167,18 @@ function remoteProvidersDirLoaded(loadState) {
const RemoteSearchProvider = new Lang.Class({
Name: 'RemoteSearchProvider',
Extends: Search.SearchProvider,
_init: function(appInfo, dbusName, dbusPath) {
this._proxy = new SearchProviderProxy(Gio.DBus.session,
dbusName, dbusPath, Lang.bind(this, this._onProxyConstructed));
_init: function(appInfo, dbusName, dbusPath, proxyType) {
if (!proxyType)
proxyType = SearchProviderProxy;
this.proxy = new proxyType(Gio.DBus.session,
dbusName, dbusPath, Lang.bind(this, this._onProxyConstructed));
this.appInfo = appInfo;
this.id = appInfo.get_id();
this.isRemoteProvider = true;
this.parent(appInfo.get_name().toUpperCase(), appInfo, true);
this._cancellable = new Gio.Cancellable();
},
@ -190,9 +198,7 @@ const RemoteSearchProvider = new Lang.Class({
width, height, rowStride, size);
}
// Ugh, but we want to fall back to something ...
return new St.Icon({ icon_name: 'text-x-generic',
icon_size: size });
return null;
},
_getResultsFinished: function(results, error) {
@ -205,9 +211,9 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable.cancel();
this._cancellable.reset();
try {
this._proxy.GetInitialResultSetRemote(terms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
this.proxy.GetInitialResultSetRemote(terms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
} catch(e) {
log('Error calling GetInitialResultSet for provider %s: %s'.format( this.title, e.toString()));
this.searchSystem.pushResults(this, []);
@ -218,9 +224,9 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable.cancel();
this._cancellable.reset();
try {
this._proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
this.proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
} catch(e) {
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.title, e.toString()));
this.searchSystem.pushResults(this, []);
@ -249,9 +255,9 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable.cancel();
this._cancellable.reset();
try {
this._proxy.GetResultMetasRemote(ids,
Lang.bind(this, this._getResultMetasFinished, callback),
this._cancellable);
this.proxy.GetResultMetasRemote(ids,
Lang.bind(this, this._getResultMetasFinished, callback),
this._cancellable);
} catch(e) {
log('Error calling GetResultMetas for provider %s: %s'.format(this.title, e.toString()));
callback([]);
@ -259,8 +265,32 @@ const RemoteSearchProvider = new Lang.Class({
},
activateResult: function(id) {
this._proxy.ActivateResultRemote(id);
this.proxy.ActivateResultRemote(id);
},
launchSearch: function(terms) {
// the provider is not compatible with the new version of the interface, launch
// the app itself but warn so we can catch the error in logs
log('Search provider ' + this.appInfo.get_id() + ' does not implement LaunchSearch');
this.appInfo.launch([], global.create_app_launch_context());
}
});
const RemoteSearchProvider2 = new Lang.Class({
Name: 'RemoteSearchProvider2',
Extends: RemoteSearchProvider,
_init: function(appInfo, dbusName, dbusPath) {
this.parent(appInfo, dbusName, dbusPath, SearchProvider2Proxy);
this.canLaunchSearch = true;
},
activateResult: function(id, terms) {
this.proxy.ActivateResultRemote(id, terms, global.get_current_time());
},
launchSearch: function(terms) {
this.proxy.LaunchSearchRemote(terms, global.get_current_time());
}
});

View File

@ -308,6 +308,7 @@ const NotificationsBox = new Lang.Class({
obj.item.disconnect(obj.contentUpdatedId);
obj.source.disconnect(obj.sourceDestroyId);
obj.source.disconnect(obj.sourceCountChangedId);
obj.source.disconnect(obj.sourceTitleChangedId);
},
});

View File

@ -1,176 +1,10 @@
// -*- mode: js; js-indent-level: 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 FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
// Not currently referenced by the search API, but
// this enumeration can be useful for provider
// implementations.
const MatchType = {
NONE: 0,
SUBSTRING: 1,
PREFIX: 2
};
const SearchResultDisplay = new Lang.Class({
Name: 'SearchResultDisplay',
_init: function(provider) {
this.provider = provider;
this.actor = null;
},
/**
* renderResults:
* @results: List of identifier strings
* @terms: List of search term strings
*
* Display the given search matches which resulted
* from the given terms. It's expected that not
* all results will fit in the space for the container
* actor; in this case, show as many as makes sense
* for your result type.
*
* The terms are useful for search match highlighting.
*/
renderResults: function(results, terms) {
throw new Error('Not implemented');
},
/**
* clear:
* Remove all results from this display.
*/
clear: function() {
this.actor.destroy_all_children();
},
/**
* getVisibleResultCount:
*
* Returns: The number of actors visible.
*/
getVisibleResultCount: function() {
throw new Error('Not implemented');
},
});
/**
* SearchProvider:
*
* Subclass this object to add a new result type
* to the search system, then call registerProvider()
* in SearchSystem with an instance.
* Search is asynchronous and uses the
* getInitialResultSet()/getSubsearchResultSet() methods.
*/
const SearchProvider = new Lang.Class({
Name: 'SearchProvider',
_init: function(title, appInfo, isRemoteProvider) {
this.title = title;
this.appInfo = appInfo;
this.searchSystem = null;
this.isRemoteProvider = !!isRemoteProvider;
},
/**
* getInitialResultSet:
* @terms: Array of search terms, treated as logical AND
*
* Called when the user first begins a search (most likely
* therefore a single term of length one or two), or when
* a new term is added.
*
* Should "return" an array of result identifier strings representing
* items which match the given search terms. This
* is expected to be a substring match on the metadata for a given
* item. Ordering of returned results is up to the discretion of the provider,
* but you should follow these heruistics:
*
* * Put items where the term matches multiple criteria (e.g. name and
* description) before single matches
* * Put items which match on a prefix before non-prefix substring matches
*
* We say "return" above, but in order to make the query asynchronous, use
* this.searchSystem.pushResults();. The return value should be ignored.
*
* This function should be fast; do not perform unindexed full-text searches
* or network queries.
*/
getInitialResultSet: function(terms) {
throw new Error('Not implemented');
},
/**
* getSubsearchResultSet:
* @previousResults: Array of item identifiers
* @newTerms: Updated search terms
*
* Called when a search is performed which is a "subsearch" of
* the previous search; i.e. when every search term has exactly
* one corresponding term in the previous search which is a prefix
* of the new term.
*
* This allows search providers to only search through the previous
* result set, rather than possibly performing a full re-query.
*
* Similar to getInitialResultSet, the return value for this will
* be ignored; use this.searchSystem.pushResults();.
*/
getSubsearchResultSet: function(previousResults, newTerms) {
throw new Error('Not implemented');
},
/**
* getResultMetas:
* @ids: Result identifier strings
*
* Call callback with array of objects with 'id', 'name', (both strings) and
* 'createIcon' (function(size) returning a Clutter.Texture) properties
* with the same number of members as @ids
*/
getResultMetas: function(ids, callback) {
throw new Error('Not implemented');
},
/**
* createResultActor:
* @resultMeta: Object with result metadata
* @terms: Array of search terms, should be used for highlighting
*
* Search providers may optionally override this to render a
* particular serch result in a custom fashion. The default
* implementation will show the icon next to the name.
*
* The actor should be an instance of St.Widget, with the style class
* 'search-result-content'.
*/
createResultActor: function(resultMeta, terms) {
return null;
},
/**
* activateResult:
* @id: Result identifier string
*
* Called when the user chooses a given result.
*/
activateResult: function(id) {
throw new Error('Not implemented');
}
});
Signals.addSignalMethods(SearchProvider.prototype);
const SearchSystem = new Lang.Class({
Name: 'SearchSystem',
@ -262,7 +96,7 @@ const SearchSystem = new Lang.Class({
results.push([provider, []]);
provider.getSubsearchResultSet(previousResults, terms);
} catch (error) {
log('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
log('A ' + error.name + ' has occured in ' + provider.id + ': ' + error.message);
}
}
} else {
@ -272,7 +106,7 @@ const SearchSystem = new Lang.Class({
results.push([provider, []]);
provider.getInitialResultSet(terms);
} catch (error) {
log('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
log('A ' + error.name + ' has occured in ' + provider.id + ': ' + error.message);
}
}
}

View File

@ -11,10 +11,11 @@ const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Separator = imports.ui.separator;
const Search = imports.ui.search;
const MAX_SEARCH_RESULTS_ROWS = 1;
const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
const SearchResult = new Lang.Class({
Name: 'SearchResult',
@ -22,33 +23,103 @@ const SearchResult = new Lang.Class({
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
this.actor = new St.Button({ style_class: 'search-result',
reactive: true,
this.terms = terms;
this.actor = new St.Button({ reactive: true,
can_focus: true,
track_hover: true,
x_align: St.Align.START,
y_fill: true });
this.actor._delegate = this;
this._dragActorSource = null;
this.actor.connect('clicked', Lang.bind(this, this.activate));
},
activate: function() {
this.provider.activateResult(this.metaInfo.id, this.terms);
Main.overview.toggle();
},
setSelected: function(selected) {
if (selected)
this.actor.add_style_pseudo_class('selected');
else
this.actor.remove_style_pseudo_class('selected');
}
});
const ListSearchResult = new Lang.Class({
Name: 'ListSearchResult',
Extends: SearchResult,
ICON_SIZE: 64,
_init: function(provider, metaInfo, terms) {
this.parent(provider, metaInfo, terms);
this.actor.style_class = 'list-search-result';
this.actor.x_fill = true;
let content = new St.BoxLayout({ style_class: 'list-search-result-content',
vertical: false });
this.actor.set_child(content);
// An icon for, or thumbnail of, content
let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
if (icon) {
content.add(icon);
}
let details = new St.BoxLayout({ vertical: true });
content.add(details, { x_fill: true,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
let title = new St.Label({ style_class: 'list-search-result-title',
text: this.metaInfo['name'] })
details.add(title, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
// TODO: should highlight terms in the description here
if (this.metaInfo['description']) {
let description = new St.Label({ style_class: 'list-search-result-description',
text: '"' + this.metaInfo['description'] + '"' });
details.add(description, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.END });
}
}
});
const GridSearchResult = new Lang.Class({
Name: 'GridSearchResult',
Extends: SearchResult,
_init: function(provider, metaInfo, terms) {
this.parent(provider, metaInfo, terms);
this.actor.style_class = 'grid-search-result';
let content = provider.createResultActor(metaInfo, terms);
let dragSource = null;
if (content == null) {
content = new St.Bin({ style_class: 'search-result-content',
reactive: true,
can_focus: true,
track_hover: true,
accessible_role: Atk.Role.PUSH_BUTTON });
content = new St.Bin();
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] });
content.set_child(icon.actor);
this._dragActorSource = icon.icon;
content.label_actor = icon.label;
dragSource = icon.icon;
} else {
if (content._delegate && content._delegate.getDragActorSource)
this._dragActorSource = content._delegate.getDragActorSource();
dragSource = content._delegate.getDragActorSource();
}
this._content = content;
this.actor.set_child(content);
this.actor.connect('clicked', Lang.bind(this, this._onResultClicked));
this.actor.set_child(content);
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
@ -63,32 +134,18 @@ const SearchResult = new Lang.Class({
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
},
setSelected: function(selected) {
if (selected)
this._content.add_style_pseudo_class('selected');
else
this._content.remove_style_pseudo_class('selected');
},
activate: function() {
this.provider.activateResult(this.metaInfo.id);
Main.overview.toggle();
},
_onResultClicked: function(actor) {
this.activate();
if (!dragSource)
// not exactly right, but alignment problems are hard to notice
dragSource = content;
this._dragActorSource = dragSource;
},
getDragActorSource: function() {
if (this._dragActorSource)
return this._dragActorSource;
// not exactly right, but alignment problems are hard to notice
return this._content;
return this._dragActorSource;
},
getDragActor: function(stageX, stageY) {
getDragActor: function() {
return this.metaInfo['createIcon'](Main.overview.dashIconSize);
},
@ -96,51 +153,52 @@ const SearchResult = new Lang.Class({
if (this.provider.dragActivateResult)
this.provider.dragActivateResult(this.metaInfo.id, params);
else
this.provider.activateResult(this.metaInfo.id, params);
this.provider.activateResult(this.metaInfo.id, this.terms);
}
});
const ListSearchResults = new Lang.Class({
Name: 'ListSearchResults',
const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
Extends: Search.SearchResultDisplay,
_init: function(provider) {
this.provider = provider;
_init: function(provider, grid) {
this.parent(provider);
this._grid = 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._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() {
let results = this.getResultsForDisplay();
if (results.length == 0)
return;
provider.getResultMetas(results, Lang.bind(this, this.renderResults));
this.actor = new St.BoxLayout({ style_class: 'search-section-content' });
this.providerIcon = new ProviderIcon(provider);
this.providerIcon.connect('clicked', Lang.bind(this,
function() {
provider.launchSearch(this._terms);
Main.overview.toggle();
}));
}));
this.actor.add(this.providerIcon, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
this._content = new St.BoxLayout({ style_class: 'list-search-results',
vertical: true });
this.actor.add_actor(this._content);
this._notDisplayedResult = [];
this._terms = [];
this._pendingClear = false;
},
getResultsForDisplay: function() {
let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
let canDisplay = this._grid.childrenInRow(this._width) * this._grid.getRowLimit()
- alreadyVisible;
let alreadyVisible = this._pendingClear ? 0 : this.getVisibleResultCount();
let canDisplay = MAX_LIST_SEARCH_RESULTS_ROWS - alreadyVisible;
let numResults = Math.min(this._notDisplayedResult.length, canDisplay);
return this._notDisplayedResult.splice(0, numResults);
let newResults = this._notDisplayedResult.splice(0, canDisplay);
return newResults;
},
getVisibleResultCount: function() {
return this._grid.visibleItemsCount();
return this._content.get_n_children();
},
hasMoreResults: function() {
return this._notDisplayedResult.length > 0;
},
setResults: function(results, terms) {
@ -152,7 +210,68 @@ const GridSearchResults = new Lang.Class({
renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new SearchResult(this.provider, metas[i], this._terms);
let display = new ListSearchResult(this.provider, metas[i], this._terms);
this._content.add_actor(display.actor);
}
},
clear: function () {
this._content.destroy_all_children();
this._pendingClear = false;
},
getFirstResult: function() {
if (this.getVisibleResultCount() > 0)
return this._content.get_child_at_index(0)._delegate;
else
return null;
}
});
const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
_init: function(provider) {
this.provider = provider;
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
this.actor = new St.Bin({ x_align: St.Align.MIDDLE });
this.actor.set_child(this._grid.actor);
this._notDisplayedResult = [];
this._terms = [];
this._pendingClear = false;
},
getResultsForDisplay: function() {
let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
let canDisplay = this._grid.childrenInRow(this.actor.width) * this._grid.getRowLimit()
- alreadyVisible;
let newResults = this._notDisplayedResult.splice(0, canDisplay);
return newResults;
},
getVisibleResultCount: function() {
return this._grid.visibleItemsCount();
},
hasMoreResults: function() {
return this._notDisplayedResult.length > 0;
},
setResults: function(results, terms) {
// copy the lists
this._notDisplayedResult = results.slice(0);
this._terms = terms.slice(0);
this._pendingClear = true;
},
renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new GridSearchResult(this.provider, metas[i], this._terms);
this._grid.addItem(display.actor);
}
},
@ -183,26 +302,20 @@ const SearchResults = new Lang.Class({
this._content = new St.BoxLayout({ name: 'searchResultsContent',
vertical: true });
let scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
style_class: 'vfade' });
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
scrollView.add_actor(this._content);
this._scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
style_class: 'vfade' });
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this._scrollView.add_actor(this._content);
let action = new Clutter.PanAction({ interpolate: true });
action.connect('pan', Lang.bind(this, this._onPan));
this._scrollView.add_action(action);
this.actor.add(scrollView, { x_fill: true,
y_fill: true,
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.actor.add(this._scrollView, { x_fill: true,
y_fill: true,
expand: true,
x_align: St.Align.START,
y_align: St.Align.START });
this._statusText = new St.Label({ style_class: 'search-statustext' });
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
@ -219,22 +332,37 @@ const SearchResults = new Lang.Class({
this._defaultResult = null;
},
_onPan: function(action) {
let [dist, dx, dy] = action.get_motion_delta(0);
let adjustment = this._scrollView.vscroll.adjustment;
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
return false;
},
createProviderMeta: function(provider) {
let providerBox = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
let title = new St.Label({ style_class: 'search-section-header',
text: provider.title });
providerBox.add(title, { x_fill: false, x_align: St.Align.START });
let providerIcon = null;
let resultDisplay = null;
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
if (provider.appInfo) {
resultDisplay = new ListSearchResults(provider);
providerIcon = resultDisplay.providerIcon;
} else {
resultDisplay = new GridSearchResults(provider);
}
let resultDisplayBin = new St.Bin({ child: resultDisplay.actor,
x_fill: true,
y_fill: true });
providerBox.add(resultDisplayBin, { expand: true });
let resultDisplay = new GridSearchResults(provider);
resultDisplayBin.set_child(resultDisplay.actor);
let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
providerBox.add(separator.actor);
this._providerMeta.push({ provider: provider,
actor: providerBox,
icon: providerIcon,
resultDisplay: resultDisplay });
this._content.add(providerBox);
},
@ -341,6 +469,11 @@ const SearchResults = new Lang.Class({
meta.resultDisplay.setResults(providerResults, terms);
let results = meta.resultDisplay.getResultsForDisplay();
if (meta.icon)
meta.icon.moreIcon.visible =
meta.resultDisplay.hasMoreResults() &&
provider.canLaunchSearch;
provider.getResultMetas(results, Lang.bind(this, function(metas) {
this._clearDisplayForProvider(provider);
meta.actor.show();
@ -386,10 +519,37 @@ const SearchResults = new Lang.Class({
let from = this._defaultResult ? this._defaultResult.actor : null;
this.actor.navigate_focus(from, direction, false);
if (this._defaultResult) {
// The default result appears focused, so navigate directly to the
// next result.
this.actor.navigate_focus(global.stage.key_focus, direction, false);
}
}
});
const ProviderIcon = new Lang.Class({
Name: 'ProviderIcon',
Extends: St.Button,
PROVIDER_ICON_SIZE: 48,
_init: function(provider) {
this.provider = provider;
this.parent({ style_class: 'search-provider-icon',
reactive: true,
can_focus: true,
track_hover: true });
this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this.set_child(this._content);
let rtl = (this.get_text_direction() == Clutter.TextDirection.RTL);
this.moreIcon = new St.Widget({ style_class: 'search-provider-icon-more',
visible: false,
x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.END,
x_expand: true,
y_expand: true });
let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE,
gicon: provider.appInfo.get_icon() });
this._content.add_actor(icon);
this._content.add_actor(this.moreIcon);
}
});

34
js/ui/separator.js Normal file
View File

@ -0,0 +1,34 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Cairo = imports.cairo;
const Lang = imports.lang;
const St = imports.gi.St;
const HorizontalSeparator = new Lang.Class({
Name: 'HorizontalSeparator',
_init: function (params) {
this.actor = new St.DrawingArea(params);
this.actor.connect('repaint', Lang.bind(this, this._onRepaint));
},
_onRepaint: function(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let margin = themeNode.get_length('-margin-horizontal');
let gradientHeight = themeNode.get_length('-gradient-height');
let startColor = themeNode.get_color('-gradient-start');
let endColor = themeNode.get_color('-gradient-end');
let gradientWidth = (width - margin * 2);
let gradientOffset = (height - gradientHeight) / 2;
let pattern = new Cairo.LinearGradient(margin, gradientOffset, width - margin, gradientOffset + gradientHeight);
pattern.addColorStopRGBA(0, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
pattern.addColorStopRGBA(0.5, endColor.red / 255, endColor.green / 255, endColor.blue / 255, endColor.alpha / 255);
pattern.addColorStopRGBA(1, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
cr.setSource(pattern);
cr.rectangle(margin, gradientOffset, gradientWidth, gradientHeight);
cr.fill();
}
});

View File

@ -1,8 +1,12 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const Params = imports.misc.params;
@ -10,10 +14,12 @@ const DEFAULT_MODE = 'restrictive';
const _modes = {
'restrictive': {
parentMode: null,
hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
allowExtensions: false,
enabledExtensions: [],
hasRunDialog: false,
hasWorkspaces: false,
hasWindows: false,
@ -104,11 +110,48 @@ const _modes = {
}
};
function _getModes(modesLoadedCallback) {
FileUtils.collectFromDatadirsAsync('modes',
{ processFile: _loadMode,
loadedCallback: modesLoadedCallback,
data: _modes });
}
function _loadMode(file, info, loadedData) {
let name = info.get_name();
let suffix = name.indexOf('.json');
let modeName = suffix == -1 ? name : name.slice(name, suffix);
if (loadedData.hasOwnProperty(modeName))
return;
let fileContent, success, tag, newMode;
try {
[success, fileContent, tag] = file.load_contents(null);
newMode = JSON.parse(fileContent);
} catch(e) {
return;
}
loadedData[modeName] = {};
let propBlacklist = ['unlockDialog'];
for (let prop in loadedData[DEFAULT_MODE]) {
if (newMode[prop] !== undefined &&
propBlacklist.indexOf(prop) == -1)
loadedData[modeName][prop]= newMode[prop];
}
loadedData[modeName]['isPrimary'] = true;
}
function listModes() {
let modes = Object.getOwnPropertyNames(_modes);
for (let i = 0; i < modes.length; i++)
if (_modes[modes[i]].isPrimary)
print(modes[i]);
_getModes(function(modes) {
let names = Object.getOwnPropertyNames(modes);
for (let i = 0; i < names.length; i++)
if (_modes[names[i]].isPrimary)
print(names[i]);
Mainloop.quit('listModes');
});
Mainloop.run('listModes');
}
const SessionMode = new Lang.Class({
@ -116,10 +159,18 @@ const SessionMode = new Lang.Class({
_init: function() {
global.connect('notify::session-mode', Lang.bind(this, this._sync));
let mode = _modes[global.session_mode].isPrimary ? global.session_mode
: 'user';
this._modeStack = [mode];
this._modes = _modes;
this._modeStack = [DEFAULT_MODE];
this._sync();
_getModes(Lang.bind(this, function(modes) {
this._modes = modes;
let primary = modes[global.session_mode] &&
modes[global.session_mode].isPrimary;
let mode = primary ? global.session_mode : 'user';
this._modeStack = [mode];
this._sync();
}));
},
pushMode: function(mode) {
@ -146,8 +197,14 @@ const SessionMode = new Lang.Class({
},
_sync: function() {
let params = _modes[this.currentMode];
params = Params.parse(params, _modes[DEFAULT_MODE]);
let params = this._modes[this.currentMode];
let defaults;
if (params.parentMode)
defaults = Params.parse(this._modes[params.parentMode],
this._modes[DEFAULT_MODE]);
else
defaults = this._modes[DEFAULT_MODE];
params = Params.parse(params, defaults);
// A simplified version of Lang.copyProperties, handles
// undefined as a special case for "no change / inherit from previous mode"

View File

@ -46,6 +46,7 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
<arg type="i" direction="in" name="width"/>
<arg type="i" direction="in" name="height"/>
</method>
<property name="Mode" type="s" access="read" />
<property name="OverviewActive" type="b" access="readwrite" />
<property name="ShellVersion" type="s" access="read" />
</interface>;
@ -186,6 +187,8 @@ const GnomeShell = new Lang.Class({
flashspot.fire();
},
Mode: global.session_mode,
get OverviewActive() {
return Main.overview.visible;
},

View File

@ -19,6 +19,8 @@ const ShellEntry = imports.ui.shellEntry;
const LIST_ITEM_ICON_SIZE = 48;
const REMEMBER_MOUNT_PASSWORD_KEY = 'remember-mount-password';
/* ------ Common Utils ------- */
function _setLabelText(label, text) {
if (text) {
@ -387,7 +389,8 @@ const ShellMountPasswordDialog = new Lang.Class({
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
this._rememberChoice = new CheckBox.CheckBox();
this._rememberChoice.getLabelActor().text = _("Remember Password");
this._rememberChoice.actor.checked = true;
this._rememberChoice.actor.checked =
global.settings.get_boolean(REMEMBER_MOUNT_PASSWORD_KEY);
this._messageBox.add(this._rememberChoice.actor);
} else {
this._rememberChoice = null;
@ -419,6 +422,8 @@ const ShellMountPasswordDialog = new Lang.Class({
},
_onEntryActivate: function() {
global.settings.set_boolean(REMEMBER_MOUNT_PASSWORD_KEY,
this._rememberChoice && this._rememberChoice.actor.checked);
this.emit('response', 1,
this._passwordEntry.get_text(),
this._rememberChoice &&

View File

@ -574,7 +574,11 @@ const NMDevice = new Lang.Class({
this.emit('network-lost');
}
if (newstate == NetworkManager.DeviceState.FAILED) {
/* Emit a notification if activation fails, but don't do it
if the reason is no secrets, as that indicates the user
cancelled the agent dialog */
if (newstate == NetworkManager.DeviceState.FAILED &&
reason != NetworkManager.DeviceStateReason.NO_SECRETS) {
this.emit('activation-failed', reason);
}
@ -1540,7 +1544,8 @@ const NMVPNSection = new Lang.Class({
},
_connectionStateChanged: function(vpnConnection, newstate, reason) {
if (newstate == NetworkManager.VPNConnectionState.FAILED) {
if (newstate == NetworkManager.VPNConnectionState.FAILED &&
reason != NetworkManager.VPNConnectionStateReason.NO_SECRETS) {
// FIXME: if we ever want to show something based on reason,
// we need to convert from NetworkManager.VPNConnectionStateReason
// to NetworkManager.DeviceStateReason

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Gio = imports.gi.Gio;
const Gvc = imports.gi.Gvc;
const St = imports.gi.St;
@ -32,6 +33,8 @@ const VolumeMenu = new Lang.Class({
_init: function(control) {
this.parent();
this.hasHeadphones = false;
this._control = control;
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
@ -98,20 +101,47 @@ const VolumeMenu = new Lang.Class({
}
},
_findHeadphones: function(sink) {
// This only works for external headphones (e.g. bluetooth)
if (sink.get_form_factor() == 'headset' ||
sink.get_form_factor() == 'headphone')
return true;
// a bit hackish, but ALSA/PulseAudio have a number
// of different identifiers for headphones, and I could
// not find the complete list
let port = sink.get_port();
if (port)
return port.port.indexOf('headphone') >= 0;
return false;
},
_portChanged: function() {
this.hasHeadphones = this._findHeadphones(this._output);
this.emit('headphones-changed');
},
_readOutput: function() {
if (this._outputVolumeId) {
this._output.disconnect(this._outputVolumeId);
this._output.disconnect(this._outputMutedId);
this._output.disconnect(this._outputPortId);
this._outputVolumeId = 0;
this._outputMutedId = 0;
this._outputPortId = 0;
}
this._output = this._control.get_default_sink();
if (this._output) {
this._outputMutedId = this._output.connect('notify::is-muted', Lang.bind(this, this._mutedChanged, '_output'));
this._outputVolumeId = this._output.connect('notify::volume', Lang.bind(this, this._volumeChanged, '_output'));
this._mutedChanged (null, null, '_output');
this._volumeChanged (null, null, '_output');
this._outputPortId = this._output.connect('notify::port', Lang.bind(this, this._portChanged));
this._mutedChanged(null, null, '_output');
this._volumeChanged(null, null, '_output');
this._portChanged();
} else {
this.hasHeadphones = false;
this._outputSlider.setValue(0);
this.emit('icon-changed', 'audio-volume-muted-symbolic');
}
@ -227,6 +257,12 @@ const Indicator = new Lang.Class({
this.setIcon(icon);
this._syncVisibility();
}));
this._volumeMenu.connect('headphones-changed', Lang.bind(this, function() {
this._syncVisibility();
}));
this._headphoneIcon = this.addIcon(new Gio.ThemedIcon({ name: 'headphones-symbolic' }));
this._headphoneIcon.visible = false;
this.menu.addMenuItem(this._volumeMenu);
@ -239,6 +275,7 @@ const Indicator = new Lang.Class({
_syncVisibility: function() {
this.actor.visible = this._hasPulseAudio;
this.mainIcon.visible = this._hasPulseAudio;
this._headphoneIcon.visible = this._hasPulseAudio && this._volumeMenu.hasHeadphones;
},
_onScrollEvent: function(actor, event) {

641
js/ui/switcherPopup.js Normal file
View File

@ -0,0 +1,641 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk;
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 Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const POPUP_DELAY_TIMEOUT = 150; // milliseconds
const POPUP_SCROLL_TIME = 0.10; // seconds
const POPUP_FADE_OUT_TIME = 0.1; // seconds
const DISABLE_HOVER_TIMEOUT = 500; // milliseconds
function mod(a, b) {
return (a + b) % b;
}
function primaryModifier(mask) {
if (mask == 0)
return 0;
let primary = 1;
while (mask > 1) {
mask >>= 1;
primary <<= 1;
}
return primary;
}
const SwitcherPopup = new Lang.Class({
Name: 'SwitcherPopup',
Abstract: true,
_init: function(items) {
this._switcherList = null;
this._items = items || [];
this._selectedIndex = 0;
this.actor = new Shell.GenericContainer({ style_class: 'switcher-popup',
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));
Main.uiGroup.add_actor(this.actor);
this._haveModal = false;
this._modifierMask = 0;
this._motionTimeoutId = 0;
this._initialDelayTimeoutId = 0;
// Initially disable hover so we ignore the enter-event if
// the switcher appears underneath the current pointer location
this._disableHover();
},
_getPreferredWidth: function(actor, forHeight, alloc) {
let primary = Main.layoutManager.primaryMonitor;
alloc.min_size = primary.width;
alloc.natural_size = primary.width;
},
_getPreferredHeight: function(actor, forWidth, alloc) {
let primary = Main.layoutManager.primaryMonitor;
alloc.min_size = primary.height;
alloc.natural_size = primary.height;
},
_allocate: function(actor, box, flags) {
let childBox = new Clutter.ActorBox();
let primary = Main.layoutManager.primaryMonitor;
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
let bottomPadding = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
let vPadding = this.actor.get_theme_node().get_vertical_padding();
let hPadding = leftPadding + rightPadding;
// Allocate the switcherList
// We select a size based on an icon size that does not overflow the screen
let [childMinHeight, childNaturalHeight] = this._switcherList.actor.get_preferred_height(primary.width - hPadding);
let [childMinWidth, childNaturalWidth] = this._switcherList.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.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth);
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._switcherList.actor.allocate(childBox, flags);
},
_createSwitcher: function() {
throw new Error('Not implemented');
},
_initialSelection: function(backward, binding) {
throw new Error('Not implemented');
},
show: function(backward, binding, mask) {
if (!this._createSwitcher())
return false;
if (!Main.pushModal(this.actor)) {
// Probably someone else has a pointer grab, try again with keyboard only
if (!Main.pushModal(this.actor, { options: Meta.ModalOptions.POINTER_ALREADY_GRABBED })) {
return false;
}
}
this._haveModal = true;
this._modifierMask = primaryModifier(mask);
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._scrollEvent));
this.actor.add_actor(this._switcherList.actor);
this._switcherList.connect('item-activated', Lang.bind(this, this._itemActivated));
this._switcherList.connect('item-entered', Lang.bind(this, this._itemEntered));
// Need to force an allocation so we can figure out whether we
// need to scroll when selecting
this.actor.opacity = 0;
this.actor.show();
this.actor.get_allocation_box();
if (this._items.length > 1)
this._selectedIndex = 1;
else
this._selectedIndex = 0;
this._initialSelection(backward, binding);
// There's a race condition; if the user released Alt before
// we got the grab, then we won't be notified. (See
// https://bugzilla.gnome.org/show_bug.cgi?id=596695 for
// details.) So we check now. (Have to do this after updating
// selection.)
let [x, y, mods] = global.get_pointer();
if (!(mods & this._modifierMask)) {
this._finish(global.get_current_time());
return false;
}
// We delay showing the popup so that fast Alt+Tab users aren't
// disturbed by the popup briefly flashing.
this._initialDelayTimeoutId = Mainloop.timeout_add(POPUP_DELAY_TIMEOUT,
Lang.bind(this, function () {
this.actor.opacity = 255;
this._initialDelayTimeoutId = 0;
}));
return true;
},
_next: function() {
return mod(this._selectedIndex + 1, this._items.length);
},
_previous: function() {
return mod(this._selectedIndex - 1, this._items.length);
},
_keyPressHandler: function(keysym, backwards, action) {
throw new Error('Not implemented');
},
_keyPressEvent: function(actor, event) {
let keysym = event.get_key_symbol();
let event_state = event.get_state();
let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
this._disableHover();
if (keysym == Clutter.Escape)
this.destroy();
else
this._keyPressHandler(keysym, backwards, action);
return true;
},
_keyReleaseEvent: function(actor, event) {
let [x, y, mods] = global.get_pointer();
let state = mods & this._modifierMask;
if (state == 0)
this._finish(event.get_time());
return true;
},
_clickedOutside: function(actor, event) {
this.destroy();
},
_scrollHandler: function(direction) {
if (direction == Clutter.ScrollDirection.UP)
this._select(this._previous());
else if (direction == Clutter.ScrollDirection.DOWN)
this._select(this._next());
},
_scrollEvent: function(actor, event) {
this._scrollHandler(event.get_scroll_direction());
},
_itemActivatedHandler: function(n) {
this._select(n);
},
_itemActivated: function(switcher, n) {
this._itemActivatedHandler(n);
this._finish(global.get_current_time());
},
_itemEnteredHandler: function(n) {
this._select(n);
},
_itemEntered: function(switcher, n) {
if (!this.mouseActive)
return;
this._itemEnteredHandler(n);
},
_disableHover: function() {
this.mouseActive = false;
if (this._motionTimeoutId != 0)
Mainloop.source_remove(this._motionTimeoutId);
this._motionTimeoutId = Mainloop.timeout_add(DISABLE_HOVER_TIMEOUT, Lang.bind(this, this._mouseTimedOut));
},
_mouseTimedOut: function() {
this._motionTimeoutId = 0;
this.mouseActive = true;
},
_popModal: function() {
if (this._haveModal) {
Main.popModal(this.actor);
this._haveModal = false;
}
},
destroy: function() {
this._popModal();
if (this.actor.visible) {
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_OUT_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.destroy();
})
});
} else
this.actor.destroy();
},
_finish: function(timestamp) {
this.destroy();
},
_onDestroy: function() {
this._popModal();
if (this._motionTimeoutId != 0)
Mainloop.source_remove(this._motionTimeoutId);
if (this._initialDelayTimeoutId != 0)
Mainloop.source_remove(this._initialDelayTimeoutId);
},
_select: function(num) {
this._selectedIndex = num;
this._switcherList.highlight(num);
}
});
const SwitcherList = new Lang.Class({
Name: 'SwitcherList',
_init : function(squareItems) {
this.actor = new Shell.GenericContainer({ style_class: 'switcher-list' });
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._allocateTop));
// Here we use a GenericContainer so that we can force all the
// children except the separator to have the same width.
this._list = new Shell.GenericContainer({ style_class: 'switcher-list-item-container' });
this._list.spacing = 0;
this._list.connect('style-changed', Lang.bind(this, function() {
this._list.spacing = this._list.get_theme_node().get_length('spacing');
}));
this._list.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this._list.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this._list.connect('allocate', Lang.bind(this, this._allocate));
this._scrollView = new St.ScrollView({ style_class: 'hfade',
enable_mouse_scrolling: false });
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER);
let scrollBox = new St.BoxLayout();
scrollBox.add_actor(this._list);
this._scrollView.add_actor(scrollBox);
this.actor.add_actor(this._scrollView);
// Those arrows indicate whether scrolling in one direction is possible
this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
pseudo_class: 'highlighted' });
this._leftArrow.connect('repaint', Lang.bind(this,
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() { drawArrow(this._rightArrow, St.Side.RIGHT); }));
this.actor.add_actor(this._leftArrow);
this.actor.add_actor(this._rightArrow);
this._items = [];
this._highlighted = -1;
this._separator = null;
this._squareItems = squareItems;
this._minSize = 0;
this._scrollableRight = true;
this._scrollableLeft = false;
},
_allocateTop: function(actor, box, flags) {
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
let childBox = new Clutter.ActorBox();
let scrollable = this._minSize > box.x2 - box.x1;
box.y1 -= this.actor.get_theme_node().get_padding(St.Side.TOP);
box.y2 += this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
this._scrollView.allocate(box, flags);
let arrowWidth = Math.floor(leftPadding / 3);
let arrowHeight = arrowWidth * 2;
childBox.x1 = leftPadding / 2;
childBox.y1 = this.actor.height / 2 - arrowWidth;
childBox.x2 = childBox.x1 + arrowWidth;
childBox.y2 = childBox.y1 + arrowHeight;
this._leftArrow.allocate(childBox, flags);
this._leftArrow.opacity = (this._scrollableLeft && scrollable) ? 255 : 0;
arrowWidth = Math.floor(rightPadding / 3);
arrowHeight = arrowWidth * 2;
childBox.x1 = this.actor.width - arrowWidth - rightPadding / 2;
childBox.y1 = this.actor.height / 2 - arrowWidth;
childBox.x2 = childBox.x1 + arrowWidth;
childBox.y2 = childBox.y1 + arrowHeight;
this._rightArrow.allocate(childBox, flags);
this._rightArrow.opacity = (this._scrollableRight && scrollable) ? 255 : 0;
},
addItem : function(item, label) {
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._onItemClicked(n); }));
bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); }));
bbox.label_actor = label;
this._items.push(bbox);
return 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;
this._list.add_actor(box);
},
highlight: function(index, justOutline) {
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].add_style_pseudo_class('outlined');
else
this._items[this._highlighted].add_style_pseudo_class('selected');
}
let adjustment = this._scrollView.hscroll.adjustment;
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let [absItemX, absItemY] = this._items[index].get_transformed_position();
let [result, posX, posY] = this.actor.transform_stage_point(absItemX, 0);
let [containerWidth, containerHeight] = this.actor.get_transformed_size();
if (posX + this._items[index].get_width() > containerWidth)
this._scrollToRight();
else if (this._items[index].allocation.x1 - value < 0)
this._scrollToLeft();
},
_scrollToLeft : function() {
let adjustment = this._scrollView.hscroll.adjustment;
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let item = this._items[this._highlighted];
if (item.allocation.x1 < value)
value = Math.min(0, item.allocation.x1);
else if (item.allocation.x2 > value + pageSize)
value = Math.max(upper, item.allocation.x2 - pageSize);
this._scrollableRight = true;
Tweener.addTween(adjustment,
{ value: value,
time: POPUP_SCROLL_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () {
if (this._highlighted == 0) {
this._scrollableLeft = false;
this.actor.queue_relayout();
}
})
});
},
_scrollToRight : function() {
let adjustment = this._scrollView.hscroll.adjustment;
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let item = this._items[this._highlighted];
if (item.allocation.x1 < value)
value = Math.max(0, item.allocation.x1);
else if (item.allocation.x2 > value + pageSize)
value = Math.min(upper, item.allocation.x2 - pageSize);
this._scrollableLeft = true;
Tweener.addTween(adjustment,
{ value: value,
time: POPUP_SCROLL_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () {
if (this._highlighted == this._items.length - 1) {
this._scrollableRight = false;
this.actor.queue_relayout();
}
})
});
},
_itemActivated: function(n) {
this.emit('item-activated', n);
},
_itemEntered: function(n) {
this.emit('item-entered', n);
},
_maxChildWidth: function (forHeight) {
let maxChildMin = 0;
let maxChildNat = 0;
for (let i = 0; i < this._items.length; i++) {
let [childMin, childNat] = this._items[i].get_preferred_width(forHeight);
maxChildMin = Math.max(childMin, maxChildMin);
maxChildNat = Math.max(childNat, maxChildNat);
if (this._squareItems) {
let [childMin, childNat] = this._items[i].get_preferred_height(-1);
maxChildMin = Math.max(childMin, maxChildMin);
maxChildNat = Math.max(childNat, maxChildNat);
}
}
return [maxChildMin, maxChildNat];
},
_getPreferredWidth: function (actor, forHeight, alloc) {
let [maxChildMin, maxChildNat] = this._maxChildWidth(forHeight);
let separatorWidth = 0;
if (this._separator) {
let [sepMin, sepNat] = this._separator.get_preferred_width(forHeight);
separatorWidth = sepNat + this._list.spacing;
}
let totalSpacing = this._list.spacing * (this._items.length - 1);
alloc.min_size = this._items.length * maxChildMin + separatorWidth + totalSpacing;
alloc.natural_size = alloc.min_size;
this._minSize = alloc.min_size;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
let maxChildMin = 0;
let maxChildNat = 0;
for (let i = 0; i < this._items.length; i++) {
let [childMin, childNat] = this._items[i].get_preferred_height(-1);
maxChildMin = Math.max(childMin, maxChildMin);
maxChildNat = Math.max(childNat, maxChildNat);
}
if (this._squareItems) {
let [childMin, childNat] = this._maxChildWidth(-1);
maxChildMin = Math.max(childMin, maxChildMin);
maxChildNat = maxChildMin;
}
alloc.min_size = maxChildMin;
alloc.natural_size = maxChildNat;
},
_allocate: function (actor, box, flags) {
let childHeight = box.y2 - box.y1;
let [maxChildMin, maxChildNat] = this._maxChildWidth(childHeight);
let totalSpacing = this._list.spacing * (this._items.length - 1);
let separatorWidth = 0;
if (this._separator) {
let [sepMin, sepNat] = this._separator.get_preferred_width(childHeight);
separatorWidth = sepNat;
totalSpacing += this._list.spacing;
}
let childWidth = Math.floor(Math.max(0, box.x2 - box.x1 - totalSpacing - separatorWidth) / this._items.length);
let x = 0;
let children = this._list.get_children();
let childBox = new Clutter.ActorBox();
let primary = Main.layoutManager.primaryMonitor;
let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
for (let i = 0; i < children.length; i++) {
if (this._items.indexOf(children[i]) != -1) {
let [childMin, childNat] = children[i].get_preferred_height(childWidth);
let vSpacing = (childHeight - childNat) / 2;
childBox.x1 = x;
childBox.y1 = vSpacing;
childBox.x2 = x + childWidth;
childBox.y2 = childBox.y1 + childNat;
children[i].allocate(childBox, flags);
x += this._list.spacing + childWidth;
} else if (children[i] == this._separator) {
// We want the separator to be more compact than the rest.
childBox.x1 = x;
childBox.y1 = 0;
childBox.x2 = x + separatorWidth;
childBox.y2 = childHeight;
children[i].allocate(childBox, flags);
x += this._list.spacing + separatorWidth;
} else {
// Something else, eg, AppSwitcher's arrows;
// we don't allocate it.
}
}
}
});
Signals.addSignalMethods(SwitcherList.prototype);
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

@ -52,8 +52,7 @@ const ViewSelector = new Lang.Class({
this._activePage = null;
this.active = false;
this._searchPending = false;
this._searchActive = false;
this._searchTimeoutId = 0;
this._searchSystem = new Search.SearchSystem();
@ -119,9 +118,6 @@ const ViewSelector = new Lang.Class({
global.focus_manager.add_group(this._searchResults.actor);
Main.overview.connect('item-drag-begin',
Lang.bind(this, this._resetShowAppsButton));
this._stageKeyPressId = 0;
Main.overview.connect('showing', Lang.bind(this,
function () {
@ -138,17 +134,6 @@ const ViewSelector = new Lang.Class({
}
}));
// Public constraints which may be used to tie actors' height or
// vertical position to the current tab's content; as the content's
// height and position depend on the view selector's style properties
// (e.g. font size, padding, spacing, ...) it would be extremely hard
// and ugly to get these from the outside. While it would be possible
// to use position and height properties directly, outside code would
// need to ensure that the content is properly allocated before
// accessing the properties.
this.constrainHeight = new Clutter.BindConstraint({ source: this._pageArea,
coordinate: Clutter.BindCoordinate.HEIGHT });
Main.wm.addKeybinding('toggle-application-view',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
@ -223,11 +208,16 @@ const ViewSelector = new Lang.Class({
});
}
this.emit('before-page-change');
page.show();
Tweener.addTween(page,
{ opacity: 255,
time: 0.1,
transition: 'easeOutQuad'
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.emit('after-page-change');
})
});
},
@ -237,7 +227,7 @@ const ViewSelector = new Lang.Class({
},
_onShowAppsButtonToggled: function() {
if (this.active)
if (this._searchActive)
this.reset();
else
this._showPage(this._showAppsButton.checked ? this._appsPage
@ -249,11 +239,16 @@ const ViewSelector = new Lang.Class({
},
_onStageKeyPress: function(actor, event) {
// Ignore events while anything but the overview has
// pushed a modal (system modals, looking glass, ...)
if (Main.modalCount > 1)
return false;
let modifiers = event.get_state();
let symbol = event.get_key_symbol();
if (symbol == Clutter.Escape) {
if (this.active)
if (this._searchActive)
this.reset();
else if (this._showAppsButton.checked)
this._resetShowAppsButton();
@ -261,9 +256,9 @@ const ViewSelector = new Lang.Class({
Main.overview.hide();
return true;
} else if (Clutter.keysym_to_unicode(symbol) ||
(symbol == Clutter.BackSpace && this.active)) {
(symbol == Clutter.BackSpace && this._searchActive)) {
this.startSearch(event);
} else if (!this.active) {
} else if (!this._searchActive) {
if (symbol == Clutter.Tab || symbol == Clutter.Down) {
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
return true;
@ -337,13 +332,15 @@ const ViewSelector = new Lang.Class({
},
_onTextChanged: function (se, prop) {
let searchPreviouslyActive = this.active;
this.active = this._entry.get_text() != '';
this._searchPending = this.active && !searchPreviouslyActive;
if (this._searchPending) {
let searchPreviouslyActive = this._searchActive;
this._searchActive = this._entry.get_text() != '';
let startSearch = this._searchActive && !searchPreviouslyActive;
if (startSearch) {
this._searchResults.startingSearch();
}
if (this.active) {
if (this._searchActive) {
this._entry.set_secondary_icon(this._activeIcon);
if (this._iconClickedId == 0) {
@ -359,14 +356,14 @@ const ViewSelector = new Lang.Class({
this._entry.set_secondary_icon(this._inactiveIcon);
this._searchCancelled();
}
if (!this.active) {
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._searchTimeoutId = 0;
}
return;
}
if (this._searchTimeoutId > 0)
return;
this._searchTimeoutId = Mainloop.timeout_add(150, Lang.bind(this, this._doSearch));
@ -388,7 +385,7 @@ const ViewSelector = new Lang.Class({
}
this._searchResults.activateDefault();
return true;
} else if (this.active) {
} else if (this._searchActive) {
let arrowNext, nextDirection;
if (entry.get_text_direction() == Clutter.TextDirection.RTL) {
arrowNext = Clutter.Left;
@ -462,6 +459,10 @@ const ViewSelector = new Lang.Class({
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
},
getAppsActive: function() {
return this._showAppsButton.checked;
},
addSearchProvider: function(provider) {
if (!this._shouldUseSearchProvider(provider))
return;
@ -473,6 +474,10 @@ const ViewSelector = new Lang.Class({
removeSearchProvider: function(provider) {
this._searchSystem.unregisterProvider(provider);
this._searchResults.destroyProviderMeta(provider);
},
getSearchActive: function() {
return this._searchActive;
}
});
Signals.addSignalMethods(ViewSelector.prototype);

View File

@ -10,7 +10,6 @@ const IconGrid = imports.ui.iconGrid;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const Search = imports.ui.search;
// we could make these gsettings
const FISH_NAME = 'wanda';
@ -71,8 +70,7 @@ const WandaIconBin = new Lang.Class({
Name: 'WandaIconBin',
_init: function(fish, label, params) {
this.actor = new St.Bin({ style_class: 'search-result-content',
reactive: true,
this.actor = new St.Bin({ reactive: true,
track_hover: true });
this.icon = new WandaIcon(fish, label, params);
@ -133,10 +131,9 @@ function capitalize(str) {
const WandaSearchProvider = new Lang.Class({
Name: 'WandaSearchProvider',
Extends: Search.SearchProvider,
_init: function() {
this.parent(_("Your favorite Easter Egg"));
this.id = 'wanda';
},
getResultMetas: function(fish, callback) {
@ -162,7 +159,7 @@ const WandaSearchProvider = new Lang.Class({
this.getInitialResultSet(terms);
},
activateResult: function(fish, params) {
activateResult: function(fish) {
if (this._dialog)
this._dialog.destroy();
this._dialog = new FortuneDialog(capitalize(fish), FISH_COMMAND);

View File

@ -136,18 +136,24 @@ const WindowManager = new Lang.Class({
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-windows',
this.setCustomKeybindingHandler('switch-applications',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
this.setCustomKeybindingHandler('switch-group',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
this.setCustomKeybindingHandler('switch-windows-backward',
this.setCustomKeybindingHandler('switch-applications-backward',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
this.setCustomKeybindingHandler('switch-group-backward',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
this.setCustomKeybindingHandler('switch-windows',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startWindowSwitcher));
this.setCustomKeybindingHandler('switch-windows-backward',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startWindowSwitcher));
this.setCustomKeybindingHandler('switch-panels',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW |
@ -155,6 +161,13 @@ const WindowManager = new Lang.Class({
Main.KeybindingMode.UNLOCK_SCREEN |
Main.KeybindingMode.LOGIN_SCREEN,
Lang.bind(this, this._startA11ySwitcher));
this.setCustomKeybindingHandler('switch-panels-backward',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW |
Main.KeybindingMode.LOCK_SCREEN |
Main.KeybindingMode.UNLOCK_SCREEN |
Main.KeybindingMode.LOGIN_SCREEN,
Lang.bind(this, this._startA11ySwitcher));
this.addKeybinding('open-application-menu',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
@ -610,7 +623,20 @@ const WindowManager = new Lang.Class({
if (this._workspaceSwitcherPopup != null)
this._workspaceSwitcherPopup.destroy();
let tabPopup = new AltTab.AltTabPopup();
let tabPopup = new AltTab.AppSwitcherPopup();
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
if (!tabPopup.show(backwards, binding.get_name(), binding.get_mask()))
tabPopup.destroy();
},
_startWindowSwitcher : function(display, screen, window, binding) {
/* prevent a corner case where both popups show up at once */
if (this._workspaceSwitcherPopup != null)
this._workspaceSwitcherPopup.destroy();
let tabPopup = new AltTab.WindowSwitcherPopup();
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
@ -621,7 +647,7 @@ const WindowManager = new Lang.Class({
_startA11ySwitcher : function(display, screen, window, binding) {
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
Main.ctrlAltTabManager.popup(backwards, binding.get_mask());
Main.ctrlAltTabManager.popup(backwards, binding.get_name(), binding.get_mask());
},
_openAppMenu : function(display, screen, window, event, binding) {

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
@ -27,6 +28,8 @@ const WORKSPACE_CUT_SIZE = 10;
const WORKSPACE_KEEP_ALIVE_TIME = 100;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
const WindowClone = new Lang.Class({
Name: 'WindowClone',
@ -493,6 +496,8 @@ const ThumbnailsBox = new Lang.Class({
_init: function() {
this.actor = new Shell.GenericContainer({ reactive: true,
style_class: 'workspace-thumbnails',
can_focus: true,
track_hover: true,
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));
@ -521,6 +526,7 @@ const ThumbnailsBox = new Lang.Class({
this._indicator = indicator;
this.actor.add_actor(indicator);
this._inDrag = false;
this._dropWorkspace = -1;
this._dropPlaceholderPos = -1;
this._dropPlaceholder = new St.Bin({ style_class: 'placeholder' });
@ -541,6 +547,18 @@ const ThumbnailsBox = new Lang.Class({
this.actor.connect('button-press-event', function() { return true; });
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect('scroll-event',
Lang.bind(this, this._onScrollEvent));
this.actor.connect('key-release-event',
Lang.bind(this, this._onKeyRelease));
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateTranslation));
this.actor.connect('notify::hover', Lang.bind(this, this._updateTranslation));
Main.overview.connect('showing',
Lang.bind(this, this._createThumbnails));
Main.overview.connect('hidden',
Lang.bind(this, this._destroyThumbnails));
Main.overview.connect('item-drag-begin',
Lang.bind(this, this._onDragBegin));
@ -554,6 +572,50 @@ const ThumbnailsBox = new Lang.Class({
Lang.bind(this, this._onDragEnd));
Main.overview.connect('window-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._settings.connect('changed::dynamic-workspaces',
Lang.bind(this, this._updateSwitcherVisibility));
},
_getInitialTranslation: function() {
// Always show the pager when hover, during a drag, or if workspaces are
// actually used, e.g. there are windows on more than one
let alwaysZoomOut = this.actor.hover || this._inDrag || global.screen.n_workspaces > 2;
if (!alwaysZoomOut) {
let monitors = Main.layoutManager.monitors;
let primary = Main.layoutManager.primaryMonitor;
/* Look for any monitor to the right of the primary, if there is
* one, we always keep zoom out, otherwise its hard to reach
* the thumbnail area without passing into the next monitor. */
for (let i = 0; i < monitors.length; i++) {
if (monitors[i].x >= primary.x + primary.width) {
alwaysZoomOut = true;
break;
}
}
}
if (alwaysZoomOut)
return 0;
let visibleWidth = this.actor.get_theme_node().get_length('visible-width');
let rtl = (this.actor.get_text_direction() == Clutter.TextDirection.RTL);
return rtl ? (visibleWidth - this.actor.width) : (this.actor.width - visibleWidth);
},
_updateTranslation: function() {
Tweener.addTween(this, { slideX: this._getInitialTranslation(),
time: SLIDE_ANIMATION_TIME,
transition: 'easeOutQuad' });
},
_updateSwitcherVisibility: function() {
this.actor.visible =
this._settings.get_boolean('dynamic-workspaces') ||
global.screen.n_workspaces > 1;
},
_onButtonRelease: function(actor, event) {
@ -573,6 +635,9 @@ const ThumbnailsBox = new Lang.Class({
},
_onDragBegin: function() {
this._inDrag = true;
this._updateTranslation();
this._dragCancelled = false;
this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion)
@ -595,6 +660,8 @@ const ThumbnailsBox = new Lang.Class({
_endDrag: function() {
this._clearDragPlaceholder();
DND.removeDragMonitor(this._dragMonitor);
this._inDrag = false;
this._updateTranslation();
},
_onDragMotion: function(dragEvent) {
@ -719,10 +786,16 @@ const ThumbnailsBox = new Lang.Class({
}
},
show: function() {
_createThumbnails: function() {
this._switchWorkspaceNotifyId =
global.window_manager.connect('switch-workspace',
Lang.bind(this, this._activeWorkspaceChanged));
this._nWorkspacesNotifyId =
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._workspacesChanged));
this._syncStackingId =
Main.overview.connect('sync-window-stacking',
Lang.bind(this, this._syncStacking));
this._targetScale = 0;
this._scale = 0;
@ -744,19 +817,101 @@ const ThumbnailsBox = new Lang.Class({
};
this.addThumbnails(0, global.screen.n_workspaces);
// reset any translation and make sure the actor is visible when
// entering the overview
this.slideX = this._getInitialTranslation();
this.actor.show();
this._updateSwitcherVisibility();
},
hide: function() {
_destroyThumbnails: function() {
if (this._switchWorkspaceNotifyId > 0) {
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
this._switchWorkspaceNotifyId = 0;
}
if (this._nWorkspacesNotifyId > 0) {
global.screen.disconnect(this._nWorkspacesNotifyId);
this._nWorkspacesNotifyId = 0;
}
if (this._syncStackingId > 0) {
Main.overview.disconnect(this._syncStackingId);
this._syncStackingId = 0;
}
for (let w = 0; w < this._thumbnails.length; w++)
this._thumbnails[w].destroy();
this._thumbnails = [];
},
_computeTranslation: function() {
let rtl = (this.actor.get_text_direction() == Clutter.TextDirection.RTL);
if (rtl)
return - this.actor.width;
else
return this.actor.width;
},
get slideX() {
return this._slideX;
},
set slideX(value) {
this._slideX = value;
this.actor.translation_x = this._slideX;
if (this._slideX > 0) {
let rect = new Clutter.Rect();
rect.size.width = this._background.width - this._slideX;
rect.size.height = this._background.height;
this.actor.clip_rect = rect;
} else {
this.actor.clip_rect = null;
}
},
show: function() {
this.actor.show();
this._updateTranslation();
},
hide: function() {
let hiddenX = this._computeTranslation();
Tweener.addTween(this, { slideX: hiddenX,
transition: 'easeOutQuad',
time: SLIDE_ANIMATION_TIME,
onComplete: Lang.bind(this, function () {
this.actor.hide();
})
});
},
_workspacesChanged: function() {
let oldNumWorkspaces = this._thumbnails.length;
let newNumWorkspaces = global.screen.n_workspaces;
let active = global.screen.get_active_workspace_index();
if (newNumWorkspaces > oldNumWorkspaces) {
this.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
} else {
let removedIndex;
let removedNum = oldNumWorkspaces - newNumWorkspaces;
for (let w = 0; w < oldNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
if (this._thumbnails[w].metaWorkspace != metaWorkspace) {
removedIndex = w;
break;
}
}
this.removeThumbnails(removedIndex, removedNum);
}
this._updateSwitcherVisibility();
},
addThumbnails: function(start, count) {
for (let k = start; k < start + count; k++) {
let metaWorkspace = global.screen.get_workspace_by_index(k);
@ -802,7 +957,7 @@ const ThumbnailsBox = new Lang.Class({
this._queueUpdateStates();
},
syncStacking: function(stackIndices) {
_syncStacking: function(actor, stackIndices) {
for (let i = 0; i < this._thumbnails.length; i++)
this._thumbnails[i].syncStacking(stackIndices);
},
@ -1157,5 +1312,30 @@ const ThumbnailsBox = new Lang.Class({
},
onCompleteScope: this
});
},
_onScrollEvent: function (actor, event) {
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
break;
case Clutter.ScrollDirection.DOWN:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
break;
}
},
_onKeyRelease: function (actor, event) {
switch (event.get_key_symbol()) {
case Clutter.KEY_Up:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
break;
case Clutter.KEY_Down:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
break;
case Clutter.KEY_Return:
Main.overview.toggle();
break;
}
}
});

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
@ -22,8 +23,6 @@ const MAX_WORKSPACES = 16;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
const CONTROLS_POP_IN_TIME = 0.1;
const WorkspacesView = new Lang.Class({
Name: 'WorkspacesView',
@ -208,11 +207,11 @@ const WorkspacesView = new Lang.Class({
this._workspaces[w].positionWindows(Workspace.WindowPositionFlags.ANIMATE);
},
_scrollToActive: function(showAnimation) {
_scrollToActive: function() {
let active = global.screen.get_active_workspace_index();
this._updateWorkspaceActors(showAnimation);
this._updateScrollAdjustment(active, showAnimation);
this._updateWorkspaceActors(true);
this._updateScrollAdjustment(active);
},
// Update workspace actors parameters
@ -270,26 +269,21 @@ const WorkspacesView = new Lang.Class({
}
},
_updateScrollAdjustment: function(index, showAnimation) {
_updateScrollAdjustment: function(index) {
if (this._scrolling)
return;
this._animatingScroll = true;
if (showAnimation) {
Tweener.addTween(this.scrollAdjustment, {
value: index,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this._animatingScroll = false;
})
});
} else {
this.scrollAdjustment.value = index;
this._animatingScroll = false;
}
Tweener.addTween(this.scrollAdjustment, {
value: index,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this._animatingScroll = false;
})
});
},
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
@ -316,7 +310,7 @@ const WorkspacesView = new Lang.Class({
if (this._scrolling)
return;
this._scrollToActive(true);
this._scrollToActive();
},
_onDestroy: function() {
@ -390,24 +384,11 @@ const WorkspacesView = new Lang.Class({
this._scrolling = true;
},
endSwipeScroll: function(result) {
endSwipeScroll: function() {
this._scrolling = false;
if (result == Overview.SwipeScrollResult.CLICK) {
let [x, y, mod] = global.get_pointer();
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
x, y);
// 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.
let active = global.screen.get_active_workspace_index();
if (this._workspaces[active].isEmpty() &&
this.actor.contains(actor))
Main.overview.hide();
}
// Make sure title captions etc are shown as necessary
this._scrollToActive();
this._updateVisibility();
},
@ -456,32 +437,39 @@ const WorkspacesDisplay = new Lang.Class({
_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.actor.connect('notify::mapped', Lang.bind(this, this._setupSwipeScrolling));
this.actor.connect('allocate', Lang.bind(this, this._updateWorkspacesGeometry));
this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
this.actor.set_clip_to_allocation(true);
let controls = new St.Bin({ style_class: 'workspace-controls',
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT,
y_align: St.Align.START,
y_fill: true });
this._controls = controls;
this.actor.add_actor(controls);
let clickAction = new Clutter.ClickAction()
clickAction.connect('clicked', Lang.bind(this, function(action) {
// 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 (action.get_button() == 1 &&
this._getPrimaryView().getActiveWorkspace().isEmpty())
Main.overview.hide();
}));
Main.overview.addAction(clickAction);
this.actor.bind_property('mapped', clickAction, 'enabled', GObject.BindingFlags.SYNC_CREATE);
controls.reactive = true;
controls.track_hover = true;
controls.connect('notify::hover',
Lang.bind(this, this._onControlsHoverChanged));
controls.connect('scroll-event',
Lang.bind(this, this._onScrollEvent));
let panAction = new Clutter.PanAction();
panAction.connect('pan', Lang.bind(this, this._onPan));
panAction.connect('gesture-begin', Lang.bind(this, function() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].startSwipeScroll();
return true;
}));
panAction.connect('gesture-end', Lang.bind(this, function() {
clickAction.release();
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll();
}));
Main.overview.addAction(panAction);
this.actor.bind_property('mapped', panAction, 'enabled', GObject.BindingFlags.SYNC_CREATE);
this._primaryIndex = Main.layoutManager.primaryIndex;
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
controls.add_actor(this._thumbnailsBox.actor);
this._workspacesViews = null;
this._primaryScrollAdjustment = null;
@ -494,26 +482,6 @@ const WorkspacesDisplay = new Lang.Class({
this._inDrag = false;
this._cancelledDrag = false;
this._controlsInitiallyHovered = false;
this._alwaysZoomOut = false;
this._zoomOut = false;
this._zoomFraction = 0;
this._updateAlwaysZoom();
// If we stop hiding the overview on layout changes, we will need to
// update the _workspacesViews here
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
this._alwaysZoomOut = true;
}));
Main.xdndHandler.connect('drag-end', Lang.bind(this, function(){
this._alwaysZoomOut = false;
this._updateAlwaysZoom();
}));
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._workspacesChanged));
@ -528,44 +496,20 @@ const WorkspacesDisplay = new Lang.Class({
this._notifyOpacityId = 0;
this._swipeScrollBeginId = 0;
this._swipeScrollEndId = 0;
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._settings.connect('changed::dynamic-workspaces',
Lang.bind(this, this._updateSwitcherVisibility));
},
_updateSwitcherVisibility: function() {
this._thumbnailsBox.actor.visible =
this._settings.get_boolean('dynamic-workspaces') ||
global.screen.n_workspaces > 1;
_onPan: function(action) {
let [dist, dx, dy] = action.get_motion_delta(0);
let adjustment = this._scrollAdjustment;
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
return false;
},
show: function() {
if(!this._alwaysZoomOut) {
let [mouseX, mouseY] = global.get_pointer();
let [x, y] = this._controls.get_transformed_position();
let [width, height] = this._controls.get_transformed_size();
let visibleWidth = this._controls.get_theme_node().get_length('visible-width');
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
if(rtl)
x = x + width - visibleWidth;
if(mouseX > x - 0.5 && mouseX < x + visibleWidth + 0.5 &&
mouseY > y - 0.5 && mouseY < y + height + 0.5)
this._controlsInitiallyHovered = true;
}
this._zoomOut = this._alwaysZoomOut;
this._zoomFraction = this._alwaysZoomOut ? 1 : 0;
this._updateZoom();
this._controls.show();
this._thumbnailsBox.show();
this._updateSwitcherVisibility();
this._updateWorkspacesViews();
this._restackedNotifyId =
global.screen.connect('restacked',
Main.overview.connect('sync-window-stacking',
Lang.bind(this, this._onRestacked));
if (this._itemDragBeginId == 0)
@ -586,8 +530,6 @@ const WorkspacesDisplay = new Lang.Class({
if (this._windowDragEndId == 0)
this._windowDragEndId = Main.overview.connect('window-drag-end',
Lang.bind(this, this._dragEnd));
this._onRestacked();
},
zoomFromOverview: function() {
@ -597,14 +539,8 @@ const WorkspacesDisplay = new Lang.Class({
},
hide: function() {
this._controls.hide();
this._thumbnailsBox.hide();
if (!this._alwaysZoomOut)
this.zoomFraction = 0;
if (this._restackedNotifyId > 0){
global.screen.disconnect(this._restackedNotifyId);
Main.overview.disconnect(this._restackedNotifyId);
this._restackedNotifyId = 0;
}
if (this._itemDragBeginId > 0) {
@ -643,33 +579,6 @@ const WorkspacesDisplay = new Lang.Class({
}
},
_setupSwipeScrolling: function() {
if (this._swipeScrollBeginId)
Main.overview.disconnect(this._swipeScrollBeginId);
this._swipeScrollBeginId = 0;
if (this._swipeScrollEndId)
Main.overview.disconnect(this._swipeScrollEndId);
this._swipeScrollEndId = 0;
if (!this.actor.mapped)
return;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(this._scrollAdjustment,
direction);
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
Lang.bind(this, function() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].startSwipeScroll();
}));
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
Lang.bind(this, function(overview, result) {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll(result);
}));
},
_workspacesOnlyOnPrimaryChanged: function() {
this._workspacesOnlyOnPrimary = this._settings.get_boolean('workspaces-only-on-primary');
@ -709,7 +618,6 @@ const WorkspacesDisplay = new Lang.Class({
this._scrollAdjustment = view.scrollAdjustment;
this._scrollAdjustment.connect('notify::value',
Lang.bind(this, this._scrollValueChanged));
this._setupSwipeScrolling();
}
this._workspacesViews.push(view);
}
@ -748,76 +656,6 @@ const WorkspacesDisplay = new Lang.Class({
return this._getPrimaryView().getActiveWorkspace().hasMaximizedWindows();
},
// zoomFraction property allows us to tween the controls sliding in and out
set zoomFraction(fraction) {
this._zoomFraction = fraction;
this.actor.queue_relayout();
},
get zoomFraction() {
return this._zoomFraction;
},
_updateAlwaysZoom: function() {
// Always show the pager if workspaces are actually used,
// e.g. there are windows on more than one
this._alwaysZoomOut = global.screen.n_workspaces > 2;
if (this._alwaysZoomOut)
return;
let monitors = Main.layoutManager.monitors;
let primary = Main.layoutManager.primaryMonitor;
/* Look for any monitor to the right of the primary, if there is
* one, we always keep zoom out, otherwise its hard to reach
* the thumbnail area without passing into the next monitor. */
for (let i = 0; i < monitors.length; i++) {
if (monitors[i].x >= primary.x + primary.width) {
this._alwaysZoomOut = true;
break;
}
}
},
_getPreferredWidth: function (actor, forHeight, alloc) {
// pass through the call in case the child needs it, but report 0x0
this._controls.get_preferred_width(forHeight);
},
_getPreferredHeight: function (actor, forWidth, alloc) {
// pass through the call in case the child needs it, but report 0x0
this._controls.get_preferred_height(forWidth);
},
_allocate: function (actor, box, flags) {
let childBox = new Clutter.ActorBox();
let totalWidth = box.x2 - box.x1;
// width of the controls
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(box.y2 - box.y1);
// Amount of space on the screen we reserve for the visible control
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
let controlsReserved = controlsVisible * (1 - this._zoomFraction) + controlsNatural * this._zoomFraction;
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
if (rtl) {
childBox.x2 = controlsReserved;
childBox.x1 = childBox.x2 - controlsNatural;
} else {
childBox.x1 = totalWidth - controlsReserved;
childBox.x2 = childBox.x1 + controlsNatural;
}
childBox.y1 = 0;
childBox.y2 = box.y2- box.y1;
this._controls.allocate(childBox, flags);
this._updateWorkspacesGeometry();
},
_parentSet: function(actor, oldParent) {
if (oldParent && this._notifyOpacityId)
oldParent.disconnect(this._notifyOpacityId);
@ -854,24 +692,19 @@ const WorkspacesDisplay = new Lang.Class({
let width = fullWidth;
let height = fullHeight;
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(height);
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
let [x, y] = this.actor.get_transformed_position();
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
let clipWidth = width - controlsVisible;
let clipWidth = width;
let clipHeight = fullHeight;
let clipX = rtl ? x + controlsVisible : x;
let clipX = x;
let clipY = y + (fullHeight - clipHeight) / 2;
let overviewSpacing = Main.overview._spacing;
let widthAdjust = this._zoomOut ? controlsNatural : controlsVisible;
widthAdjust += overviewSpacing;
width -= widthAdjust;
width -= overviewSpacing;
if (rtl)
x += widthAdjust;
x += overviewSpacing;
let monitors = Main.layoutManager.monitors;
let m = 0;
@ -895,25 +728,12 @@ const WorkspacesDisplay = new Lang.Class({
}
},
_onRestacked: function() {
let stack = global.get_window_actors();
let stackIndices = {};
for (let i = 0; i < stack.length; i++) {
// Use the stable sequence for an integer to use as a hash key
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
}
_onRestacked: function(actor, stackIndices) {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].syncStacking(stackIndices);
this._thumbnailsBox.syncStacking(stackIndices);
},
_workspacesChanged: function() {
this._updateAlwaysZoom();
this._updateZoom();
if (this._workspacesViews == null)
return;
@ -938,8 +758,6 @@ const WorkspacesDisplay = new Lang.Class({
}
m++;
}
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
} else {
// Assume workspaces are only removed sequentially
// (e.g. 2,3,4 - not 2,4,7)
@ -962,43 +780,11 @@ const WorkspacesDisplay = new Lang.Class({
lostWorkspaces[l].destroy();
}
}
this._thumbnailsBox.removeThumbnails(removedIndex, removedNum);
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
newNumWorkspaces);
this._updateSwitcherVisibility();
},
_updateZoom : function() {
if (Main.overview.animationInProgress)
return;
let shouldZoom = this._alwaysZoomOut || this._controls.hover;
if (shouldZoom != this._zoomOut) {
this._zoomOut = shouldZoom;
this._updateWorkspacesGeometry();
if (!this._workspacesViews)
return;
Tweener.addTween(this,
{ zoomFraction: this._zoomOut ? 1 : 0,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad' });
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].updateWindowPositions();
}
},
_onControlsHoverChanged: function() {
if(!this._controls.hover)
this._controlsInitiallyHovered = false;
if(!this._controlsInitiallyHovered)
this._updateZoom();
},
_dragBegin: function() {
@ -1016,33 +802,11 @@ const WorkspacesDisplay = new Lang.Class({
},
_onDragMotion: function(dragEvent) {
let controlsHovered = this._controls.contains(dragEvent.targetActor);
this._controls.set_hover(controlsHovered);
return DND.DragMotionResult.CONTINUE;
},
_dragEnd: function() {
this._inDrag = false;
// We do this deferred because drag-end is emitted before dnd.js emits
// event/leave events that were suppressed during the drag. If we didn't
// defer this, we'd zoom out then immediately zoom in because of the
// enter event we received. That would normally be invisible but we
// might as well avoid it.
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
Lang.bind(this, this._updateZoom));
},
_onScrollEvent: function (actor, event) {
switch ( event.get_scroll_direction() ) {
case Clutter.ScrollDirection.UP:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
break;
case Clutter.ScrollDirection.DOWN:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
break;
}
}
});
Signals.addSignalMethods(WorkspacesDisplay.prototype);

View File

@ -17,6 +17,7 @@ js/ui/components/networkAgent.js
js/ui/components/polkitAgent.js
js/ui/components/recorder.js
js/ui/components/telepathyClient.js
js/ui/ctrlAltTab.js
js/ui/dash.js
js/ui/dateMenu.js
js/ui/endSessionDialog.js

796
po/ar.po

File diff suppressed because it is too large Load Diff

371
po/as.po
View File

@ -9,10 +9,10 @@ msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2012-11-26 14:01+0000\n"
"PO-Revision-Date: 2012-11-27 14:40+0530\n"
"POT-Creation-Date: 2012-12-09 13:03+0000\n"
"PO-Revision-Date: 2012-12-10 18:23+0530\n"
"Last-Translator: Nilamdyuti Goswami <ngoswami@redhat.com>\n"
"Language-Team: as_IN <kde-i18n-doc@kde.org>\n"
"Language-Team: Assamese <kde-i18n-doc@kde.org>\n"
"Language: as_IN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -173,68 +173,89 @@ msgid "Whether the users full name is shown in the user menu or not."
msgstr "ব্যৱহাৰকাৰী মেনুত ব্যৱহাৰকাৰীসকলৰ সম্পূৰ্ণ নাম দেখুৱা হয় নে নহয়।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
msgid ""
"Whether to remember password for mounting encrypted or remote filesystems"
msgstr ""
"ইনক্ৰিপ্টেড অথবা দূৰৱৰ্তী ফাইলচিস্টেমসমূহ মাউন্ট কৰাৰ বাবে পাছৱাৰ্ড মনত ৰখা "
"হব নে"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
msgid ""
"The shell will request a password when an encrypted device or a remote "
"filesystem is mounted. If the password can be saved for future use a "
"'Remember Password' checkbox will be present. This key sets the default "
"state of the checkbox."
msgstr ""
"শ্বেলে এটা পাছৱাৰ্ড অনুৰোধ কৰিব যেতিয়া এটা ইনক্ৰিপ্টেড ডিভাইচ অথবা এটা "
"দূৰৱৰ্তী "
"ফাইলচিস্টেম মাউন্ট কৰা হয়। যদি পাছৱাৰ্ডক ভৱিষ্যত ব্যৱহাৰৰ বাবে সংৰক্ষণ কৰিব "
"পাৰি "
"তেন্তে এটা 'পাছৱাৰ্ড মনত ৰাখক' চেকবাকচ উপস্থিত থাকিব। এই কি'য়ে চেকবাকচৰ "
"অবিকল্পিত অৱস্থা সংহতি কৰে।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
msgid "Show the week date in the calendar"
msgstr "কেলেন্ডাৰত সপ্তাহৰ তাৰিখ দেখুৱাওক"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
msgid "If true, display the ISO week date in the calendar."
msgstr "যদি সত্য, ISO সপ্তাহ তাৰিখক কেলেণ্ডাৰত দেখুৱাওক।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
msgid "Keybinding to open the application menu"
msgstr "এপ্লিকেচন মেনু খোলিবলে Keybinding"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
msgid "Keybinding to open the application menu."
msgstr "এপ্লিকেচন মেনু খোলিবলে Keybinding।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
msgid "Keybinding to open the \"Show Applications\" view"
msgstr "\"এপ্লিকেচনসমূহ দেখুৱাওক\" দৰ্শন খোলিবলে কি'বাইণ্ডিং"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
msgid ""
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
msgstr ""
"কাৰ্য্যসমূহ অভাৰভিউৰ \"এপ্লিকেচনসমূহ দেখুৱাওক\" দৰ্শন খোলিবলে কি'বাইণ্ডিং।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
msgid "Keybinding to toggle the visibility of the message tray"
msgstr "বাৰ্তা ট্ৰেৰ দৃশ্যমানতা টগ'ল কৰিবলে Keybinding"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
msgid "Keybinding to toggle the visibility of the message tray."
msgstr "বাৰ্তা ট্ৰেৰ দৃশ্যমানতা টগ'ল কৰিবলে Keybinding।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
msgid "Keybinding to focus the active notification"
msgstr "সক্ৰিয় অধিসূচনা ফকাচ কৰিবলে কি'বাইণ্ডিং"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
msgid "Keybinding to focus the active notification."
msgstr "সক্ৰিয় অধিসূচনা ফকাচ কৰিবলে কি'বাইণ্ডিং।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
msgid "Keybinding to toggle the screen recorder"
msgstr "পৰ্দা ৰেকৰ্ডাৰ অদল বদল কৰিবলে Keybinding"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr "বিল্টইন পৰ্দা ৰেকৰ্ডাৰ আৰম্ভ/বন্ধ কৰিবলে Keybinding।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
msgid "Which keyboard to use"
msgstr "কোনটো কিবৰ্ড ব্যৱহাৰ কৰা হব"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
msgid "The type of keyboard to use."
msgstr "ব্যৱহাৰ কৰিব লগিয়া কিবৰ্ডৰ ধৰণ।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
msgid "Framerate used for recording screencasts."
msgstr "screencasts ৰেকৰ্ড কৰাৰ কাৰণে ব্যৱহৃত Framerate"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
@ -242,11 +263,11 @@ msgstr ""
"GNOME শ্বেলৰ screencast ৰেকৰ্ডাৰে ফ্ৰেইম-প্ৰতি ছেকেণ্ডত ৰেকৰ্ড কৰা পৰিণাম "
"screencast ৰ framerate।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "screencast এনক'ড কৰিবলে ব্যৱহাৰ কৰা gstreamer পাইপলাইন"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
#, no-c-format
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
@ -274,11 +295,11 @@ msgstr ""
"কাওন্টত এটা "
"অনুমানৰ প্লেইচহল্ডাৰ হিচাপে ব্যৱহাৰ কৰা হয়।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:36
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
msgid "File extension used for storing the screencast"
msgstr "screencast সংৰক্ষণ কৰাৰ কাৰণে লথিপত্ৰ সম্প্ৰসাৰন"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
@ -289,20 +310,36 @@ msgstr ""
"অন্তৰ্ভুক্তক "
"বিন্যাসত ৰেকৰ্ড কৰোতে পৰিবৰ্তন কৰিব লাগিব।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
#| msgid "Open the application menu"
msgid "The application icon mode."
msgstr "এপ্লিকেচন আইকন অৱস্থা।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
msgid ""
"Configures how the windows are shown in the switcher. Valid possibilities "
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
"only' (shows only the application icon) or 'both'."
msgstr ""
"চুইচাৰত উইন্ডোসমূহ কেনেধৰণে দেখুৱা হয় সংৰূপণ কৰে। বৈধ সম্ভাবনাসমূহ হল "
"'thumbnail-only' "
"(উইন্ডোৰ এটা থাম্বনেইল দেখুৱায়), 'app-icon-only' (কেৱল এপ্লিকেচন আইকন "
"দেখুৱায়) অথবা 'both'।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
msgid "Attach modal dialog to the parent window"
msgstr "মডাল ডাইলগ উপধায়ক উইন্ডোৰ সৈতে সংলগ্ন কৰক"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
msgid ""
"This key overrides the key in org.gnome.mutter when running GNOME Shell."
msgstr "GNOME শ্বেল চলাওতে এই কি'য়ে org.gnome.mutter ত থকা কি' অভাৰৰাইড কৰে।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
msgid "Arrangement of buttons on the titlebar"
msgstr "শীৰ্ষকবাৰত বুটামসমূহ সজোঁৱা"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
#: ../data/org.gnome.shell.gschema.xml.in.in.h:45
msgid ""
"This key overrides the key in org.gnome.desktop.wm.preferences when running "
"GNOME Shell."
@ -310,15 +347,15 @@ msgstr ""
"GNOME শ্বেল চলাওতে এই কি'য়ে org.gnome.desktop.wm.preferences ত থকা কি' "
"অভাৰৰাইড কৰে।"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
msgid "Enable edge tiling when dropping windows on screen edges"
msgstr "উইন্ডোসমূহক পৰ্দাৰ প্ৰান্তসমূহত এৰোতে প্ৰান্ত টাইলিং সামৰ্থবান কৰক"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
msgid "Workspaces are managed dynamically"
msgstr "কাৰ্য্যস্থানসমূহক চলমানভাৱে ব্যৱস্থাপনা কৰা হয়"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
msgid "Workspaces only on primary monitor"
msgstr "কাৰ্য্যস্থানসমূহ কেৱল প্ৰাথমিক মনিটৰত"
@ -353,8 +390,8 @@ msgstr "তালিকাভুক্ত নহয়?"
#: ../js/gdm/loginDialog.js:962 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:373
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:396
#: ../js/ui/status/bluetooth.js:413 ../js/ui/unlockDialog.js:179
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
#: ../js/ui/status/bluetooth.js:413 ../js/ui/unlockDialog.js:178
msgid "Cancel"
msgstr "বাতিল কৰক"
@ -433,23 +470,23 @@ msgstr "'%s' ৰ প্ৰেৰণ ব্যৰ্থ হল:"
msgid "All"
msgstr "সকলো"
#: ../js/ui/appDisplay.js:317
#: ../js/ui/appDisplay.js:318
msgid "APPLICATIONS"
msgstr "APPLICATIONS"
#: ../js/ui/appDisplay.js:377
#: ../js/ui/appDisplay.js:375
msgid "SETTINGS"
msgstr "SETTINGS"
#: ../js/ui/appDisplay.js:682
#: ../js/ui/appDisplay.js:679
msgid "New Window"
msgstr "নতুন উইন্ডো"
#: ../js/ui/appDisplay.js:685 ../js/ui/dash.js:289
#: ../js/ui/appDisplay.js:682 ../js/ui/dash.js:289
msgid "Remove from Favorites"
msgstr "পছন্দৰ পৰা আতৰাওক"
#: ../js/ui/appDisplay.js:686
#: ../js/ui/appDisplay.js:683
msgid "Add to Favorites"
msgstr "পছন্দলে যোগ কৰক"
@ -722,7 +759,7 @@ msgstr "প্ৰমাণীত কৰক"
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
#: ../js/ui/components/polkitAgent.js:248 ../js/ui/shellMountOperation.js:381
#: ../js/ui/components/polkitAgent.js:248 ../js/ui/shellMountOperation.js:383
msgid "Sorry, that didn't work. Please try again."
msgstr "ক্ষমা কৰিব, সেয়া কাম নকৰিলে। অনুগ্ৰহ কৰি পুনৰ চেষ্টা কৰক।"
@ -760,42 +797,40 @@ msgstr "অমৌন কৰক"
msgid "Mute"
msgstr "মোন কৰক"
#. Translators: this is a time format string followed by the word "Yesterday". i.e. "14:30 on Yesterday"
#: ../js/ui/components/telepathyClient.js:932
#. Translators: this is the word "Yesterday" followed by a time string. i.e. "Yesterday, 14:30"
#: ../js/ui/components/telepathyClient.js:931
#, no-c-format
msgid "<b>%H:%M</b> on Yesterday"
msgstr "<b>%H:%M</b> যোৱাকালী"
msgid "<b>Yesterday</b>, <b>%H:%M</b>"
msgstr "<b>যোৱাকালী</b>, <b>%H:%M</b>"
#. Translators: this is a time format string followed by a week day name. i.e. "14:30 on Monday
#: ../js/ui/components/telepathyClient.js:938
#. Translators: this is the week day name followed by a time string. i.e. "Monday, 14:30
#: ../js/ui/components/telepathyClient.js:937
#, no-c-format
msgid "<b>%H:%M</b> on <b>%A</b>"
msgstr "<b>%A</b> <b>%H:%M</b>"
msgid "<b>%A</b>, <b>%H:%M</b>"
msgstr "<b>%A</b>, <b>%H:%M</b>"
#. Translators: this is a time format in the style of "14:30 on Wednesday, May 25",
#. shown when you get a chat message in the same year
#: ../js/ui/components/telepathyClient.js:944
#. Translators: this is the month name and day number followed by a time string. i.e. "May 25, 14:30"
#: ../js/ui/components/telepathyClient.js:942
#, no-c-format
msgid "<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>"
msgstr "<b>%A</b> <b>%H:%M</b>, <b>%B</b> <b>%d</b>"
msgid "<b>%B</b> <b>%d</b>, <b>%H:%M</b>"
msgstr "<b>%B</b> <b>%d</b>, <b>%H:%M</b>"
#. Translators: this is a time format in the style of "14:30 on Wednesday, May 25, 2012",
#. shown when you get a chat message in a different year
#: ../js/ui/components/telepathyClient.js:949
#. Translators: this is the month name, day number, year number followed by a time string. i.e. "May 25 2012, 14:30"
#: ../js/ui/components/telepathyClient.js:946
#, no-c-format
msgid "<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>, %Y"
msgstr "<b>%A</b> <b>%H:%M</b>, <b>%B</b> <b>%d</b>, %Y"
msgid "<b>%B</b> <b>%d</b> <b>%Y</b>, <b>%H:%M</b> "
msgstr "<b>%B</b> <b>%d</b> <b>%Y</b>, <b>%H:%M</b> "
#. Translators: this is the other person changing their old IM name to their new
#. IM name.
#: ../js/ui/components/telepathyClient.js:977
#: ../js/ui/components/telepathyClient.js:974
#, c-format
msgid "%s is now known as %s"
msgstr "%s এতিয়া %s হিচাপে জনাজাত"
#. translators: argument is a room name like
#. * room@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1076
#: ../js/ui/components/telepathyClient.js:1073
#, c-format
msgid "Invitation to %s"
msgstr "%s লে নিমন্ত্ৰণ"
@ -803,38 +838,38 @@ msgstr "%s লে নিমন্ত্ৰণ"
#. translators: first argument is the name of a contact and the second
#. * one the name of a room. "Alice is inviting you to join room@jabber.org
#. * for example.
#: ../js/ui/components/telepathyClient.js:1084
#: ../js/ui/components/telepathyClient.js:1081
#, c-format
msgid "%s is inviting you to join %s"
msgstr "%s এ আপোনাক %s ত অংশগ্ৰহণ কৰিবলে আমন্ত্ৰণ জনাইছে"
#: ../js/ui/components/telepathyClient.js:1086
#: ../js/ui/components/telepathyClient.js:1125
#: ../js/ui/components/telepathyClient.js:1165
#: ../js/ui/components/telepathyClient.js:1228
#: ../js/ui/components/telepathyClient.js:1083
#: ../js/ui/components/telepathyClient.js:1122
#: ../js/ui/components/telepathyClient.js:1162
#: ../js/ui/components/telepathyClient.js:1225
msgid "Decline"
msgstr "নাকচ কৰক"
#: ../js/ui/components/telepathyClient.js:1087
#: ../js/ui/components/telepathyClient.js:1166
#: ../js/ui/components/telepathyClient.js:1229
#: ../js/ui/components/telepathyClient.js:1084
#: ../js/ui/components/telepathyClient.js:1163
#: ../js/ui/components/telepathyClient.js:1226
msgid "Accept"
msgstr "গ্ৰহন কৰক"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1117
#: ../js/ui/components/telepathyClient.js:1114
#, c-format
msgid "Video call from %s"
msgstr "%s ৰ পৰা ভিডিঅ' কল"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1120
#: ../js/ui/components/telepathyClient.js:1117
#, c-format
msgid "Call from %s"
msgstr "%s ৰ পৰা কল"
#. translators: this is a button label (verb), not a noun
#: ../js/ui/components/telepathyClient.js:1127
#: ../js/ui/components/telepathyClient.js:1124
msgid "Answer"
msgstr "উত্তৰ দিয়ক"
@ -843,110 +878,110 @@ msgstr "উত্তৰ দিয়ক"
#. * file name. The string will be something
#. * like: "Alice is sending you test.ogg"
#.
#: ../js/ui/components/telepathyClient.js:1159
#: ../js/ui/components/telepathyClient.js:1156
#, c-format
msgid "%s is sending you %s"
msgstr "%s এ আপোনাক %s পঠাই আছে"
#. To translators: The parameter is the contact's alias
#: ../js/ui/components/telepathyClient.js:1194
#: ../js/ui/components/telepathyClient.js:1191
#, c-format
msgid "%s would like permission to see when you are online"
msgstr "আপুনি কেতিয়া অনলাইন আছে চাবলে %s এ অনুমতি বিচাৰিব"
#: ../js/ui/components/telepathyClient.js:1286
#: ../js/ui/components/telepathyClient.js:1283
msgid "Network error"
msgstr "নেটৱাৰ্ক ত্ৰুটি"
#: ../js/ui/components/telepathyClient.js:1288
#: ../js/ui/components/telepathyClient.js:1285
msgid "Authentication failed"
msgstr "প্ৰমাণীকৰণ ব্যৰ্থ"
#: ../js/ui/components/telepathyClient.js:1290
#: ../js/ui/components/telepathyClient.js:1287
msgid "Encryption error"
msgstr "ইনক্ৰিপষণ ত্ৰুটি"
#: ../js/ui/components/telepathyClient.js:1292
#: ../js/ui/components/telepathyClient.js:1289
msgid "Certificate not provided"
msgstr "প্ৰমাণপত্ৰ প্ৰদান কৰা হোৱা নাই"
#: ../js/ui/components/telepathyClient.js:1294
#: ../js/ui/components/telepathyClient.js:1291
msgid "Certificate untrusted"
msgstr "প্ৰমাণপত্ৰক ভৰষা কৰিব নোৱাৰি"
#: ../js/ui/components/telepathyClient.js:1296
#: ../js/ui/components/telepathyClient.js:1293
msgid "Certificate expired"
msgstr "প্ৰমাণপত্ৰৰ অৱসান ঘটিছে"
#: ../js/ui/components/telepathyClient.js:1298
#: ../js/ui/components/telepathyClient.js:1295
msgid "Certificate not activated"
msgstr "প্ৰমাণপত্ৰ সক্ৰিয় কৰা হোৱা নাই"
#: ../js/ui/components/telepathyClient.js:1300
#: ../js/ui/components/telepathyClient.js:1297
msgid "Certificate hostname mismatch"
msgstr "প্ৰমাণপত্ৰ হস্টনাম অমিল"
#: ../js/ui/components/telepathyClient.js:1302
#: ../js/ui/components/telepathyClient.js:1299
msgid "Certificate fingerprint mismatch"
msgstr "প্ৰমাণপত্ৰ ফিংগাৰপ্ৰিন্ট অমিল"
#: ../js/ui/components/telepathyClient.js:1304
#: ../js/ui/components/telepathyClient.js:1301
msgid "Certificate self-signed"
msgstr "প্ৰমাণপত্ৰ স্ব-স্বাক্ষৰীত"
#: ../js/ui/components/telepathyClient.js:1306
#: ../js/ui/components/telepathyClient.js:1303
msgid "Status is set to offline"
msgstr "অৱস্থা অফলাইনলে সংহতি কৰা হৈছে"
#: ../js/ui/components/telepathyClient.js:1308
#: ../js/ui/components/telepathyClient.js:1305
msgid "Encryption is not available"
msgstr "ইনক্ৰিপষণ উপলব্ধ নহয়"
#: ../js/ui/components/telepathyClient.js:1310
#: ../js/ui/components/telepathyClient.js:1307
msgid "Certificate is invalid"
msgstr "প্ৰমাণপত্ৰ অবৈধ"
#: ../js/ui/components/telepathyClient.js:1312
#: ../js/ui/components/telepathyClient.js:1309
msgid "Connection has been refused"
msgstr "সংযোগ নাকচ কৰা হৈছে"
#: ../js/ui/components/telepathyClient.js:1314
#: ../js/ui/components/telepathyClient.js:1311
msgid "Connection can't be established"
msgstr "সংযোগ স্থাপন কৰিব নোৱাৰি"
#: ../js/ui/components/telepathyClient.js:1316
#: ../js/ui/components/telepathyClient.js:1313
msgid "Connection has been lost"
msgstr "সংযোগ হেৰাইছে"
#: ../js/ui/components/telepathyClient.js:1318
#: ../js/ui/components/telepathyClient.js:1315
msgid "This account is already connected to the server"
msgstr "এই একাওন্ট ইতিমধ্যে চাৰ্ভাৰৰ সৈতে সংযোগিত"
#: ../js/ui/components/telepathyClient.js:1320
#: ../js/ui/components/telepathyClient.js:1317
msgid ""
"Connection has been replaced by a new connection using the same resource"
msgstr "সংযোগক একে সম্পদ ব্যৱহাৰ কৰি এটা নতুন সংযোগৰে প্ৰতিস্থাপন কৰা হৈছে"
#: ../js/ui/components/telepathyClient.js:1322
#: ../js/ui/components/telepathyClient.js:1319
msgid "The account already exists on the server"
msgstr "একাওন্ট ইতিমধ্যে চাৰ্ভাৰত উপস্থিত"
#: ../js/ui/components/telepathyClient.js:1324
#: ../js/ui/components/telepathyClient.js:1321
msgid "Server is currently too busy to handle the connection"
msgstr "চাৰ্ভাৰ সংযোগ ব্যৱস্থাপনা কৰিবলে বৰ্তমানে অতি ব্যস্ত"
#: ../js/ui/components/telepathyClient.js:1326
#: ../js/ui/components/telepathyClient.js:1323
msgid "Certificate has been revoked"
msgstr "প্ৰমাণপত্ৰ প্ৰত্যাহাৰ কৰা হৈছে"
#: ../js/ui/components/telepathyClient.js:1328
#: ../js/ui/components/telepathyClient.js:1325
msgid ""
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr ""
"প্ৰমাণপত্ৰয় এটা অসুৰক্ষিত চিফাৰ এলগৰিথম ব্যৱহাৰ কৰে অথবা ক্ৰিপ্টোগ্ৰাফিয়ভাৱে "
"দুৰ্বল"
#: ../js/ui/components/telepathyClient.js:1330
#: ../js/ui/components/telepathyClient.js:1327
msgid ""
"The length of the server certificate, or the depth of the server certificate "
"chain, exceed the limits imposed by the cryptography library"
@ -955,26 +990,29 @@ msgstr ""
"ক্ৰিপ্টোগ্ৰাফী "
"লাইব্ৰেৰীয়ে প্ৰণয়ন কৰা সীমাসমূহত অতিক্ৰম কৰে"
#: ../js/ui/components/telepathyClient.js:1332
#: ../js/ui/components/telepathyClient.js:1329
msgid "Internal error"
msgstr "অভ্যন্তৰীক ত্ৰুটি"
#. translators: argument is the account name, like
#. * name@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1342
#: ../js/ui/components/telepathyClient.js:1339
#, c-format
msgid "Unable to connect to %s"
msgstr "%s ৰ সৈতে সংযোগ কৰিবলে অক্ষম"
#: ../js/ui/components/telepathyClient.js:1347
#| msgid "Edit account"
#: ../js/ui/components/telepathyClient.js:1344
msgid "View account"
msgstr "একাওন্ট দৰ্শন কৰক"
#: ../js/ui/components/telepathyClient.js:1387
#: ../js/ui/components/telepathyClient.js:1384
msgid "Unknown reason"
msgstr "অজ্ঞাত কাৰণ"
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:87
msgid "Windows"
msgstr "উইন্ডোসমূহ"
#: ../js/ui/dash.js:253 ../js/ui/dash.js:291
msgid "Show Applications"
msgstr "এপ্লিকেচনসমূহ দেখুৱাওক"
@ -1124,9 +1162,7 @@ msgstr "ত্ৰুটিসমূহ দেখুৱাওক"
msgid "Enabled"
msgstr "সামৰ্থবান কৰা আছে"
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:767 ../src/gvc/gvc-mixer-control.c:1082
#: ../js/ui/lookingGlass.js:767
msgid "Disabled"
msgstr "অসামৰ্থবান কৰা আছে"
@ -1158,15 +1194,15 @@ msgstr "খোলক"
msgid "Remove"
msgstr "আতৰাওক"
#: ../js/ui/messageTray.js:1552
#: ../js/ui/messageTray.js:1551
msgid "No Messages"
msgstr "কোনো বাৰ্তা নাই"
#: ../js/ui/messageTray.js:1569
#: ../js/ui/messageTray.js:1568
msgid "Message Tray"
msgstr "বাৰ্তা ট্ৰে"
#: ../js/ui/messageTray.js:2639
#: ../js/ui/messageTray.js:2635
msgid "System Information"
msgstr "চিস্টেম তথ্য"
@ -1175,11 +1211,11 @@ msgctxt "program"
msgid "Unknown"
msgstr "অজ্ঞাত"
#: ../js/ui/overview.js:107
#: ../js/ui/overview.js:95
msgid "Undo"
msgstr "কাৰ্য্য বাতিল কৰক"
#: ../js/ui/overview.js:155
#: ../js/ui/overview.js:144
msgid "Overview"
msgstr "অভাৰভিউ"
@ -1187,27 +1223,27 @@ msgstr "অভাৰভিউ"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
#: ../js/ui/overview.js:229
#: ../js/ui/overview.js:221
msgid "Type to search..."
msgstr "সন্ধান কৰিবলে টাইপ কৰক..."
#. Translators: this is the name of the dock/favorites area on
#. the left of the overview
#: ../js/ui/overview.js:250
#: ../js/ui/overview.js:242
msgid "Dash"
msgstr "ডেশ"
#: ../js/ui/panel.js:599
#: ../js/ui/panel.js:608
msgid "Quit"
msgstr "প্ৰস্থান কৰক"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:631
#: ../js/ui/panel.js:637
msgid "Activities"
msgstr "কাৰ্য্যসমূহ"
#: ../js/ui/panel.js:999
#: ../js/ui/panel.js:980
msgid "Top Bar"
msgstr "উপৰৰ বাৰ"
@ -1216,7 +1252,7 @@ msgstr "উপৰৰ বাৰ"
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:731
#: ../js/ui/popupMenu.js:732
msgid "toggle-switch-us"
msgstr "toggle-switch-us"
@ -1248,15 +1284,15 @@ msgid_plural "%d new notifications"
msgstr[0] "%d নতুন অধিসূচনা"
msgstr[1] "%d নতুন অধিসূচনাসমূহ"
#: ../js/ui/screenShield.js:401 ../js/ui/userMenu.js:780
#: ../js/ui/screenShield.js:402 ../js/ui/userMenu.js:780
msgid "Lock"
msgstr "লক কৰক"
#: ../js/ui/searchDisplay.js:275
#: ../js/ui/searchDisplay.js:277
msgid "Searching..."
msgstr "সন্ধান কৰা হৈছে..."
#: ../js/ui/searchDisplay.js:323
#: ../js/ui/searchDisplay.js:325
msgid "No results."
msgstr "কোনো ফলাফল নাই।"
@ -1276,15 +1312,15 @@ msgstr "লিখনী দেখুৱাওক"
msgid "Hide Text"
msgstr "লিখনী লুকুৱাওক"
#: ../js/ui/shellMountOperation.js:368
#: ../js/ui/shellMountOperation.js:370
msgid "Password"
msgstr "পাছৱাৰ্ড"
#: ../js/ui/shellMountOperation.js:389
#: ../js/ui/shellMountOperation.js:391
msgid "Remember Password"
msgstr "পাছৱাৰ্ড মনত ৰাখক"
#: ../js/ui/shellMountOperation.js:400 ../js/ui/unlockDialog.js:193
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:192
msgid "Unlock"
msgstr "আনলক কৰক"
@ -1372,7 +1408,7 @@ msgid "disconnecting..."
msgstr "বিচ্ছিনিত কৰা হৈছে..."
#: ../js/ui/status/bluetooth.js:220 ../js/ui/status/network.js:442
#: ../js/ui/status/network.js:1449
#: ../js/ui/status/network.js:1453
msgid "connecting..."
msgstr "সংযোগ কৰা হৈছে..."
@ -1388,7 +1424,7 @@ msgstr "কিবৰ্ড সংহতিসমূহ"
msgid "Mouse Settings"
msgstr "মাউছ আৰু টাচপেড সংহতিসমূহ"
#: ../js/ui/status/bluetooth.js:253 ../js/ui/status/volume.js:234
#: ../js/ui/status/bluetooth.js:253 ../js/ui/status/volume.js:270
msgid "Sound Settings"
msgstr "শব্দ সংহতিসমূহ"
@ -1480,7 +1516,7 @@ msgid "unmanaged"
msgstr "অব্যৱস্থাপিত"
#. Translators: this is for network connections that require some kind of key or password
#: ../js/ui/status/network.js:445 ../js/ui/status/network.js:1452
#: ../js/ui/status/network.js:445 ../js/ui/status/network.js:1456
msgid "authentication required"
msgstr "প্ৰমাণীকৰণৰ প্ৰয়োজন"
@ -1501,72 +1537,72 @@ msgstr "কেবুল আনপ্লাগ্গড"
msgid "unavailable"
msgstr "উপলব্ধ নাই"
#: ../js/ui/status/network.js:469 ../js/ui/status/network.js:1454
#: ../js/ui/status/network.js:469 ../js/ui/status/network.js:1458
msgid "connection failed"
msgstr "সংযোগ ব্যৰ্থ"
#: ../js/ui/status/network.js:525 ../js/ui/status/network.js:1388
#: ../js/ui/status/network.js:1530
#: ../js/ui/status/network.js:525 ../js/ui/status/network.js:1392
#: ../js/ui/status/network.js:1534
msgid "More..."
msgstr "অধিক..."
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
#. and we cannot access its settings (including the name)
#: ../js/ui/status/network.js:561 ../js/ui/status/network.js:1318
#: ../js/ui/status/network.js:561 ../js/ui/status/network.js:1322
msgid "Connected (private)"
msgstr "সংযোগিত (ব্যক্তিগত)"
#: ../js/ui/status/network.js:615
#: ../js/ui/status/network.js:619
msgid "Auto Ethernet"
msgstr "স্বচালিত ইথাৰনেট"
#: ../js/ui/status/network.js:673
#: ../js/ui/status/network.js:677
msgid "Auto broadband"
msgstr "স্বচালিত ব্ৰডবেণ্ড"
#: ../js/ui/status/network.js:676
#: ../js/ui/status/network.js:680
msgid "Auto dial-up"
msgstr "স্বচালিত ডায়েল-আপ"
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
#: ../js/ui/status/network.js:805 ../js/ui/status/network.js:1335
#: ../js/ui/status/network.js:809 ../js/ui/status/network.js:1339
#, c-format
msgid "Auto %s"
msgstr "স্বচালিত %s"
#: ../js/ui/status/network.js:807
#: ../js/ui/status/network.js:811
msgid "Auto bluetooth"
msgstr "স্বচালিত ব্লুটুথ"
#: ../js/ui/status/network.js:1337
#: ../js/ui/status/network.js:1341
msgid "Auto wireless"
msgstr "স্বচালিত বেতাঁৰ"
#: ../js/ui/status/network.js:1579
#: ../js/ui/status/network.js:1584
msgid "Enable networking"
msgstr "নেটৱাৰ্কিং সামৰ্থবান কৰক"
#: ../js/ui/status/network.js:1611
#: ../js/ui/status/network.js:1616
msgid "Wi-Fi"
msgstr "Wi-Fi"
#: ../js/ui/status/network.js:1630
#: ../js/ui/status/network.js:1635
msgid "Network Settings"
msgstr "নেটৱাৰ্ক সংহতিসমূহ"
#: ../js/ui/status/network.js:1674
#: ../js/ui/status/network.js:1679
msgid "Network Manager"
msgstr "নেটৱাৰ্ক ব্যৱস্থাপক"
#: ../js/ui/status/network.js:1756
#: ../js/ui/status/network.js:1761
msgid "Connection failed"
msgstr "সংযোগ ব্যৰ্থ"
#: ../js/ui/status/network.js:1757
#: ../js/ui/status/network.js:1762
msgid "Activation of network connection failed"
msgstr "নেটৱাৰ্ক সংযোগ সক্ৰিয়কৰণ ব্যৰ্থ হল"
#: ../js/ui/status/network.js:2074
#: ../js/ui/status/network.js:2079
msgid "Networking is disabled"
msgstr "নেটৱাৰ্কিং অসামৰ্থবান কৰা আছে"
@ -1668,19 +1704,19 @@ msgid "Unknown"
msgstr "অজ্ঞাত"
#. Translators: This is the label for audio volume
#: ../js/ui/status/volume.js:47 ../js/ui/status/volume.js:221
#: ../js/ui/status/volume.js:50 ../js/ui/status/volume.js:251
msgid "Volume"
msgstr "ভলিউম"
#: ../js/ui/status/volume.js:59
#: ../js/ui/status/volume.js:62
msgid "Microphone"
msgstr "মাইক্ৰোফোন"
#: ../js/ui/unlockDialog.js:202
#: ../js/ui/unlockDialog.js:201
msgid "Log in as another user"
msgstr "অন্য ব্যৱহাৰকাৰী হিচাপে লগিন কৰক"
#: ../js/ui/unlockDialog.js:225
#: ../js/ui/unlockDialog.js:224
msgid "Unlock Window"
msgstr "উইন্ডো আনলক কৰক"
@ -1742,10 +1778,6 @@ msgstr ""
"অনলাইন অৱস্থা ঠিক কৰা হৈছে যাতে আনে জানিব পাৰে যে আপুনি সিহতৰ বাৰ্তা চাব "
"নোৱাৰিবও পাৰে।"
#: ../js/ui/viewSelector.js:87
msgid "Windows"
msgstr "উইন্ডোসমূহ"
#: ../js/ui/viewSelector.js:91
msgid "Applications"
msgstr "এপ্লিকেচনসমূহ"
@ -1754,7 +1786,7 @@ msgstr "এপ্লিকেচনসমূহ"
msgid "Search"
msgstr "সন্ধান কৰক"
#: ../js/ui/wanda.js:117
#: ../js/ui/wanda.js:94
#, c-format
msgid ""
"Sorry, no wisdom for you today:\n"
@ -1763,12 +1795,12 @@ msgstr ""
"ক্ষমা কৰিব, আপোনাৰ বাবে আজি কোনো জ্ঞান নাই:\n"
"%s"
#: ../js/ui/wanda.js:121
#: ../js/ui/wanda.js:98
#, c-format
msgid "%s the Oracle says"
msgstr "%s Oracle এ ক'য়"
#: ../js/ui/wanda.js:162
#: ../js/ui/wanda.js:139
msgid "Your favorite Easter Egg"
msgstr "আপোনাৰ পছন্দৰ Easter Egg"
@ -1781,28 +1813,6 @@ msgstr "'%s' প্ৰস্তুত"
msgid "Evolution Calendar"
msgstr "Evolution কেলেন্ডাৰ"
#. translators:
#. * The number of sound outputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1089
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u আউটপুট"
msgstr[1] "%u আউটপুটসমূহ"
#. translators:
#. * The number of sound inputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1099
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u ইনপুট"
msgstr[1] "%u ইনপুটসমূহ"
#: ../src/gvc/gvc-mixer-control.c:1397
msgid "System Sounds"
msgstr "চিস্টেম শব্দসমূহ"
#: ../src/main.c:332
msgid "Print version"
msgstr "প্ৰিন্ট সংস্কৰণ"
@ -1844,6 +1854,25 @@ msgstr "অবিকল্পিত"
msgid "Authentication dialog was dismissed by the user"
msgstr "প্ৰমাণীকৰণ ডাইলগ ব্যৱহাৰকাৰী দ্বাৰা নাকচ কৰা হৈছিল"
#~ msgid "%u Output"
#~ msgid_plural "%u Outputs"
#~ msgstr[0] "%u আউটপুট"
#~ msgstr[1] "%u আউটপুটসমূহ"
#~ msgid "%u Input"
#~ msgid_plural "%u Inputs"
#~ msgstr[0] "%u ইনপুট"
#~ msgstr[1] "%u ইনপুটসমূহ"
#~ msgid "System Sounds"
#~ msgstr "চিস্টেম শব্দসমূহ"
#~ msgid "<b>%H:%M</b> on Yesterday"
#~ msgstr "<b>%H:%M</b> যোৱাকালী"
#~ msgid "<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>, %Y"
#~ msgstr "<b>%A</b> ত <b>%H:%M</b>, <b>%B</b> <b>%d</b>, %Y"
#~ msgid "Subscription request"
#~ msgstr "স্বাক্ষৰণ অনুৰোধ"

412
po/kn.po
View File

@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2012-09-19 11:02+0000\n"
"PO-Revision-Date: 2012-09-26 16:05+0530\n"
"POT-Creation-Date: 2012-12-07 10:16+0000\n"
"PO-Revision-Date: 2012-12-07 16:12+0530\n"
"Last-Translator: Shankar Prasad <svenkate@redhat.com>\n"
"Language-Team: Kannada <kn@li.org>\n"
"Language: kn\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
"X-Generator: Lokalize 1.2\n"
"X-Generator: Lokalize 1.5\n"
#: ../data/50-gnome-shell-screenshot.xml.in.h:1
msgid "Screenshots"
@ -25,16 +25,15 @@ msgstr "ತೆರೆಚಿತ್ರಗಳು"
#: ../data/50-gnome-shell-screenshot.xml.in.h:2
msgid "Record a screencast"
msgstr ""
msgstr "ಒಂದು ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟನ್ನು ರೆಕಾರ್ಡು ಮಾಡಿ"
#: ../data/50-gnome-shell-system.xml.in.h:1
#| msgid "File System"
msgid "System"
msgstr "ವ್ಯವಸ್ಥೆ"
#: ../data/50-gnome-shell-system.xml.in.h:2
msgid "Show the message tray"
msgstr ""
msgstr "ಸಂದೇಶ ಟ್ರೇ ಅನ್ನು ತೋರಿಸು"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
@ -79,6 +78,12 @@ msgid ""
"list. You can also manipulate this list with the EnableExtension and "
"DisableExtension DBus methods on org.gnome.Shell."
msgstr ""
"GNOME ಶೆಲ್ ವಿಸ್ತರಣೆಗಳು ಒಂದು uuid ಗುಣವನ್ನು ಹೊಂದಿವೆ; ಈ ಕೀಲಿ ಪಟ್ಟಿಯು ಲೋಡ್ "
"ಮಾಡಬೇಕಿರುವ "
"ವಿಸ್ತರಣೆಗಳ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸುತ್ತದೆ. ಯಾವುದೆ ವಿಸ್ತರಣೆಗಳನ್ನು ಲೋಡ್‌ ಮಾಡಬೇಕಿದ್ದಲ್ಲಿ "
"ಅದು ಈ "
"ಪಟ್ಟಿಯಲ್ಲಿ ಇರುವುದು ಅತ್ಯಗತ್ಯ. org.gnome.Shell ನಲ್ಲಿ EnableExtension ಮತ್ತು "
"DisableExtension DBus ವಿಧಾನಗಳನ್ನು ಬಳಸಿಕೊಂಡೂ ಸಹ ಈ ಪಟ್ಟಿಯನ್ನು ನಿರ್ವಹಿಸಬಹುದು."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
msgid "Whether to collect stats about applications usage"
@ -91,6 +96,11 @@ msgid ""
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"ಶೆಲ್‌ ಸಾಮಾನ್ಯವಾಗಿ ಹೆಚ್ಚಾಗಿ ಬಳಸಲಾದ (ಉದಾ. ಆರಂಭಕಗಳಲ್ಲಿ) ಅನ್ವಯಗಳನ್ನು ತೋರಿಸಲು "
"ಸಕ್ರಿಯವಾದವುಗಳನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ನಡೆಸುತ್ತದೆ. ಈ ದತ್ತಾಂಶವನ್ನು ಗೌಪ್ಯವಾಗಿ "
"ಇರಿಸಲಾಗುತ್ತದೆ, "
"ಹಾಗೂ ಗೌಪ್ಯತಾ ಕಾರಣಗಳಿದ್ದಲ್ಲಿ ನೀವು ಅದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು. ಹಾಗೆ ಮಾಡುವುದರಿಂದ "
"ಉಳಿಸಲಾದ ಯಾವದೆ ದತ್ತಾಂಶವು ತೆಗೆದುಹಾಕಲ್ಪಡುವುದಿಲ್ಲ ಎನ್ನುವುದನ್ನು ನೆನಪಿಡಿ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
msgid "List of desktop file IDs for favorite applications"
@ -116,64 +126,75 @@ msgid ""
"Internally used to store the last IM presence explicitly set by the user. "
"The value here is from the TpConnectionPresenceType enumeration."
msgstr ""
"ಆಂತರಿಕವಾಗಿ ಬಳಕೆದಾರರಿಂದ ಸ್ಪಷ್ಟವಾಗಿ ಹೊಂದಿಸಲಾದ ಕೊನೆಯ IM ಅನ್ನು ಶೇಖರಿಸಿಡಸಲು "
"ಬಳಸಲಾಗುತ್ತದೆ. ಇಲ್ಲಿರುವ ಮೌಲ್ಯವು TpConnectionPresenceType ಎನ್ಯೂಮರೇಶನ್‌ನಿಂದ "
"ಬಂದಿರುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
msgid ""
"Internally used to store the last session presence status for the user. The "
"value here is from the GsmPresenceStatus enumeration."
msgstr ""
"ಆಂತರಿಕವಾಗಿ ಬಳಕೆದಾರರಿಂದ ಸ್ಪಷ್ಟವಾಗಿ ಹೊಂದಿಸಲಾದ ಕೊನೆಯ ಅಧಿವೇಶನವನ್ನು ಶೇಖರಿಸಿಡಸಲು "
"ಬಳಸಲಾಗುತ್ತದೆ. ಇಲ್ಲಿರುವ ಮೌಲ್ಯವು GsmPresenceStatus ಎನ್ಯೂಮರೇಶನ್‌ನಿಂದ ಬಂದಿರುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
msgid "Always show the 'Log out' menuitem in the user menu."
msgstr "ಯಾವಾಗಲೂ 'ನಿರ್ಗಮಿಸು' ಪರಿವಿಡಿಅಂಶವನ್ನು ಬಳಕೆದಾರ ಪರಿವಿಡಿಯಲ್ಲಿ ತೋರಿಸು."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
msgid ""
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
"user, single-session situations."
msgstr ""
"ಈ ಕೀಲಿಯು ಏಕ-ಬಳಕೆದಾರ, ಏಕ-ಅಧಿವೇಶನ ಸಂದರ್ಭಗಳಲ್ಲಿ 'ನಿರ್ಗಮಿಸು' ಪರಿವಿಡಿಅಂಶವನ್ನು "
"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅಡಗಿಸುವ ಆಯ್ಕೆಯನ್ನು ಅತಿಕ್ರಮಿಸುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
msgid "Show the week date in the calendar"
msgstr "ಕ್ಯಾಲೆಂಡರಿನಲ್ಲಿ ವಾರದ ದಿನವನ್ನು ತೋರಿಸು"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
msgid "If true, display the ISO week date in the calendar."
msgstr "true ಆದಲ್ಲಿ, ಕ್ಯಾಲೆಂಡರಿನಲ್ಲಿ ISO ವಾರದ ದಿನವನ್ನು ತೋರಿಸುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
msgid "Keybinding to open the application menu"
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
msgid "Keybinding to open the application menu."
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
msgid "Keybinding to toggle the visibility of the message tray"
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
#, fuzzy
#| msgid "Keybinding to open the application menu."
msgid "Keybinding to toggle the visibility of the message tray."
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
#, fuzzy
#| msgid "Keybinding to open the application menu"
msgid "Keybinding to toggle the screen recorder"
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್"
msgid "Keybinding to toggle the visibility of the message tray"
msgstr "ಸಂದೇಶ ಟ್ರೇಯ ಗೋಚರಿಕೆಯನ್ನು ಹೊರಳಿಸಲು ಕೀಬೈಂಡಿಂಗ್"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
#, fuzzy
#| msgid "Keybinding to open the application menu."
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್."
msgid "Keybinding to toggle the visibility of the message tray."
msgstr "ಸಂದೇಶ ಟ್ರೇಯ ಗೋಚರಿಕೆಯನ್ನು ಹೊರಳಿಸಲು ಕೀಬೈಂಡಿಂಗ್."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
msgid "Keybinding to toggle the screen recorder"
msgstr "ತೆರೆ ರೆಕಾರ್ಡರ್ ಅನ್ನು ಹೊರಳಿಸಲು ಕೀಬೈಂಡಿಂಗ್"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr "ಒಳನಿರ್ಮಿತ ತೆರೆ ರೆಕಾರ್ಡರ್ ಅನ್ನು ಆರಂಭಿಸಲು/ನಿಲ್ಲಿಸಲು ಕೀಬೈಂಡಿಂಗ್."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
msgid "Which keyboard to use"
msgstr "ಯಾವ ಕೀಲಿಮಣೆಯನ್ನು ಬಳಸಬೇಕಿದೆ"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
msgid "The type of keyboard to use."
msgstr "ಬಳಸಬೇಕಿರುವ ಕೀಲಿಮಣೆಯ ಬಗೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
msgid "Framerate used for recording screencasts."
msgstr "ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟುಗಳನ್ನು ರೆಕಾರ್ಡು ಮಾಡಲು ಬಳಸಲಾಗುವ ಫ್ರೇಮ್‌ದರಗಳು."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
@ -182,11 +203,11 @@ msgstr ""
"ರೆಕಾರ್ಡು ಮಾಡಲಾದ "
"ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟಿನ ಫ್ರೇಮ್‌ದರ. "
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟ್‍ ಅನ್ನು ಎನ್ಕೋಡ್ ಮಾಡಲು ಬಳಸಲಾಗುವ gstreamer ಪೈಪ್‌ಲೈನ್"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
#, no-c-format
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
@ -200,12 +221,31 @@ msgid ""
"threads=%T ! queue ! webmmux' and records to WEBM using the VP8 codec. %T is "
"used as a placeholder for a guess at the optimal thread count on the system."
msgstr ""
"ರೆಕಾರ್ಡಿಂಗ್‌ಗಳನ್ನು ಎನ್ಕೋಡ್ ಮಾಡಲು ಬಳಸಲಾದ GStreamer ಪೈಪ್‌ಲೈನ್‌ ಅನ್ನು "
"ಹೊಂದಿಸುತ್ತದೆ. ಇದು gst-"
"launch ನಲ್ಲಿ ಬಳಸಲಾದ ಸಿಂಟ್ಯಾಕ್ಸನ್ನು ಅನುಸರಿಸುತ್ತದೆ. ಪೈಪ್‌ಲೈನ್ ವಿಡಿಯೊವನ್ನು "
"ರೆಕಾರ್ಡು ಮಾಡಲು "
"ಒಂದು ನಿಯೋಜಿಸದೇ ಇರುವ ಸಿಂಕ್‌ಪ್ಯಾಡ್‌ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿರಬೇಕು. ಇದು ಸಾಮಾನ್ಯವಾಗಿ "
"ಸಂಪರ್ಕಿತಗೊಂಡಿರದೆ ಇರುವ ಪೈಪ್‌ಲೈನ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ; ಆ ಪ್ಯಾಡ್‌ನಿಂದ ಔಟ್‌ಪುಟ್ "
"ಅನ್ನು ಔಟ್‌ಪುಟ್ "
"ಕಡತಕ್ಕೆ ಬರೆಯಲಾಗುತ್ತದೆ. ಆದರೆ ಪೈಪ್‌ಲೈನ್ ತನ್ನದೆ ಆದ ಔಟ್‌ಪುಟ್ ಅನ್ನು "
"ನೋಡಿಕೊಳ್ಳಬಲ್ಲದು - "
"shout2send ಅಥವ ಅದೇ ರೀತಿಯದರ ಮೂಲಕ icecast ಪೂರೈಕೆಗಣಕಕ್ಕೆ ಔಟ್‌ಪುಟ್ ಅನ್ನು ಕಳುಹಿಸಲು "
"ಇದನ್ನು ಬಳಸಬಹುದಾಗಿರುತ್ತದೆ. ಇದರ ಹೊಂದಿಕೆಯನ್ನು ರದ್ದುಗೊಳಿಸಿದಲ್ಲಿ ಅಥವ ಒಂದು ಖಾಲಿ "
"ಮೌಲ್ಯಕ್ಕೆ "
"ಹೊಂದಿಸಿದಲ್ಲಿ, ಪೂರ್ವನಿಯೋಜಿತ ಪೈಪ್‌ಲೈನ್ ಅನ್ನು ಬಳಸಲಾಗುತ್ತದೆ. ಇದು ಪ್ರಸ್ತುತ 'vp8enc "
"min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! "
"queue ! webmmux' ಆಗಿರುತ್ತದೆ ಮತ್ತು VP8 ಕೋಡೆಕ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು WEBM ಅನ್ನು "
"ರೆಕಾರ್ಡು "
"ಮಾಡುತ್ತದೆ. %T ಎನ್ನು ವ್ಯವಸ್ತೆಯಲ್ಲಿನ ಸೂಕ್ತವಾದ ಎಳೆಯ ಎಣಿಕೆಯನ್ನು ಊಹಿಸಲು ಒಂದು "
"ಪ್ಲೇಸ್‌ಹೋಲ್ಡರ್ "
"ಆಗಿ ಬಳಸಲಾಗುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
msgid "File extension used for storing the screencast"
msgstr "ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟುಗಳನ್ನು ಶೇಖರಿಸಿಡಲು ಬಳಸಲಾಗುವ ಕಡತ ವಿಸ್ತರಣೆಗಳು"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
@ -222,7 +262,6 @@ msgid "There was an error loading the preferences dialog for %s:"
msgstr "%s ಗಾಗಿ ಆದ್ಯತೆಗಳ ಸಂವಾದವನ್ನು ಲೋಡ್ ಮಾಡುವಲ್ಲಿ ದೋಷ ಉಂಟಾಗಿದೆ:"
#: ../js/extensionPrefs/main.js:164
#| msgid "<b>Extension</b>"
msgid "Extension"
msgstr "ವಿಸ್ತರಣೆ"
@ -231,11 +270,11 @@ msgid "Select an extension to configure using the combobox above."
msgstr ""
"ಮೇಲಿನ ಸಂಯೋಜನಾಚೌಕವನ್ನು ಬಳಸಿಕೊಂಡು ಸಂರಚಿಸಬೇಕಿರುವ ಒಂದು ವಿಸ್ತರಣೆಯನ್ನು ಆರಿಸಿ."
#: ../js/gdm/loginDialog.js:526
#: ../js/gdm/loginDialog.js:529
msgid "Session..."
msgstr "ಅಧಿವೇಶನ..."
#: ../js/gdm/loginDialog.js:674
#: ../js/gdm/loginDialog.js:680
msgctxt "title"
msgid "Sign In"
msgstr "ಒಳ ಪ್ರವೇಶಿಸಿ"
@ -243,55 +282,68 @@ msgstr "ಒಳ ಪ್ರವೇಶಿಸಿ"
#. translators: this message is shown below the user list on the
#. login screen. It can be activated to reveal an entry for
#. manually entering the username.
#: ../js/gdm/loginDialog.js:741
#: ../js/gdm/loginDialog.js:740
msgid "Not listed?"
msgstr "ಪಟ್ಟಿಯಲ್ಲಿಲ್ಲವೆ?"
#: ../js/gdm/loginDialog.js:894 ../js/ui/components/networkAgent.js:137
#: ../js/gdm/loginDialog.js:898 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:373
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:396
#: ../js/ui/status/bluetooth.js:427 ../js/ui/unlockDialog.js:166
#: ../js/ui/status/bluetooth.js:427 ../js/ui/unlockDialog.js:168
msgid "Cancel"
msgstr "ರದ್ದು ಮಾಡು"
#: ../js/gdm/loginDialog.js:899
#: ../js/gdm/loginDialog.js:903
msgctxt "button"
msgid "Sign In"
msgstr "ಒಳಗೆ ಪ್ರವೇಶಿಸು"
#: ../js/gdm/loginDialog.js:1238
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
#: ../js/gdm/loginDialog.js:962 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "ಬಳಕೆದಾರ ಹೆಸರು: "
#: ../js/gdm/loginDialog.js:1269
msgid "Login Window"
msgstr "ಪ್ರವೇಶದ ಕಿಟಕಿ"
#: ../js/gdm/powerMenu.js:88 ../js/ui/userMenu.js:658 ../js/ui/userMenu.js:662
#: ../js/ui/userMenu.js:773
#. Translators: accessible name of the power menu in the login screen
#: ../js/gdm/powerMenu.js:35
#| msgid "Power Off"
msgid "Power"
msgstr "ವಿದ್ಯುಚ್ಛಕ್ತಿ"
#: ../js/gdm/powerMenu.js:89 ../js/ui/userMenu.js:664 ../js/ui/userMenu.js:668
#: ../js/ui/userMenu.js:779
msgid "Suspend"
msgstr "ಅಮಾನತ್ತಿನಲ್ಲಿಡು"
#: ../js/gdm/powerMenu.js:93
#: ../js/gdm/powerMenu.js:94
msgid "Restart"
msgstr "ಮರಳಿ ಆರಂಭಿಸು"
#: ../js/gdm/powerMenu.js:98 ../js/ui/userMenu.js:660 ../js/ui/userMenu.js:662
#: ../js/ui/userMenu.js:772
#: ../js/gdm/powerMenu.js:99 ../js/ui/userMenu.js:666 ../js/ui/userMenu.js:668
#: ../js/ui/userMenu.js:778
msgid "Power Off"
msgstr "ಸ್ಥಗಿತಗೊಳಿಸು"
#: ../js/gdm/util.js:148
#| msgid "Authentication Required"
#: ../js/gdm/util.js:152
msgid "Authentication error"
msgstr "ದೃಢೀಕರಣ ದೋಷ"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:265
#: ../js/gdm/util.js:269
msgid "(or swipe finger)"
msgstr "(ಅಥವ ನಿಮ್ಮ ಬೆರಳನ್ನು ಉಜ್ಜಿ)"
#: ../js/gdm/util.js:290
#: ../js/gdm/util.js:294
#, c-format
msgid "(e.g., user or %s)"
msgstr ""
msgstr "(ಉದಾ., ಬಳಕೆದಾರ ಅಥವ %s)"
#: ../js/misc/util.js:92
msgid "Command not found"
@ -325,7 +377,7 @@ msgstr "SETTINGS"
msgid "New Window"
msgstr "ಹೊಸ ವಿಂಡೊ"
#: ../js/ui/appDisplay.js:678 ../js/ui/dash.js:271
#: ../js/ui/appDisplay.js:678 ../js/ui/dash.js:290
msgid "Remove from Favorites"
msgstr "ಎಲ್ಲಾ ಅಚ್ಚುಮೆಚ್ಚಿನವುಗಳನ್ನು ತೆಗೆದುಹಾಕು"
@ -489,16 +541,16 @@ msgstr "ಈ ವಾರ"
msgid "Next week"
msgstr "ಮುಂದಿನ ವಾರ"
#: ../js/ui/components/autorunManager.js:278
#: ../js/ui/components/autorunManager.js:297
msgid "Removable Devices"
msgstr "ತೆಗೆದುಹಾಕಬಹುದಾದ ಸಾಧನಗಳು"
#: ../js/ui/components/autorunManager.js:575
#: ../js/ui/components/autorunManager.js:594
#, c-format
msgid "Open with %s"
msgstr "%s ನೊಂದಿಗೆ ತೆರೆ"
#: ../js/ui/components/autorunManager.js:601
#: ../js/ui/components/autorunManager.js:620
msgid "Eject"
msgstr "ಹೊರತಳ್ಳು"
@ -528,14 +580,6 @@ msgstr "ದಾಟುಪದ: "
msgid "Key: "
msgstr "ಕೀಲಿ: "
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
#: ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "ಬಳಕೆದಾರ ಹೆಸರು: "
#: ../js/ui/components/networkAgent.js:266
msgid "Identity: "
msgstr "ಗುರುತು: "
@ -646,7 +690,7 @@ msgstr "ಸಂಪರ್ಕ ದೋಷ"
#: ../js/ui/components/telepathyClient.js:491
msgid "Unmute"
msgstr ""
msgstr "ಮಾತುಬರಿಸು"
#: ../js/ui/components/telepathyClient.js:491
msgid "Mute"
@ -655,35 +699,35 @@ msgstr "ಮೂಕಗೊಳಿಸು"
#. Translators: this is a time format string followed by a date.
#. If applicable, replace %X with a strftime format valid for your
#. locale, without seconds.
#: ../js/ui/components/telepathyClient.js:948
#: ../js/ui/components/telepathyClient.js:952
#, no-c-format
msgid "Sent at <b>%X</b> on <b>%A</b>"
msgstr "<b>%A</b> ರಂದು <b>%X</b> ಗೆ ಕಳುಹಿಸಲಾಗಿದೆ"
#. Translators: this is a time format in the style of "Wednesday, May 25",
#. shown when you get a chat message in the same year.
#: ../js/ui/components/telepathyClient.js:954
#: ../js/ui/components/telepathyClient.js:958
#, no-c-format
msgid "Sent on <b>%A</b>, <b>%B %d</b>"
msgstr "<b>%A</b>, <b>%B %d</b> ರಂದು ಕಳುಹಿಸಲಾಗಿದೆ"
#. Translators: this is a time format in the style of "Wednesday, May 25, 2012",
#. shown when you get a chat message in a different year.
#: ../js/ui/components/telepathyClient.js:959
#: ../js/ui/components/telepathyClient.js:963
#, no-c-format
msgid "Sent on <b>%A</b>, <b>%B %d</b>, %Y"
msgstr "%A</b>, <b>%B %d</b>, %Y ರಂದು ಕಳುಹಿಸಲಾಗಿದೆ"
#. Translators: this is the other person changing their old IM name to their new
#. IM name.
#: ../js/ui/components/telepathyClient.js:988
#: ../js/ui/components/telepathyClient.js:992
#, c-format
msgid "%s is now known as %s"
msgstr "%s ಈಗ %s ಆಗಿದ್ದಾರೆ"
#. translators: argument is a room name like
#. * room@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1088
#: ../js/ui/components/telepathyClient.js:1092
#, c-format
msgid "Invitation to %s"
msgstr "%s ಗಾಗಿನ ಆಹ್ವಾನ"
@ -691,42 +735,42 @@ msgstr "%s ಗಾಗಿನ ಆಹ್ವಾನ"
#. translators: first argument is the name of a contact and the second
#. * one the name of a room. "Alice is inviting you to join room@jabber.org
#. * for example.
#: ../js/ui/components/telepathyClient.js:1096
#: ../js/ui/components/telepathyClient.js:1100
#, c-format
msgid "%s is inviting you to join %s"
msgstr "%s ನಿಮ್ಮನ್ನು %s ಗೆ ಸೇರುವಂತೆ ಆಹ್ವಾನಿಸುತ್ತಿದ್ದಾರೆ"
#: ../js/ui/components/telepathyClient.js:1098
#: ../js/ui/components/telepathyClient.js:1177
#: ../js/ui/components/telepathyClient.js:1240
#: ../js/ui/components/telepathyClient.js:1102
#: ../js/ui/components/telepathyClient.js:1181
#: ../js/ui/components/telepathyClient.js:1244
msgid "Decline"
msgstr "ತಿರಸ್ಕರಿಸು"
#: ../js/ui/components/telepathyClient.js:1099
#: ../js/ui/components/telepathyClient.js:1178
#: ../js/ui/components/telepathyClient.js:1241
#: ../js/ui/components/telepathyClient.js:1103
#: ../js/ui/components/telepathyClient.js:1182
#: ../js/ui/components/telepathyClient.js:1245
msgid "Accept"
msgstr "ಅಂಗೀಕರಿಸು"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1129
#: ../js/ui/components/telepathyClient.js:1133
#, c-format
msgid "Video call from %s"
msgstr "%s ಇಂದ ವೀಡಿಯೊ ಕರೆ ಬಂದಿದೆ"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1132
#: ../js/ui/components/telepathyClient.js:1136
#, c-format
msgid "Call from %s"
msgstr "%s ಇಂದ ಕರೆ ಬಂದಿದೆ"
#: ../js/ui/components/telepathyClient.js:1137
#: ../js/ui/components/telepathyClient.js:1141
#: ../js/ui/status/bluetooth.js:346
msgid "Reject"
msgstr "ತಿರಸ್ಕರಿಸು"
#. translators: this is a button label (verb), not a noun
#: ../js/ui/components/telepathyClient.js:1139
#: ../js/ui/components/telepathyClient.js:1143
msgid "Answer"
msgstr "ಉತ್ತರ"
@ -735,106 +779,106 @@ msgstr "ಉತ್ತರ"
#. * file name. The string will be something
#. * like: "Alice is sending you test.ogg"
#.
#: ../js/ui/components/telepathyClient.js:1171
#: ../js/ui/components/telepathyClient.js:1175
#, c-format
msgid "%s is sending you %s"
msgstr "%s ರವರು ನಿಮಗೆ %s ಅನ್ನು ಕಳುಹಿಸುತ್ತಿದ್ದಾರೆ"
#. To translators: The parameter is the contact's alias
#: ../js/ui/components/telepathyClient.js:1206
#: ../js/ui/components/telepathyClient.js:1210
#, c-format
msgid "%s would like permission to see when you are online"
msgstr ""
"ನೀವು ಯಾವಾಗ ಆನ್‌ಲೈನ್‌ನಲ್ಲಿ ಇರುತ್ತೀರಿ ಎಂದು ತಿಳಿಯಲು %s ರವರು ನಿಮ್ಮ ಅನುಮತಿಯನ್ನು "
"ಕೋರಿದ್ದಾರೆ"
#: ../js/ui/components/telepathyClient.js:1298
#: ../js/ui/components/telepathyClient.js:1302
msgid "Network error"
msgstr "ಜಾಲಬಂಧದ ದೋಷ"
#: ../js/ui/components/telepathyClient.js:1300
#: ../js/ui/components/telepathyClient.js:1304
msgid "Authentication failed"
msgstr "ದೃಢೀಕರಣವು ವಿಫಲಗೊಂಡಿದೆ"
#: ../js/ui/components/telepathyClient.js:1302
#: ../js/ui/components/telepathyClient.js:1306
msgid "Encryption error"
msgstr "ಗೂಢಲಿಪೀಕರಣ ದೋಷ"
#: ../js/ui/components/telepathyClient.js:1304
#: ../js/ui/components/telepathyClient.js:1308
msgid "Certificate not provided"
msgstr "ಪ್ರಮಾಣಪತ್ರವನ್ನು ಒದಗಿಸಲಾಗಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1306
#: ../js/ui/components/telepathyClient.js:1310
msgid "Certificate untrusted"
msgstr "ಪ್ರಮಾಣಪತ್ರವನ್ನು ನಂಬಲಾಗಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1308
#: ../js/ui/components/telepathyClient.js:1312
msgid "Certificate expired"
msgstr "ಪ್ರಮಾಣಪತ್ರದ ಕಾಲಾವಧಿ ತೀರಿದೆ"
#: ../js/ui/components/telepathyClient.js:1310
#: ../js/ui/components/telepathyClient.js:1314
msgid "Certificate not activated"
msgstr "ಪ್ರಮಾಣಪತ್ರವು ಸಕ್ರಿಯಗೊಂಡಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1312
#: ../js/ui/components/telepathyClient.js:1316
msgid "Certificate hostname mismatch"
msgstr "ಪ್ರಮಾಣಪತ್ರದ ಅತಿಥೇಯದ ಹೆಸರು ತಾಳೆಯಾಗುತ್ತಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1314
#: ../js/ui/components/telepathyClient.js:1318
msgid "Certificate fingerprint mismatch"
msgstr "ಪ್ರಮಾಣಪತ್ರದ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ತಾಳೆಯಾಗುತ್ತಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1316
#: ../js/ui/components/telepathyClient.js:1320
msgid "Certificate self-signed"
msgstr "ಪ್ರಮಾಣಪತ್ರವು ಸ್ವತಃ ಸೈನ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"
#: ../js/ui/components/telepathyClient.js:1318
#: ../js/ui/components/telepathyClient.js:1322
msgid "Status is set to offline"
msgstr "ಸ್ಥಿತಿಯನ್ನು ಆಫ್‌ಲೈನ್‌ ಎಂದು ಸೂಚಿಸಿದ್ದಾರೆ."
#: ../js/ui/components/telepathyClient.js:1320
#: ../js/ui/components/telepathyClient.js:1324
msgid "Encryption is not available"
msgstr "ಗೂಢಲಿಪೀಕರಣ ಲಭ್ಯವಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1322
#: ../js/ui/components/telepathyClient.js:1326
msgid "Certificate is invalid"
msgstr "ಪ್ರಮಾಣಪತ್ರವು ಅಮಾನ್ಯವಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1324
#: ../js/ui/components/telepathyClient.js:1328
msgid "Connection has been refused"
msgstr "ಸಂಪರ್ಕವನ್ನು ನಿರಾಕರಿಸಲಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1326
#: ../js/ui/components/telepathyClient.js:1330
msgid "Connection can't be established"
msgstr "ಸಂಪರ್ಕವನ್ನು ಸಾಧಿಸಲಾಗಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1328
#: ../js/ui/components/telepathyClient.js:1332
msgid "Connection has been lost"
msgstr "ಸಂಪರ್ಕವು ಕಡಿದು ಹೋಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1330
#: ../js/ui/components/telepathyClient.js:1334
msgid "This account is already connected to the server"
msgstr "ಈ ಖಾತೆಯು ಈಗಾಗಲೆ ಪರಿಚಾರಕದೊಂದಿಗೆ ಸಂಪರ್ಕ ಜೋಡಿಸಲಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1332
#: ../js/ui/components/telepathyClient.js:1336
msgid ""
"Connection has been replaced by a new connection using the same resource"
msgstr ""
"ಒಂದು ಹೊಸ ಸಂಪರ್ಕದಿಂದ ಈ ಸಂಪರ್ಕವನ್ನು ಇದೇ ಸಂಪನ್ಮೂಲವನ್ನು ಬಳಸಿಕೊಂಡು ಬದಲಾಯಿಸಲಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1334
#: ../js/ui/components/telepathyClient.js:1338
msgid "The account already exists on the server"
msgstr "ಖಾತೆಯು ಈಗಾಗಲೆ ಪರಿಚಾರಕದಲ್ಲಿ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ"
#: ../js/ui/components/telepathyClient.js:1336
#: ../js/ui/components/telepathyClient.js:1340
msgid "Server is currently too busy to handle the connection"
msgstr "ಪರಿಚಾರಕಕ್ಕೆ ಬಿಡುವಿಲ್ಲದ ಕಾರಣ ಸಂಪರ್ಕವನ್ನು ನಿಭಾಯಿಸಲಾಗುತ್ತಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1338
#: ../js/ui/components/telepathyClient.js:1342
msgid "Certificate has been revoked"
msgstr "ಪ್ರಮಾಣಪತ್ರವನ್ನು ಹಿಂದಕ್ಕೆ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1340
#: ../js/ui/components/telepathyClient.js:1344
msgid ""
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr ""
@ -842,7 +886,7 @@ msgstr ""
"ಗೂಢಲಿಪೀಕರಣವನ್ನು "
"ಹೊಂದಿದೆ"
#: ../js/ui/components/telepathyClient.js:1342
#: ../js/ui/components/telepathyClient.js:1346
msgid ""
"The length of the server certificate, or the depth of the server certificate "
"chain, exceed the limits imposed by the cryptography library"
@ -851,31 +895,30 @@ msgstr ""
"ಲೈಬ್ರರಿಯಿಂದ "
"ನಿಗದಿ ಪಡಿಸಲಾದ ಮಿತಿಗಳನ್ನು ಮೀರಿದೆ."
#: ../js/ui/components/telepathyClient.js:1344
#: ../js/ui/components/telepathyClient.js:1348
msgid "Internal error"
msgstr "ಆಂತರಿಕ ತಪ್ಪು"
#. translators: argument is the account name, like
#. * name@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1354
#: ../js/ui/components/telepathyClient.js:1358
#, c-format
msgid "Connection to %s failed"
msgstr "%s ಗಾಗಿನ ಸಂಪರ್ಕವು ವಿಫಲಗೊಂಡಿದೆ"
#: ../js/ui/components/telepathyClient.js:1363
#: ../js/ui/components/telepathyClient.js:1367
msgid "Reconnect"
msgstr "ಮರಳಿ ಸಂಪರ್ಕ ಜೋಡಿಸು"
#: ../js/ui/components/telepathyClient.js:1364
#: ../js/ui/components/telepathyClient.js:1368
msgid "Edit account"
msgstr "ಖಾತೆಯನ್ನು ಸಂಪಾದಿಸು"
#: ../js/ui/components/telepathyClient.js:1409
#: ../js/ui/components/telepathyClient.js:1413
msgid "Unknown reason"
msgstr "ಅಜ್ಞಾತ ಕಾರಣ"
#: ../js/ui/dash.js:245 ../js/ui/dash.js:273
#| msgid "Applications"
#: ../js/ui/dash.js:254 ../js/ui/dash.js:292
msgid "Show Applications"
msgstr "ಅನ್ವಯಗಳನ್ನು ತೋರಿಸು"
@ -883,14 +926,14 @@ msgstr "ಅನ್ವಯಗಳನ್ನು ತೋರಿಸು"
msgid "Date and Time Settings"
msgstr "ದಿನಾಂಕ ಹಾಗು ಸಮಯದ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/dateMenu.js:109
#: ../js/ui/dateMenu.js:111
msgid "Open Calendar"
msgstr "ಕ್ಯಾಲೆಂಡರನ್ನು ತೆರೆ"
#. 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").
#.
#: ../js/ui/dateMenu.js:175
#: ../js/ui/dateMenu.js:201
msgid "%A %B %e, %Y"
msgstr "%A %B %e, %Y"
@ -995,11 +1038,11 @@ msgid "Download and install '%s' from extensions.gnome.org?"
msgstr ""
"'%s' ಅನ್ನು extensions.gnome.org ಇಂದ ಡೌನ್‌ಲೋಡ್ ಮಾಡಿಕೊಂಡು ಅನುಸ್ಥಾಪಿಸಬೇಕೆ?"
#: ../js/ui/keyboard.js:327
#: ../js/ui/keyboard.js:337
msgid "tray"
msgstr "ಟ್ರೇ"
#: ../js/ui/keyboard.js:561 ../js/ui/status/keyboard.js:194
#: ../js/ui/keyboard.js:584 ../js/ui/status/keyboard.js:195
#: ../js/ui/status/power.js:205
msgid "Keyboard"
msgstr "ಕೀಲಿಮಣೆ"
@ -1052,24 +1095,23 @@ msgstr "ಆಕರವನ್ನು ನೋಡಿ"
msgid "Web Page"
msgstr "ಜಾಲ ಪುಟ"
#: ../js/ui/messageTray.js:1080
#: ../js/ui/messageTray.js:1084
msgid "Open"
msgstr "ತೆರೆ"
#: ../js/ui/messageTray.js:1087
#: ../js/ui/messageTray.js:1091
msgid "Remove"
msgstr "ತೆಗೆದು ಹಾಕು"
#: ../js/ui/messageTray.js:2052
#: ../js/ui/messageTray.js:1531
msgid "Message Tray"
msgstr ""
msgstr "ಸಂದೇಶ ಟ್ರೇ"
#: ../js/ui/messageTray.js:2508
#: ../js/ui/messageTray.js:2543
msgid "System Information"
msgstr "ವ್ಯವಸ್ಥೆಯ ಮಾಹಿತಿ"
#: ../js/ui/notificationDaemon.js:506 ../src/shell-app.c:373
#| msgid "Unknown"
#: ../js/ui/notificationDaemon.js:506 ../src/shell-app.c:374
msgctxt "program"
msgid "Unknown"
msgstr "ಗೊತ್ತಿಲ್ಲದ"
@ -1125,33 +1167,29 @@ msgstr "ದಯವಿಟ್ಟು ಒಂದು ಆಜ್ಞೆಯನ್ನು ನ
#. Translators: This is a time format for a date in
#. long format
#: ../js/ui/screenShield.js:79
#| msgctxt "calendar heading"
#| msgid "%A, %B %d"
#: ../js/ui/screenShield.js:81
msgid "%A, %B %d"
msgstr "%A, %B %d"
#: ../js/ui/screenShield.js:144
#: ../js/ui/screenShield.js:145
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "%d ಹೊಸ ಸಂದೇಶ"
msgstr[1] "%d ಹೊಸ ಸಂದೇಶಗಳು"
#: ../js/ui/screenShield.js:146
#, fuzzy, c-format
#| msgid "Notifications"
#: ../js/ui/screenShield.js:147
#, c-format
msgid "%d new notification"
msgid_plural "%d new notifications"
msgstr[0] "ಸೂಚನೆಗಳು"
msgstr[1] "ಸೂಚನೆಗಳು"
msgstr[0] "%d ಹೊಸ ಸೂಚನೆ"
msgstr[1] "%d ಹೊಸ ಸೂಚನೆಗಳು"
#: ../js/ui/searchDisplay.js:275
msgid "Searching..."
msgstr "ಹುಡುಕಲಾಗುತ್ತಿದೆ..."
#: ../js/ui/searchDisplay.js:323
#| msgid "No matching results."
msgid "No results."
msgstr "ಯಾವುದೆ ಫಲಿತಾಂಶಗಳಿಲ್ಲ."
@ -1172,18 +1210,16 @@ msgid "Hide Text"
msgstr "ಪಠ್ಯವನ್ನು ಅಡಗಿಸು"
#: ../js/ui/shellMountOperation.js:368
#| msgid "Password:"
msgid "Password"
msgstr "ಗುಪ್ತಪದ"
#: ../js/ui/shellMountOperation.js:389
#| msgid "Password:"
msgid "Remember Password"
msgstr "ಈ ಗುಪ್ತಪದವನ್ನು ನೆನಪಿನಲ್ಲಿಡು"
#: ../js/ui/shellMountOperation.js:400 ../js/ui/unlockDialog.js:169
#: ../js/ui/shellMountOperation.js:400 ../js/ui/unlockDialog.js:171
msgid "Unlock"
msgstr ""
msgstr "ಅನ್‌ಲಾಕ್ ಮಾಡು"
#: ../js/ui/status/accessibility.js:39
msgid "Accessibility"
@ -1299,7 +1335,7 @@ msgstr "ಕೀಲಿಮಣೆ ಸಿದ್ಧತೆಗಳು"
msgid "Mouse Settings"
msgstr "ಮೌಸ್‌ನ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/status/bluetooth.js:269 ../js/ui/status/volume.js:236
#: ../js/ui/status/bluetooth.js:269 ../js/ui/status/volume.js:234
msgid "Sound Settings"
msgstr "ಧ್ವನಿಯ ಸಿದ್ಧತೆಗಳು"
@ -1332,10 +1368,10 @@ msgid "Device %s wants to pair with this computer"
msgstr "%s ಎನ್ನುವ ಸಾಧನದೊಂದಿಗೆ ಸಂಪರ್ಕ ಜೋಡಿಸಲು ಬಯಸುತ್ತಿದೆ"
#: ../js/ui/status/bluetooth.js:379
#, fuzzy, c-format
#| msgid "Please confirm whether the PIN '%s' matches the one on the device."
#, c-format
msgid "Please confirm whether the PIN '%06d' matches the one on the device."
msgstr "'%s' ಎನ್ನುವ PIN ಸಾಧನದಲ್ಲಿರುವುದಕ್ಕೆ ತಾಳೆಯಾಗುತ್ತದೆಯೆ ಎಂದು ಖಚಿತಪಡಿಸಿ."
msgstr ""
"'%06d' ಎಂಬ PIN ಸಾಧನದಲ್ಲಿರುವುದಕ್ಕೆ ತಾಳೆಯಾಗುತ್ತದೆಯೆ ಎಂದು ದಯವಿಟ್ಟು ಖಚಿತಪಡಿಸಿ."
#: ../js/ui/status/bluetooth.js:381
msgid "Matches"
@ -1358,17 +1394,17 @@ msgstr "ದಯವಿಟ್ಟು ಸಾಧನದಲ್ಲಿ ಸೂಚಿಸಿ
msgid "OK"
msgstr "ಸರಿ"
#: ../js/ui/status/keyboard.js:227
#: ../js/ui/status/keyboard.js:228
msgid "Show Keyboard Layout"
msgstr "ಕೀಲಿಮಣೆ ವಿನ್ಯಾಸವನ್ನು ತೋರಿಸು"
#: ../js/ui/status/keyboard.js:232
#: ../js/ui/status/keyboard.js:233
msgid "Region and Language Settings"
msgstr "ಪ್ರದೇಶ ಮತ್ತು ಭಾಷೆ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/status/lockScreenMenu.js:18
msgid "Volume, network, battery"
msgstr ""
msgstr "ಧ್ವನಿಪ್ರಮಾಣ, ಜಾಲಬಂಧ, ಬ್ಯಾಟರಿ"
#: ../js/ui/status/network.js:94
msgid "<unknown>"
@ -1580,13 +1616,12 @@ msgid "Computer"
msgstr "ಗಣಕ"
#: ../js/ui/status/power.js:217
#| msgid "Unknown"
msgctxt "device"
msgid "Unknown"
msgstr "ಗೊತ್ತಿಲ್ಲದ"
#. Translators: This is the label for audio volume
#: ../js/ui/status/volume.js:47 ../js/ui/status/volume.js:223
#: ../js/ui/status/volume.js:47 ../js/ui/status/volume.js:221
msgid "Volume"
msgstr "ಧ್ವನಿ ಪ್ರಮಾಣ"
@ -1594,75 +1629,71 @@ msgstr "ಧ್ವನಿ ಪ್ರಮಾಣ"
msgid "Microphone"
msgstr "ಮೈಕ್ರೊಫೋನ್"
#: ../js/ui/unlockDialog.js:176
#: ../js/ui/unlockDialog.js:178
msgid "Log in as another user"
msgstr ""
msgstr "ಇನ್ನೊಬ್ಬ ಬಳಕೆದಾರನಾಗಿ ಪ್ರವೇಶಿಸಿ"
#: ../js/ui/userMenu.js:175
#: ../js/ui/userMenu.js:181
msgid "Available"
msgstr "ಲಭ್ಯ"
#: ../js/ui/userMenu.js:178
#: ../js/ui/userMenu.js:184
msgid "Busy"
msgstr "ಕಾರ್ಯನಿರತ"
#: ../js/ui/userMenu.js:181
#: ../js/ui/userMenu.js:187
msgid "Invisible"
msgstr "ಅಗೋಚರ"
#: ../js/ui/userMenu.js:184
#: ../js/ui/userMenu.js:190
msgid "Away"
msgstr "ಹೊರಗೆ ಹೋಗಿದ್ದೇನೆ"
#: ../js/ui/userMenu.js:187
#: ../js/ui/userMenu.js:193
msgid "Idle"
msgstr "ಜಡ"
#: ../js/ui/userMenu.js:190
#: ../js/ui/userMenu.js:196
msgid "Unavailable"
msgstr "ಅಲಭ್ಯ"
#: ../js/ui/userMenu.js:613 ../js/ui/userMenu.js:754
msgid "Switch User"
msgstr "ಬಳಕೆದಾರನನ್ನು ಬದಲಿಸು"
#: ../js/ui/userMenu.js:614
#, fuzzy
#| msgid "Switch User"
msgid "Switch Session"
msgstr "ಬಳಕೆದಾರನನ್ನು ಬದಲಿಸು"
#: ../js/ui/userMenu.js:738
#: ../js/ui/userMenu.js:744
msgid "Notifications"
msgstr "ಸೂಚನೆಗಳು"
#: ../js/ui/userMenu.js:746
#: ../js/ui/userMenu.js:752
msgid "System Settings"
msgstr "ವ್ಯವಸ್ಥೆಯ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/userMenu.js:759
#| msgctxt "title"
#| msgid "Log Out"
#: ../js/ui/userMenu.js:760
msgid "Switch User"
msgstr "ಬಳಕೆದಾರನನ್ನು ಬದಲಿಸು"
#: ../js/ui/userMenu.js:765
msgid "Log Out"
msgstr "ನಿರ್ಗಮಿಸು"
#: ../js/ui/userMenu.js:764
#: ../js/ui/userMenu.js:770
msgid "Lock"
msgstr ""
msgstr "ಲಾಕ್ ಮಾಡು"
#: ../js/ui/userMenu.js:779
#: ../js/ui/userMenu.js:785
msgid "Install Updates & Restart"
msgstr ""
msgstr "ಅಪ್‌ಡೇಟ್‌ಗಳನ್ನು ಅನುಸ್ಥಾಪಿಸು ಮತ್ತು ಮರಳಿಸ್ಥಾಪಿಸು"
#: ../js/ui/userMenu.js:797
#: ../js/ui/userMenu.js:803
msgid "Your chat status will be set to busy"
msgstr "ನಿಮ್ಮ ಹರಟೆಯ ಸ್ಥಿತಿಯನ್ನು ಕಾರ್ಯನಿರತರಾಗಿದ್ದಾರೆ ಎಂದು ಬದಲಾಯಿಸಲಾಗಿದೆ."
#: ../js/ui/userMenu.js:798
#: ../js/ui/userMenu.js:804
msgid ""
"Notifications are now disabled, including chat messages. Your online status "
"has been adjusted to let others know that you might not see their messages."
msgstr ""
"ಸಂಭಾಷಣೆಯ ಸಂದೇಶಗಳೂ ಸಹ ಸೇರಿದಂತೆ ಸೂಚನೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿರುತ್ತದೆ. ನೀವು "
"ಬೇರೆಯವರಿಂದ ಬಂದ ಸಂದೇಶಗಳನ್ನು ನೀವು ನೋಡಿಲ್ಲ ಎಂದು ಅವರಿಗೆ ಗೊತ್ತಾಗುವಂತೆ ನಿಮ್ಮ "
"ಆನ್‌ಲೈನ್ "
"ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿಸಲಾಗಿರುತ್ತದೆ."
#: ../js/ui/viewSelector.js:85
msgid "Windows"
@ -1676,7 +1707,7 @@ msgstr "ಅನ್ವಯಗಳು"
msgid "Search"
msgstr "ಹುಡುಕು"
#: ../js/ui/wanda.js:119
#: ../js/ui/wanda.js:117
#, c-format
msgid ""
"Sorry, no wisdom for you today:\n"
@ -1685,12 +1716,12 @@ msgstr ""
"ಕ್ಷಮಿಸಿ, ನಿಮಗಾಗಿ ಯಾವುದೆ ವಿವೇಕವಾಣಿ ಇಲ್ಲ :\n"
"%s"
#: ../js/ui/wanda.js:123
#: ../js/ui/wanda.js:121
#, c-format
msgid "%s the Oracle says"
msgstr "%s Oracle ಹೇಳುವಂತೆ"
#: ../js/ui/wanda.js:164
#: ../js/ui/wanda.js:162
msgid "Your favorite Easter Egg"
msgstr "ನಿಮ್ಮ ಮೆಚ್ಚಿನ ಈಸ್ಟರ್ ಮೊಟ್ಟೆ"
@ -1700,7 +1731,6 @@ msgid "'%s' is ready"
msgstr "'%s' ಸಿದ್ಧಗೊಂಡಿದೆ"
#: ../src/calendar-server/evolution-calendar.desktop.in.in.h:1
#| msgid "Open Calendar"
msgid "Evolution Calendar"
msgstr "Evolution ಕ್ಯಾಲೆಂಡರ್"
@ -1726,23 +1756,23 @@ msgstr[1] "%u ಇನ್‌ಪುಟ್‌ಗಳು"
msgid "System Sounds"
msgstr "ವ್ಯವಸ್ಥೆಯ ಧ್ವನಿಗಳು"
#: ../src/main.c:330
#: ../src/main.c:332
msgid "Print version"
msgstr "ಮುದ್ರಿಸಬಹುದಾದ ಆವೃತ್ತಿ"
#: ../src/main.c:336
#: ../src/main.c:338
msgid "Mode used by GDM for login screen"
msgstr "ಪ್ರವೇಶದ ತೆರೆಗಾಗಿ GDM ಬಳಸಿದ ಪ್ರಕಾರ"
#: ../src/main.c:342
#: ../src/main.c:344
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
msgstr ""
msgstr "ನಿಶ್ಚಿತ ಸ್ಥಿತಿಯನ್ನು ಬಳಸು, ಉದಾ. ಪ್ರವೇಶ ತೆರೆಗಾಗಿ \"gdm\""
#: ../src/main.c:348
#: ../src/main.c:350
msgid "List possible modes"
msgstr ""
msgstr "ಸಾಧ್ಯವಿರುವ ಸ್ಥಿತಿಗಳನ್ನು ಪಟ್ಟಿ ಮಾಡು"
#: ../src/shell-app.c:621
#: ../src/shell-app.c:622
#, c-format
msgid "Failed to launch '%s'"
msgstr "'%s' ಅನ್ನು ಆರಂಭಿಸುವಲ್ಲಿ ವಿಫಲಗೊಂಡಿದೆ"
@ -1767,6 +1797,10 @@ msgstr "ಪೂರ್ವನಿಯೋಜಿತ"
msgid "Authentication dialog was dismissed by the user"
msgstr "ದೃಢೀಕರಣದ ಸಂವಾದವನ್ನು ಬಳಕೆದಾರರಿಂದ ತಿರಸ್ಕರಿಸಲಾಗಿದೆ"
#~| msgid "Switch User"
#~ msgid "Switch Session"
#~ msgstr "ಅಧಿವೇಶನವನ್ನು ಬದಲಿಸು"
#~ msgid "disabled OpenSearch providers"
#~ msgstr "ಅಶಕ್ತಗೊಳಿಸಲಾದ OpenSearch ಒದಗಿಸುವವರು"

599
po/nb.po

File diff suppressed because it is too large Load Diff

730
po/pa.po

File diff suppressed because it is too large Load Diff

940
po/ta.po

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +0,0 @@
noinst_LTLIBRARIES += libgvc.la
libgvc_la_CPPFLAGS = \
$(WARN_CFLAGS) \
$(GVC_CFLAGS) \
-I$(srcdir)/gvc/ \
-DWITH_INTROSPECTION \
-DG_LOG_DOMAIN="\"Gvc\""
libgvc_la_LIBADD = \
$(GVC_LIBS)
libgvc_la_LDFLAGS = -avoid-version
libgvc_la_gir_sources = \
gvc/gvc-mixer-stream.h \
gvc/gvc-mixer-stream.c \
gvc/gvc-channel-map.h \
gvc/gvc-channel-map.c \
gvc/gvc-mixer-card.c \
gvc/gvc-mixer-card.h \
gvc/gvc-mixer-sink.h \
gvc/gvc-mixer-sink.c \
gvc/gvc-mixer-source.h \
gvc/gvc-mixer-source.c \
gvc/gvc-mixer-sink-input.h \
gvc/gvc-mixer-sink-input.c \
gvc/gvc-mixer-source-output.h \
gvc/gvc-mixer-source-output.c \
gvc/gvc-mixer-event-role.h \
gvc/gvc-mixer-event-role.c \
gvc/gvc-mixer-control.h \
gvc/gvc-mixer-control.c
libgvc_la_private_sources = \
gvc/gvc-mixer-stream-private.h \
gvc/gvc-channel-map-private.h \
gvc/gvc-mixer-card-private.h \
gvc/gvc-mixer-control-private.h \
gvc/gvc-pulseaudio-fake.h
libgvc_la_SOURCES = \
$(libgvc_la_gir_sources) \
$(libgvc_la_private_sources)
Gvc-1.0.gir: libgvc.la
Gvc_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0
Gvc_1_0_gir_CFLAGS = $(INCLUDES) -I$(srcdir)/gvc -DWITH_INTROSPECTION
Gvc_1_0_gir_LIBS = libgvc.la
Gvc_1_0_gir_FILES = $(addprefix $(srcdir)/,$(libgvc_la_gir_sources))
INTROSPECTION_GIRS += Gvc-1.0.gir
CLEANFILES += Gvc-1.0.gir

View File

@ -87,6 +87,21 @@ stamp-st.h: Makefile
BUILT_SOURCES += st.h
CLEANFILES += stamp-st.h
st-scroll-view-fade-generated.c: stamp-st-scroll-view-fade-generated.c
@true
stamp-st-scroll-view-fade-generated.c: $(srcdir)/st/st-scroll-view-fade.glsl $(srcdir)/data-to-c.pl
$(AM_V_GEN) $(srcdir)/data-to-c.pl $(srcdir)/st/st-scroll-view-fade.glsl st_scroll_view_fade_glsl > $@.tmp && \
(cmp -s $@.tmp st-scroll-view-fade-generated.c || cp $@.tmp st-scroll-view-fade-generated.c) && \
rm -f $@.tmp && \
echo timestamp > $(@F)
BUILT_SOURCES += st-scroll-view-fade-generated.c
CLEANFILES += stamp-st-scroll-view-fade-generated.c
EXTRA_DIST += \
st/st-scroll-view-fade.glsl \
data-to-c.pl \
$(NULL)
st_source_private_h = \
st/st-private.h \
st/st-table-private.h \

View File

@ -8,6 +8,8 @@ noinst_LTLIBRARIES =
noinst_PROGRAMS =
service_in_files =
SUBDIRS = gvc
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS =
INTROSPECTION_SCANNER_ARGS = --warn-all --warn-error --add-include-path=$(srcdir)
@ -79,7 +81,6 @@ CLEANFILES += gnome-shell $(bin_SCRIPTS)
include Makefile-st.am
include Makefile-tray.am
include Makefile-gvc.am
include Makefile-calendar-server.am
include Makefile-hotplug-sniffer.am
@ -284,7 +285,7 @@ libgnome_shell_la_LIBADD = \
$(BLUETOOTH_LIBS) \
libst-1.0.la \
libtray.la \
libgvc.la \
gvc/libgvc.la \
$(NULL)
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)

39
src/data-to-c.pl Executable file
View File

@ -0,0 +1,39 @@
#!/usr/bin/perl
# Copyright © 2011 Red Hat, Inc
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the licence, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#
# Author: Kalev Lember <kalevlember@gmail.com>
if (@ARGV != 2) {
die "Usage: data-to-c.pl <filename> <variable>\n";
}
$file = $ARGV[0];
open (FILE, $file) || die "Cannot open $file: $!\n";
printf ("const char %s[] = \"", $ARGV[1]);
while (my $line = <FILE>) {
foreach my $c (split //, $line) {
printf ("\\x%02x", ord ($c));
}
}
print "\";\n";
close (FILE);

View File

@ -93,6 +93,7 @@ def start_shell():
args.append('--replace')
if options.sync:
args.append('--sync')
args += params
return subprocess.Popen(args, env=env)
def run_shell():
@ -156,11 +157,7 @@ parser.add_option("", "--sync", action="store_true")
parser.add_option("", "--version", action="callback", callback=show_version,
help="Display version and exit")
options, args = parser.parse_args()
if args:
parser.print_usage()
sys.exit(1)
options, params = parser.parse_args()
# Handle ssh logins
if 'DISPLAY' not in os.environ:

1
src/gvc Submodule

Submodule src/gvc added at 40cdff2479

View File

@ -1,39 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_CHANNEL_MAP_PRIVATE_H
#define __GVC_CHANNEL_MAP_PRIVATE_H
#include <glib-object.h>
#include <pulse/pulseaudio.h>
G_BEGIN_DECLS
GvcChannelMap * gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *map);
const pa_channel_map * gvc_channel_map_get_pa_channel_map (const GvcChannelMap *map);
void gvc_channel_map_volume_changed (GvcChannelMap *map,
const pa_cvolume *cv,
gboolean set);
const pa_cvolume * gvc_channel_map_get_cvolume (const GvcChannelMap *map);
G_END_DECLS
#endif /* __GVC_CHANNEL_MAP_PRIVATE_H */

View File

@ -1,252 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <pulse/pulseaudio.h>
#include "gvc-channel-map.h"
#include "gvc-channel-map-private.h"
#define GVC_CHANNEL_MAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapPrivate))
struct GvcChannelMapPrivate
{
pa_channel_map pa_map;
gboolean pa_volume_is_set;
pa_cvolume pa_volume;
gdouble extern_volume[NUM_TYPES]; /* volume, balance, fade, lfe */
gboolean can_balance;
gboolean can_fade;
};
enum {
VOLUME_CHANGED,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
static void gvc_channel_map_class_init (GvcChannelMapClass *klass);
static void gvc_channel_map_init (GvcChannelMap *channel_map);
static void gvc_channel_map_finalize (GObject *object);
G_DEFINE_TYPE (GvcChannelMap, gvc_channel_map, G_TYPE_OBJECT)
guint
gvc_channel_map_get_num_channels (const GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), 0);
if (!pa_channel_map_valid(&map->priv->pa_map))
return 0;
return map->priv->pa_map.channels;
}
const gdouble *
gvc_channel_map_get_volume (GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
if (!pa_channel_map_valid(&map->priv->pa_map))
return NULL;
map->priv->extern_volume[VOLUME] = (gdouble) pa_cvolume_max (&map->priv->pa_volume);
if (gvc_channel_map_can_balance (map))
map->priv->extern_volume[BALANCE] = (gdouble) pa_cvolume_get_balance (&map->priv->pa_volume, &map->priv->pa_map);
else
map->priv->extern_volume[BALANCE] = 0;
if (gvc_channel_map_can_fade (map))
map->priv->extern_volume[FADE] = (gdouble) pa_cvolume_get_fade (&map->priv->pa_volume, &map->priv->pa_map);
else
map->priv->extern_volume[FADE] = 0;
if (gvc_channel_map_has_lfe (map))
map->priv->extern_volume[LFE] = (gdouble) pa_cvolume_get_position (&map->priv->pa_volume, &map->priv->pa_map, PA_CHANNEL_POSITION_LFE);
else
map->priv->extern_volume[LFE] = 0;
return map->priv->extern_volume;
}
gboolean
gvc_channel_map_can_balance (const GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
return map->priv->can_balance;
}
gboolean
gvc_channel_map_can_fade (const GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
return map->priv->can_fade;
}
const char *
gvc_channel_map_get_mapping (const GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
if (!pa_channel_map_valid(&map->priv->pa_map))
return NULL;
return pa_channel_map_to_pretty_name (&map->priv->pa_map);
}
/**
* gvc_channel_map_has_position: (skip)
* @map:
* @position:
*
* Returns:
*/
gboolean
gvc_channel_map_has_position (const GvcChannelMap *map,
pa_channel_position_t position)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
return pa_channel_map_has_position (&(map->priv->pa_map), position);
}
const pa_channel_map *
gvc_channel_map_get_pa_channel_map (const GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
if (!pa_channel_map_valid(&map->priv->pa_map))
return NULL;
return &map->priv->pa_map;
}
const pa_cvolume *
gvc_channel_map_get_cvolume (const GvcChannelMap *map)
{
g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
if (!pa_channel_map_valid(&map->priv->pa_map))
return NULL;
return &map->priv->pa_volume;
}
static void
gvc_channel_map_class_init (GvcChannelMapClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = gvc_channel_map_finalize;
signals [VOLUME_CHANGED] =
g_signal_new ("volume-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GvcChannelMapClass, volume_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
g_type_class_add_private (klass, sizeof (GvcChannelMapPrivate));
}
void
gvc_channel_map_volume_changed (GvcChannelMap *map,
const pa_cvolume *cv,
gboolean set)
{
g_return_if_fail (GVC_IS_CHANNEL_MAP (map));
g_return_if_fail (cv != NULL);
g_return_if_fail (pa_cvolume_compatible_with_channel_map(cv, &map->priv->pa_map));
if (pa_cvolume_equal(cv, &map->priv->pa_volume))
return;
map->priv->pa_volume = *cv;
if (map->priv->pa_volume_is_set == FALSE) {
map->priv->pa_volume_is_set = TRUE;
return;
}
g_signal_emit (map, signals[VOLUME_CHANGED], 0, set);
}
static void
gvc_channel_map_init (GvcChannelMap *map)
{
map->priv = GVC_CHANNEL_MAP_GET_PRIVATE (map);
map->priv->pa_volume_is_set = FALSE;
}
static void
gvc_channel_map_finalize (GObject *object)
{
GvcChannelMap *channel_map;
g_return_if_fail (object != NULL);
g_return_if_fail (GVC_IS_CHANNEL_MAP (object));
channel_map = GVC_CHANNEL_MAP (object);
g_return_if_fail (channel_map->priv != NULL);
G_OBJECT_CLASS (gvc_channel_map_parent_class)->finalize (object);
}
GvcChannelMap *
gvc_channel_map_new (void)
{
GObject *map;
map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL);
return GVC_CHANNEL_MAP (map);
}
static void
set_from_pa_map (GvcChannelMap *map,
const pa_channel_map *pa_map)
{
g_assert (pa_channel_map_valid(pa_map));
map->priv->can_balance = pa_channel_map_can_balance (pa_map);
map->priv->can_fade = pa_channel_map_can_fade (pa_map);
map->priv->pa_map = *pa_map;
pa_cvolume_set(&map->priv->pa_volume, pa_map->channels, PA_VOLUME_NORM);
}
GvcChannelMap *
gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *pa_map)
{
GObject *map;
map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL);
set_from_pa_map (GVC_CHANNEL_MAP (map), pa_map);
return GVC_CHANNEL_MAP (map);
}

View File

@ -1,73 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_CHANNEL_MAP_H
#define __GVC_CHANNEL_MAP_H
#include <glib-object.h>
#include <gvc-pulseaudio-fake.h>
G_BEGIN_DECLS
#define GVC_TYPE_CHANNEL_MAP (gvc_channel_map_get_type ())
#define GVC_CHANNEL_MAP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMap))
#define GVC_CHANNEL_MAP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass))
#define GVC_IS_CHANNEL_MAP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_CHANNEL_MAP))
#define GVC_IS_CHANNEL_MAP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_CHANNEL_MAP))
#define GVC_CHANNEL_MAP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass))
typedef struct GvcChannelMapPrivate GvcChannelMapPrivate;
typedef struct
{
GObject parent;
GvcChannelMapPrivate *priv;
} GvcChannelMap;
typedef struct
{
GObjectClass parent_class;
void (*volume_changed) (GvcChannelMap *channel_map, gboolean set);
} GvcChannelMapClass;
enum {
VOLUME,
BALANCE,
FADE,
LFE,
NUM_TYPES
};
GType gvc_channel_map_get_type (void);
GvcChannelMap * gvc_channel_map_new (void);
guint gvc_channel_map_get_num_channels (const GvcChannelMap *map);
const gdouble * gvc_channel_map_get_volume (GvcChannelMap *map);
gboolean gvc_channel_map_can_balance (const GvcChannelMap *map);
gboolean gvc_channel_map_can_fade (const GvcChannelMap *map);
gboolean gvc_channel_map_has_position (const GvcChannelMap *map,
pa_channel_position_t position);
#define gvc_channel_map_has_lfe(x) gvc_channel_map_has_position (x, PA_CHANNEL_POSITION_LFE)
const char * gvc_channel_map_get_mapping (const GvcChannelMap *map);
G_END_DECLS
#endif /* __GVC_CHANNEL_MAP_H */

View File

@ -1,35 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008-2009 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_CARD_PRIVATE_H
#define __GVC_MIXER_CARD_PRIVATE_H
#include <pulse/pulseaudio.h>
#include "gvc-mixer-card.h"
G_BEGIN_DECLS
GvcMixerCard * gvc_mixer_card_new (pa_context *context,
guint index);
pa_context * gvc_mixer_card_get_pa_context (GvcMixerCard *card);
G_END_DECLS
#endif /* __GVC_MIXER_CARD_PRIVATE_H */

View File

@ -1,514 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
* Copyright (C) 2009 Bastien Nocera
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <pulse/pulseaudio.h>
#include "gvc-mixer-card.h"
#include "gvc-mixer-card-private.h"
#define GVC_MIXER_CARD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardPrivate))
static guint32 card_serial = 1;
struct GvcMixerCardPrivate
{
pa_context *pa_context;
guint id;
guint index;
char *name;
char *icon_name;
char *profile;
char *target_profile;
char *human_profile;
GList *profiles;
pa_operation *profile_op;
};
enum
{
PROP_0,
PROP_ID,
PROP_PA_CONTEXT,
PROP_INDEX,
PROP_NAME,
PROP_ICON_NAME,
PROP_PROFILE,
PROP_HUMAN_PROFILE,
};
static void gvc_mixer_card_class_init (GvcMixerCardClass *klass);
static void gvc_mixer_card_init (GvcMixerCard *mixer_card);
static void gvc_mixer_card_finalize (GObject *object);
G_DEFINE_TYPE (GvcMixerCard, gvc_mixer_card, G_TYPE_OBJECT)
static guint32
get_next_card_serial (void)
{
guint32 serial;
serial = card_serial++;
if ((gint32)card_serial < 0) {
card_serial = 1;
}
return serial;
}
pa_context *
gvc_mixer_card_get_pa_context (GvcMixerCard *card)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
return card->priv->pa_context;
}
guint
gvc_mixer_card_get_index (GvcMixerCard *card)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
return card->priv->index;
}
guint
gvc_mixer_card_get_id (GvcMixerCard *card)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
return card->priv->id;
}
const char *
gvc_mixer_card_get_name (GvcMixerCard *card)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
return card->priv->name;
}
gboolean
gvc_mixer_card_set_name (GvcMixerCard *card,
const char *name)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
g_free (card->priv->name);
card->priv->name = g_strdup (name);
g_object_notify (G_OBJECT (card), "name");
return TRUE;
}
const char *
gvc_mixer_card_get_icon_name (GvcMixerCard *card)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
return card->priv->icon_name;
}
gboolean
gvc_mixer_card_set_icon_name (GvcMixerCard *card,
const char *icon_name)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
g_free (card->priv->icon_name);
card->priv->icon_name = g_strdup (icon_name);
g_object_notify (G_OBJECT (card), "icon-name");
return TRUE;
}
/**
* gvc_mixer_card_get_profile: (skip)
* @card:
*
* Returns:
*/
GvcMixerCardProfile *
gvc_mixer_card_get_profile (GvcMixerCard *card)
{
GList *l;
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
g_return_val_if_fail (card->priv->profiles != NULL, NULL);
for (l = card->priv->profiles; l != NULL; l = l->next) {
GvcMixerCardProfile *p = l->data;
if (g_str_equal (card->priv->profile, p->profile)) {
return p;
}
}
g_assert_not_reached ();
return NULL;
}
gboolean
gvc_mixer_card_set_profile (GvcMixerCard *card,
const char *profile)
{
GList *l;
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
g_free (card->priv->profile);
card->priv->profile = g_strdup (profile);
g_free (card->priv->human_profile);
card->priv->human_profile = NULL;
for (l = card->priv->profiles; l != NULL; l = l->next) {
GvcMixerCardProfile *p = l->data;
if (g_str_equal (card->priv->profile, p->profile)) {
card->priv->human_profile = g_strdup (p->human_profile);
break;
}
}
g_object_notify (G_OBJECT (card), "profile");
return TRUE;
}
static void
_pa_context_set_card_profile_by_index_cb (pa_context *context,
int success,
void *userdata)
{
GvcMixerCard *card = GVC_MIXER_CARD (userdata);
g_assert (card->priv->target_profile);
if (success > 0) {
gvc_mixer_card_set_profile (card, card->priv->target_profile);
} else {
g_debug ("Failed to switch profile on '%s' from '%s' to '%s'",
card->priv->name,
card->priv->profile,
card->priv->target_profile);
}
g_free (card->priv->target_profile);
card->priv->target_profile = NULL;
pa_operation_unref (card->priv->profile_op);
card->priv->profile_op = NULL;
}
gboolean
gvc_mixer_card_change_profile (GvcMixerCard *card,
const char *profile)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
/* Same profile, or already requested? */
if (g_strcmp0 (card->priv->profile, profile) == 0)
return TRUE;
if (g_strcmp0 (profile, card->priv->target_profile) == 0)
return TRUE;
if (card->priv->profile_op != NULL) {
pa_operation_cancel (card->priv->profile_op);
pa_operation_unref (card->priv->profile_op);
card->priv->profile_op = NULL;
}
if (card->priv->profile != NULL) {
g_free (card->priv->target_profile);
card->priv->target_profile = g_strdup (profile);
card->priv->profile_op = pa_context_set_card_profile_by_index (card->priv->pa_context,
card->priv->index,
card->priv->target_profile,
_pa_context_set_card_profile_by_index_cb,
card);
if (card->priv->profile_op == NULL) {
g_warning ("pa_context_set_card_profile_by_index() failed");
return FALSE;
}
} else {
g_assert (card->priv->human_profile == NULL);
card->priv->profile = g_strdup (profile);
}
return TRUE;
}
/**
* gvc_mixer_card_get_profiles:
*
* Return value: (transfer none) (element-type GvcMixerCardProfile):
*/
const GList *
gvc_mixer_card_get_profiles (GvcMixerCard *card)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
return card->priv->profiles;
}
static int
sort_profiles (GvcMixerCardProfile *a,
GvcMixerCardProfile *b)
{
if (a->priority == b->priority)
return 0;
if (a->priority > b->priority)
return 1;
return -1;
}
/**
* gvc_mixer_card_set_profiles:
* @profiles: (transfer full) (element-type GvcMixerCardProfile):
*/
gboolean
gvc_mixer_card_set_profiles (GvcMixerCard *card,
GList *profiles)
{
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
g_return_val_if_fail (card->priv->profiles == NULL, FALSE);
card->priv->profiles = g_list_sort (profiles, (GCompareFunc) sort_profiles);
return TRUE;
}
static void
gvc_mixer_card_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GvcMixerCard *self = GVC_MIXER_CARD (object);
switch (prop_id) {
case PROP_PA_CONTEXT:
self->priv->pa_context = g_value_get_pointer (value);
break;
case PROP_INDEX:
self->priv->index = g_value_get_ulong (value);
break;
case PROP_ID:
self->priv->id = g_value_get_ulong (value);
break;
case PROP_NAME:
gvc_mixer_card_set_name (self, g_value_get_string (value));
break;
case PROP_ICON_NAME:
gvc_mixer_card_set_icon_name (self, g_value_get_string (value));
break;
case PROP_PROFILE:
gvc_mixer_card_set_profile (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gvc_mixer_card_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GvcMixerCard *self = GVC_MIXER_CARD (object);
switch (prop_id) {
case PROP_PA_CONTEXT:
g_value_set_pointer (value, self->priv->pa_context);
break;
case PROP_INDEX:
g_value_set_ulong (value, self->priv->index);
break;
case PROP_ID:
g_value_set_ulong (value, self->priv->id);
break;
case PROP_NAME:
g_value_set_string (value, self->priv->name);
break;
case PROP_ICON_NAME:
g_value_set_string (value, self->priv->icon_name);
break;
case PROP_PROFILE:
g_value_set_string (value, self->priv->profile);
break;
case PROP_HUMAN_PROFILE:
g_value_set_string (value, self->priv->human_profile);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GObject *
gvc_mixer_card_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
GObject *object;
GvcMixerCard *self;
object = G_OBJECT_CLASS (gvc_mixer_card_parent_class)->constructor (type, n_construct_properties, construct_params);
self = GVC_MIXER_CARD (object);
self->priv->id = get_next_card_serial ();
return object;
}
static void
gvc_mixer_card_class_init (GvcMixerCardClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructor = gvc_mixer_card_constructor;
gobject_class->finalize = gvc_mixer_card_finalize;
gobject_class->set_property = gvc_mixer_card_set_property;
gobject_class->get_property = gvc_mixer_card_get_property;
g_object_class_install_property (gobject_class,
PROP_INDEX,
g_param_spec_ulong ("index",
"Index",
"The index for this card",
0, G_MAXULONG, 0,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_ID,
g_param_spec_ulong ("id",
"id",
"The id for this card",
0, G_MAXULONG, 0,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_PA_CONTEXT,
g_param_spec_pointer ("pa-context",
"PulseAudio context",
"The PulseAudio context for this card",
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string ("name",
"Name",
"Name to display for this card",
NULL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_ICON_NAME,
g_param_spec_string ("icon-name",
"Icon Name",
"Name of icon to display for this card",
NULL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_PROFILE,
g_param_spec_string ("profile",
"Profile",
"Name of current profile for this card",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_HUMAN_PROFILE,
g_param_spec_string ("human-profile",
"Profile (Human readable)",
"Name of current profile for this card in human readable form",
NULL,
G_PARAM_READABLE));
g_type_class_add_private (klass, sizeof (GvcMixerCardPrivate));
}
static void
gvc_mixer_card_init (GvcMixerCard *card)
{
card->priv = GVC_MIXER_CARD_GET_PRIVATE (card);
}
GvcMixerCard *
gvc_mixer_card_new (pa_context *context,
guint index)
{
GObject *object;
object = g_object_new (GVC_TYPE_MIXER_CARD,
"index", index,
"pa-context", context,
NULL);
return GVC_MIXER_CARD (object);
}
static void
free_profile (GvcMixerCardProfile *p)
{
g_free (p->profile);
g_free (p->human_profile);
g_free (p->status);
g_free (p);
}
static void
gvc_mixer_card_finalize (GObject *object)
{
GvcMixerCard *mixer_card;
g_return_if_fail (object != NULL);
g_return_if_fail (GVC_IS_MIXER_CARD (object));
mixer_card = GVC_MIXER_CARD (object);
g_return_if_fail (mixer_card->priv != NULL);
g_free (mixer_card->priv->name);
mixer_card->priv->name = NULL;
g_free (mixer_card->priv->icon_name);
mixer_card->priv->icon_name = NULL;
g_free (mixer_card->priv->target_profile);
mixer_card->priv->target_profile = NULL;
g_free (mixer_card->priv->profile);
mixer_card->priv->profile = NULL;
g_free (mixer_card->priv->human_profile);
mixer_card->priv->human_profile = NULL;
g_list_foreach (mixer_card->priv->profiles, (GFunc) free_profile, NULL);
g_list_free (mixer_card->priv->profiles);
mixer_card->priv->profiles = NULL;
G_OBJECT_CLASS (gvc_mixer_card_parent_class)->finalize (object);
}

View File

@ -1,83 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008-2009 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_CARD_H
#define __GVC_MIXER_CARD_H
#include <glib-object.h>
G_BEGIN_DECLS
#define GVC_TYPE_MIXER_CARD (gvc_mixer_card_get_type ())
#define GVC_MIXER_CARD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CARD, GvcMixerCard))
#define GVC_MIXER_CARD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CARD, GvcMixerCardClass))
#define GVC_IS_MIXER_CARD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CARD))
#define GVC_IS_MIXER_CARD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CARD))
#define GVC_MIXER_CARD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardClass))
typedef struct GvcMixerCardPrivate GvcMixerCardPrivate;
typedef struct
{
GObject parent;
GvcMixerCardPrivate *priv;
} GvcMixerCard;
typedef struct
{
GObjectClass parent_class;
/* vtable */
} GvcMixerCardClass;
typedef struct
{
char *profile;
char *human_profile;
char *status;
guint priority;
guint n_sinks, n_sources;
} GvcMixerCardProfile;
GType gvc_mixer_card_get_type (void);
guint gvc_mixer_card_get_id (GvcMixerCard *card);
guint gvc_mixer_card_get_index (GvcMixerCard *card);
const char * gvc_mixer_card_get_name (GvcMixerCard *card);
const char * gvc_mixer_card_get_icon_name (GvcMixerCard *card);
GvcMixerCardProfile * gvc_mixer_card_get_profile (GvcMixerCard *card);
const GList * gvc_mixer_card_get_profiles (GvcMixerCard *card);
gboolean gvc_mixer_card_change_profile (GvcMixerCard *card,
const char *profile);
/* private */
gboolean gvc_mixer_card_set_name (GvcMixerCard *card,
const char *name);
gboolean gvc_mixer_card_set_icon_name (GvcMixerCard *card,
const char *name);
gboolean gvc_mixer_card_set_profile (GvcMixerCard *card,
const char *profile);
gboolean gvc_mixer_card_set_profiles (GvcMixerCard *card,
GList *profiles);
G_END_DECLS
#endif /* __GVC_MIXER_CARD_H */

View File

@ -1,35 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_CONTROL_PRIVATE_H
#define __GVC_MIXER_CONTROL_PRIVATE_H
#include <glib-object.h>
#include <pulse/pulseaudio.h>
#include "gvc-mixer-stream.h"
#include "gvc-mixer-card.h"
G_BEGIN_DECLS
pa_context * gvc_mixer_control_get_pa_context (GvcMixerControl *control);
G_END_DECLS
#endif /* __GVC_MIXER_CONTROL_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,108 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_CONTROL_H
#define __GVC_MIXER_CONTROL_H
#include <glib-object.h>
#include "gvc-mixer-stream.h"
#include "gvc-mixer-card.h"
G_BEGIN_DECLS
typedef enum
{
GVC_STATE_CLOSED,
GVC_STATE_READY,
GVC_STATE_CONNECTING,
GVC_STATE_FAILED
} GvcMixerControlState;
#define GVC_TYPE_MIXER_CONTROL (gvc_mixer_control_get_type ())
#define GVC_MIXER_CONTROL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControl))
#define GVC_MIXER_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass))
#define GVC_IS_MIXER_CONTROL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CONTROL))
#define GVC_IS_MIXER_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CONTROL))
#define GVC_MIXER_CONTROL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass))
typedef struct GvcMixerControlPrivate GvcMixerControlPrivate;
typedef struct
{
GObject parent;
GvcMixerControlPrivate *priv;
} GvcMixerControl;
typedef struct
{
GObjectClass parent_class;
void (*state_changed) (GvcMixerControl *control,
GvcMixerControlState new_state);
void (*stream_added) (GvcMixerControl *control,
guint id);
void (*stream_removed) (GvcMixerControl *control,
guint id);
void (*card_added) (GvcMixerControl *control,
guint id);
void (*card_removed) (GvcMixerControl *control,
guint id);
void (*default_sink_changed) (GvcMixerControl *control,
guint id);
void (*default_source_changed) (GvcMixerControl *control,
guint id);
} GvcMixerControlClass;
GType gvc_mixer_control_get_type (void);
GvcMixerControl * gvc_mixer_control_new (const char *name);
gboolean gvc_mixer_control_open (GvcMixerControl *control);
gboolean gvc_mixer_control_close (GvcMixerControl *control);
GSList * gvc_mixer_control_get_cards (GvcMixerControl *control);
GSList * gvc_mixer_control_get_streams (GvcMixerControl *control);
GSList * gvc_mixer_control_get_sinks (GvcMixerControl *control);
GSList * gvc_mixer_control_get_sources (GvcMixerControl *control);
GSList * gvc_mixer_control_get_sink_inputs (GvcMixerControl *control);
GSList * gvc_mixer_control_get_source_outputs (GvcMixerControl *control);
GvcMixerStream * gvc_mixer_control_lookup_stream_id (GvcMixerControl *control,
guint id);
GvcMixerCard * gvc_mixer_control_lookup_card_id (GvcMixerControl *control,
guint id);
GvcMixerStream * gvc_mixer_control_get_default_sink (GvcMixerControl *control);
GvcMixerStream * gvc_mixer_control_get_default_source (GvcMixerControl *control);
GvcMixerStream * gvc_mixer_control_get_event_sink_input (GvcMixerControl *control);
gboolean gvc_mixer_control_set_default_sink (GvcMixerControl *control,
GvcMixerStream *stream);
gboolean gvc_mixer_control_set_default_source (GvcMixerControl *control,
GvcMixerStream *stream);
gdouble gvc_mixer_control_get_vol_max_norm (GvcMixerControl *control);
gdouble gvc_mixer_control_get_vol_max_amplified (GvcMixerControl *control);
GvcMixerControlState gvc_mixer_control_get_state (GvcMixerControl *control);
G_END_DECLS
#endif /* __GVC_MIXER_CONTROL_H */

View File

@ -1,230 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <pulse/pulseaudio.h>
#include <pulse/ext-stream-restore.h>
#include "gvc-mixer-event-role.h"
#include "gvc-mixer-stream-private.h"
#include "gvc-channel-map-private.h"
#define GVC_MIXER_EVENT_ROLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRolePrivate))
struct GvcMixerEventRolePrivate
{
char *device;
};
enum
{
PROP_0,
PROP_DEVICE
};
static void gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass);
static void gvc_mixer_event_role_init (GvcMixerEventRole *mixer_event_role);
static void gvc_mixer_event_role_finalize (GObject *object);
G_DEFINE_TYPE (GvcMixerEventRole, gvc_mixer_event_role, GVC_TYPE_MIXER_STREAM)
static gboolean
update_settings (GvcMixerEventRole *role,
gboolean is_muted,
gpointer *op)
{
pa_operation *o;
const GvcChannelMap *map;
pa_context *context;
pa_ext_stream_restore_info info;
map = gvc_mixer_stream_get_channel_map (GVC_MIXER_STREAM(role));
info.volume = *gvc_channel_map_get_cvolume(map);
info.name = "sink-input-by-media-role:event";
info.channel_map = *gvc_channel_map_get_pa_channel_map(map);
info.device = role->priv->device;
info.mute = is_muted;
context = gvc_mixer_stream_get_pa_context (GVC_MIXER_STREAM (role));
o = pa_ext_stream_restore_write (context,
PA_UPDATE_REPLACE,
&info,
1,
TRUE,
NULL,
NULL);
if (o == NULL) {
g_warning ("pa_ext_stream_restore_write() failed");
return FALSE;
}
if (op != NULL)
*op = o;
return TRUE;
}
static gboolean
gvc_mixer_event_role_push_volume (GvcMixerStream *stream, gpointer *op)
{
return update_settings (GVC_MIXER_EVENT_ROLE (stream),
gvc_mixer_stream_get_is_muted (stream), op);
}
static gboolean
gvc_mixer_event_role_change_is_muted (GvcMixerStream *stream,
gboolean is_muted)
{
return update_settings (GVC_MIXER_EVENT_ROLE (stream),
is_muted, NULL);
}
static gboolean
gvc_mixer_event_role_set_device (GvcMixerEventRole *role,
const char *device)
{
g_return_val_if_fail (GVC_IS_MIXER_EVENT_ROLE (role), FALSE);
g_free (role->priv->device);
role->priv->device = g_strdup (device);
g_object_notify (G_OBJECT (role), "device");
return TRUE;
}
static void
gvc_mixer_event_role_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object);
switch (prop_id) {
case PROP_DEVICE:
gvc_mixer_event_role_set_device (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gvc_mixer_event_role_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object);
switch (prop_id) {
case PROP_DEVICE:
g_value_set_string (value, self->priv->device);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
object_class->finalize = gvc_mixer_event_role_finalize;
object_class->set_property = gvc_mixer_event_role_set_property;
object_class->get_property = gvc_mixer_event_role_get_property;
stream_class->push_volume = gvc_mixer_event_role_push_volume;
stream_class->change_is_muted = gvc_mixer_event_role_change_is_muted;
g_object_class_install_property (object_class,
PROP_DEVICE,
g_param_spec_string ("device",
"Device",
"Device",
NULL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_type_class_add_private (klass, sizeof (GvcMixerEventRolePrivate));
}
static void
gvc_mixer_event_role_init (GvcMixerEventRole *event_role)
{
event_role->priv = GVC_MIXER_EVENT_ROLE_GET_PRIVATE (event_role);
}
static void
gvc_mixer_event_role_finalize (GObject *object)
{
GvcMixerEventRole *mixer_event_role;
g_return_if_fail (object != NULL);
g_return_if_fail (GVC_IS_MIXER_EVENT_ROLE (object));
mixer_event_role = GVC_MIXER_EVENT_ROLE (object);
g_return_if_fail (mixer_event_role->priv != NULL);
g_free (mixer_event_role->priv->device);
G_OBJECT_CLASS (gvc_mixer_event_role_parent_class)->finalize (object);
}
/**
* gvc_mixer_event_role_new: (skip)
* @context:
* @device:
* @channel_map:
*
* Returns:
*/
GvcMixerStream *
gvc_mixer_event_role_new (pa_context *context,
const char *device,
GvcChannelMap *channel_map)
{
GObject *object;
object = g_object_new (GVC_TYPE_MIXER_EVENT_ROLE,
"pa-context", context,
"index", 0,
"device", device,
"channel-map", channel_map,
NULL);
return GVC_MIXER_STREAM (object);
}

View File

@ -1,57 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_EVENT_ROLE_H
#define __GVC_MIXER_EVENT_ROLE_H
#include <glib-object.h>
#include "gvc-mixer-stream.h"
G_BEGIN_DECLS
#define GVC_TYPE_MIXER_EVENT_ROLE (gvc_mixer_event_role_get_type ())
#define GVC_MIXER_EVENT_ROLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRole))
#define GVC_MIXER_EVENT_ROLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass))
#define GVC_IS_MIXER_EVENT_ROLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_EVENT_ROLE))
#define GVC_IS_MIXER_EVENT_ROLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_EVENT_ROLE))
#define GVC_MIXER_EVENT_ROLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass))
typedef struct GvcMixerEventRolePrivate GvcMixerEventRolePrivate;
typedef struct
{
GvcMixerStream parent;
GvcMixerEventRolePrivate *priv;
} GvcMixerEventRole;
typedef struct
{
GvcMixerStreamClass parent_class;
} GvcMixerEventRoleClass;
GType gvc_mixer_event_role_get_type (void);
GvcMixerStream * gvc_mixer_event_role_new (pa_context *context,
const char *device,
GvcChannelMap *channel_map);
G_END_DECLS
#endif /* __GVC_MIXER_EVENT_ROLE_H */

View File

@ -1,165 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <pulse/pulseaudio.h>
#include "gvc-mixer-sink-input.h"
#include "gvc-mixer-stream-private.h"
#include "gvc-channel-map-private.h"
#define GVC_MIXER_SINK_INPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputPrivate))
struct GvcMixerSinkInputPrivate
{
gpointer dummy;
};
static void gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass);
static void gvc_mixer_sink_input_init (GvcMixerSinkInput *mixer_sink_input);
static void gvc_mixer_sink_input_finalize (GObject *object);
G_DEFINE_TYPE (GvcMixerSinkInput, gvc_mixer_sink_input, GVC_TYPE_MIXER_STREAM)
static gboolean
gvc_mixer_sink_input_push_volume (GvcMixerStream *stream, gpointer *op)
{
pa_operation *o;
guint index;
const GvcChannelMap *map;
pa_context *context;
const pa_cvolume *cv;
index = gvc_mixer_stream_get_index (stream);
map = gvc_mixer_stream_get_channel_map (stream);
cv = gvc_channel_map_get_cvolume(map);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_sink_input_volume (context,
index,
cv,
NULL,
NULL);
if (o == NULL) {
g_warning ("pa_context_set_sink_input_volume() failed");
return FALSE;
}
*op = o;
return TRUE;
}
static gboolean
gvc_mixer_sink_input_change_is_muted (GvcMixerStream *stream,
gboolean is_muted)
{
pa_operation *o;
guint index;
pa_context *context;
index = gvc_mixer_stream_get_index (stream);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_sink_input_mute (context,
index,
is_muted,
NULL,
NULL);
if (o == NULL) {
g_warning ("pa_context_set_sink_input_mute_by_index() failed");
return FALSE;
}
pa_operation_unref(o);
return TRUE;
}
static void
gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
object_class->finalize = gvc_mixer_sink_input_finalize;
stream_class->push_volume = gvc_mixer_sink_input_push_volume;
stream_class->change_is_muted = gvc_mixer_sink_input_change_is_muted;
g_type_class_add_private (klass, sizeof (GvcMixerSinkInputPrivate));
}
static void
gvc_mixer_sink_input_init (GvcMixerSinkInput *sink_input)
{
sink_input->priv = GVC_MIXER_SINK_INPUT_GET_PRIVATE (sink_input);
}
static void
gvc_mixer_sink_input_finalize (GObject *object)
{
GvcMixerSinkInput *mixer_sink_input;
g_return_if_fail (object != NULL);
g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object));
mixer_sink_input = GVC_MIXER_SINK_INPUT (object);
g_return_if_fail (mixer_sink_input->priv != NULL);
G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->finalize (object);
}
/**
* gvc_mixer_sink_input_new: (skip)
* @context:
* @index:
* @map:
*
* Returns:
*/
GvcMixerStream *
gvc_mixer_sink_input_new (pa_context *context,
guint index,
GvcChannelMap *channel_map)
{
GObject *object;
object = g_object_new (GVC_TYPE_MIXER_SINK_INPUT,
"pa-context", context,
"index", index,
"channel-map", channel_map,
NULL);
return GVC_MIXER_STREAM (object);
}

View File

@ -1,57 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_SINK_INPUT_H
#define __GVC_MIXER_SINK_INPUT_H
#include <glib-object.h>
#include "gvc-mixer-stream.h"
G_BEGIN_DECLS
#define GVC_TYPE_MIXER_SINK_INPUT (gvc_mixer_sink_input_get_type ())
#define GVC_MIXER_SINK_INPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInput))
#define GVC_MIXER_SINK_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass))
#define GVC_IS_MIXER_SINK_INPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK_INPUT))
#define GVC_IS_MIXER_SINK_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK_INPUT))
#define GVC_MIXER_SINK_INPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass))
typedef struct GvcMixerSinkInputPrivate GvcMixerSinkInputPrivate;
typedef struct
{
GvcMixerStream parent;
GvcMixerSinkInputPrivate *priv;
} GvcMixerSinkInput;
typedef struct
{
GvcMixerStreamClass parent_class;
} GvcMixerSinkInputClass;
GType gvc_mixer_sink_input_get_type (void);
GvcMixerStream * gvc_mixer_sink_input_new (pa_context *context,
guint index,
GvcChannelMap *map);
G_END_DECLS
#endif /* __GVC_MIXER_SINK_INPUT_H */

View File

@ -1,199 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <pulse/pulseaudio.h>
#include "gvc-mixer-sink.h"
#include "gvc-mixer-stream-private.h"
#include "gvc-channel-map-private.h"
#define GVC_MIXER_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkPrivate))
struct GvcMixerSinkPrivate
{
gpointer dummy;
};
static void gvc_mixer_sink_class_init (GvcMixerSinkClass *klass);
static void gvc_mixer_sink_init (GvcMixerSink *mixer_sink);
static void gvc_mixer_sink_finalize (GObject *object);
G_DEFINE_TYPE (GvcMixerSink, gvc_mixer_sink, GVC_TYPE_MIXER_STREAM)
static gboolean
gvc_mixer_sink_push_volume (GvcMixerStream *stream, gpointer *op)
{
pa_operation *o;
guint index;
const GvcChannelMap *map;
pa_context *context;
const pa_cvolume *cv;
index = gvc_mixer_stream_get_index (stream);
map = gvc_mixer_stream_get_channel_map (stream);
/* set the volume */
cv = gvc_channel_map_get_cvolume(map);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_sink_volume_by_index (context,
index,
cv,
NULL,
NULL);
if (o == NULL) {
g_warning ("pa_context_set_sink_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
*op = o;
return TRUE;
}
static gboolean
gvc_mixer_sink_change_is_muted (GvcMixerStream *stream,
gboolean is_muted)
{
pa_operation *o;
guint index;
pa_context *context;
index = gvc_mixer_stream_get_index (stream);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_sink_mute_by_index (context,
index,
is_muted,
NULL,
NULL);
if (o == NULL) {
g_warning ("pa_context_set_sink_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
pa_operation_unref(o);
return TRUE;
}
static gboolean
gvc_mixer_sink_change_port (GvcMixerStream *stream,
const char *port)
{
#if PA_MICRO > 15
pa_operation *o;
guint index;
pa_context *context;
index = gvc_mixer_stream_get_index (stream);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_sink_port_by_index (context,
index,
port,
NULL,
NULL);
if (o == NULL) {
g_warning ("pa_context_set_sink_port_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
pa_operation_unref(o);
return TRUE;
#else
return FALSE;
#endif /* PA_MICRO > 15 */
}
static void
gvc_mixer_sink_class_init (GvcMixerSinkClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
object_class->finalize = gvc_mixer_sink_finalize;
stream_class->push_volume = gvc_mixer_sink_push_volume;
stream_class->change_port = gvc_mixer_sink_change_port;
stream_class->change_is_muted = gvc_mixer_sink_change_is_muted;
g_type_class_add_private (klass, sizeof (GvcMixerSinkPrivate));
}
static void
gvc_mixer_sink_init (GvcMixerSink *sink)
{
sink->priv = GVC_MIXER_SINK_GET_PRIVATE (sink);
}
static void
gvc_mixer_sink_finalize (GObject *object)
{
GvcMixerSink *mixer_sink;
g_return_if_fail (object != NULL);
g_return_if_fail (GVC_IS_MIXER_SINK (object));
mixer_sink = GVC_MIXER_SINK (object);
g_return_if_fail (mixer_sink->priv != NULL);
G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->finalize (object);
}
/**
* gvc_mixer_sink_new: (skip)
* @context:
* @index:
* @map:
*
* Returns:
*/
GvcMixerStream *
gvc_mixer_sink_new (pa_context *context,
guint index,
GvcChannelMap *channel_map)
{
GObject *object;
object = g_object_new (GVC_TYPE_MIXER_SINK,
"pa-context", context,
"index", index,
"channel-map", channel_map,
NULL);
return GVC_MIXER_STREAM (object);
}

View File

@ -1,57 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_SINK_H
#define __GVC_MIXER_SINK_H
#include <glib-object.h>
#include "gvc-mixer-stream.h"
G_BEGIN_DECLS
#define GVC_TYPE_MIXER_SINK (gvc_mixer_sink_get_type ())
#define GVC_MIXER_SINK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK, GvcMixerSink))
#define GVC_MIXER_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass))
#define GVC_IS_MIXER_SINK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK))
#define GVC_IS_MIXER_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK))
#define GVC_MIXER_SINK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass))
typedef struct GvcMixerSinkPrivate GvcMixerSinkPrivate;
typedef struct
{
GvcMixerStream parent;
GvcMixerSinkPrivate *priv;
} GvcMixerSink;
typedef struct
{
GvcMixerStreamClass parent_class;
} GvcMixerSinkClass;
GType gvc_mixer_sink_get_type (void);
GvcMixerStream * gvc_mixer_sink_new (pa_context *context,
guint index,
GvcChannelMap *map);
G_END_DECLS
#endif /* __GVC_MIXER_SINK_H */

View File

@ -1,120 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <pulse/pulseaudio.h>
#include "gvc-mixer-source-output.h"
#define GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputPrivate))
struct GvcMixerSourceOutputPrivate
{
gpointer dummy;
};
static void gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass);
static void gvc_mixer_source_output_init (GvcMixerSourceOutput *mixer_source_output);
static void gvc_mixer_source_output_finalize (GObject *object);
G_DEFINE_TYPE (GvcMixerSourceOutput, gvc_mixer_source_output, GVC_TYPE_MIXER_STREAM)
static gboolean
gvc_mixer_source_output_push_volume (GvcMixerStream *stream, gpointer *op)
{
/* FIXME: */
*op = NULL;
return TRUE;
}
static gboolean
gvc_mixer_source_output_change_is_muted (GvcMixerStream *stream,
gboolean is_muted)
{
/* FIXME: */
return TRUE;
}
static void
gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
object_class->finalize = gvc_mixer_source_output_finalize;
stream_class->push_volume = gvc_mixer_source_output_push_volume;
stream_class->change_is_muted = gvc_mixer_source_output_change_is_muted;
g_type_class_add_private (klass, sizeof (GvcMixerSourceOutputPrivate));
}
static void
gvc_mixer_source_output_init (GvcMixerSourceOutput *source_output)
{
source_output->priv = GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE (source_output);
}
static void
gvc_mixer_source_output_finalize (GObject *object)
{
GvcMixerSourceOutput *mixer_source_output;
g_return_if_fail (object != NULL);
g_return_if_fail (GVC_IS_MIXER_SOURCE_OUTPUT (object));
mixer_source_output = GVC_MIXER_SOURCE_OUTPUT (object);
g_return_if_fail (mixer_source_output->priv != NULL);
G_OBJECT_CLASS (gvc_mixer_source_output_parent_class)->finalize (object);
}
/**
* gvc_mixer_source_output_new: (skip)
* @context:
* @index:
* @map:
*
* Returns:
*/
GvcMixerStream *
gvc_mixer_source_output_new (pa_context *context,
guint index,
GvcChannelMap *channel_map)
{
GObject *object;
object = g_object_new (GVC_TYPE_MIXER_SOURCE_OUTPUT,
"pa-context", context,
"index", index,
"channel-map", channel_map,
NULL);
return GVC_MIXER_STREAM (object);
}

View File

@ -1,57 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_SOURCE_OUTPUT_H
#define __GVC_MIXER_SOURCE_OUTPUT_H
#include <glib-object.h>
#include "gvc-mixer-stream.h"
G_BEGIN_DECLS
#define GVC_TYPE_MIXER_SOURCE_OUTPUT (gvc_mixer_source_output_get_type ())
#define GVC_MIXER_SOURCE_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutput))
#define GVC_MIXER_SOURCE_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass))
#define GVC_IS_MIXER_SOURCE_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT))
#define GVC_IS_MIXER_SOURCE_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE_OUTPUT))
#define GVC_MIXER_SOURCE_OUTPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass))
typedef struct GvcMixerSourceOutputPrivate GvcMixerSourceOutputPrivate;
typedef struct
{
GvcMixerStream parent;
GvcMixerSourceOutputPrivate *priv;
} GvcMixerSourceOutput;
typedef struct
{
GvcMixerStreamClass parent_class;
} GvcMixerSourceOutputClass;
GType gvc_mixer_source_output_get_type (void);
GvcMixerStream * gvc_mixer_source_output_new (pa_context *context,
guint index,
GvcChannelMap *map);
G_END_DECLS
#endif /* __GVC_MIXER_SOURCE_OUTPUT_H */

View File

@ -1,199 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <pulse/pulseaudio.h>
#include "gvc-mixer-source.h"
#include "gvc-mixer-stream-private.h"
#include "gvc-channel-map-private.h"
#define GVC_MIXER_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourcePrivate))
struct GvcMixerSourcePrivate
{
gpointer dummy;
};
static void gvc_mixer_source_class_init (GvcMixerSourceClass *klass);
static void gvc_mixer_source_init (GvcMixerSource *mixer_source);
static void gvc_mixer_source_finalize (GObject *object);
G_DEFINE_TYPE (GvcMixerSource, gvc_mixer_source, GVC_TYPE_MIXER_STREAM)
static gboolean
gvc_mixer_source_push_volume (GvcMixerStream *stream, gpointer *op)
{
pa_operation *o;
guint index;
const GvcChannelMap *map;
pa_context *context;
const pa_cvolume *cv;
index = gvc_mixer_stream_get_index (stream);
map = gvc_mixer_stream_get_channel_map (stream);
/* set the volume */
cv = gvc_channel_map_get_cvolume (map);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_source_volume_by_index (context,
index,
cv,
NULL,
NULL);
if (o == NULL) {
g_warning ("pa_context_set_source_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
*op = o;
return TRUE;
}
static gboolean
gvc_mixer_source_change_is_muted (GvcMixerStream *stream,
gboolean is_muted)
{
pa_operation *o;
guint index;
pa_context *context;
index = gvc_mixer_stream_get_index (stream);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_source_mute_by_index (context,
index,
is_muted,
NULL,
NULL);
if (o == NULL) {
g_warning ("pa_context_set_source_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
pa_operation_unref(o);
return TRUE;
}
static gboolean
gvc_mixer_source_change_port (GvcMixerStream *stream,
const char *port)
{
#if PA_MICRO > 15
pa_operation *o;
guint index;
pa_context *context;
index = gvc_mixer_stream_get_index (stream);
context = gvc_mixer_stream_get_pa_context (stream);
o = pa_context_set_source_port_by_index (context,
index,
port,
NULL,
NULL);
if (o == NULL) {
g_warning ("pa_context_set_source_port_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
return FALSE;
}
pa_operation_unref(o);
return TRUE;
#else
return FALSE;
#endif /* PA_MICRO > 15 */
}
static void
gvc_mixer_source_class_init (GvcMixerSourceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
object_class->finalize = gvc_mixer_source_finalize;
stream_class->push_volume = gvc_mixer_source_push_volume;
stream_class->change_is_muted = gvc_mixer_source_change_is_muted;
stream_class->change_port = gvc_mixer_source_change_port;
g_type_class_add_private (klass, sizeof (GvcMixerSourcePrivate));
}
static void
gvc_mixer_source_init (GvcMixerSource *source)
{
source->priv = GVC_MIXER_SOURCE_GET_PRIVATE (source);
}
static void
gvc_mixer_source_finalize (GObject *object)
{
GvcMixerSource *mixer_source;
g_return_if_fail (object != NULL);
g_return_if_fail (GVC_IS_MIXER_SOURCE (object));
mixer_source = GVC_MIXER_SOURCE (object);
g_return_if_fail (mixer_source->priv != NULL);
G_OBJECT_CLASS (gvc_mixer_source_parent_class)->finalize (object);
}
/**
* gvc_mixer_source_new: (skip)
* @context:
* @index:
* @map:
*
* Returns:
*/
GvcMixerStream *
gvc_mixer_source_new (pa_context *context,
guint index,
GvcChannelMap *channel_map)
{
GObject *object;
object = g_object_new (GVC_TYPE_MIXER_SOURCE,
"pa-context", context,
"index", index,
"channel-map", channel_map,
NULL);
return GVC_MIXER_STREAM (object);
}

View File

@ -1,57 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_SOURCE_H
#define __GVC_MIXER_SOURCE_H
#include <glib-object.h>
#include "gvc-mixer-stream.h"
G_BEGIN_DECLS
#define GVC_TYPE_MIXER_SOURCE (gvc_mixer_source_get_type ())
#define GVC_MIXER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSource))
#define GVC_MIXER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass))
#define GVC_IS_MIXER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE))
#define GVC_IS_MIXER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE))
#define GVC_MIXER_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass))
typedef struct GvcMixerSourcePrivate GvcMixerSourcePrivate;
typedef struct
{
GvcMixerStream parent;
GvcMixerSourcePrivate *priv;
} GvcMixerSource;
typedef struct
{
GvcMixerStreamClass parent_class;
} GvcMixerSourceClass;
GType gvc_mixer_source_get_type (void);
GvcMixerStream * gvc_mixer_source_new (pa_context *context,
guint index,
GvcChannelMap *map);
G_END_DECLS
#endif /* __GVC_MIXER_SOURCE_H */

View File

@ -1,34 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_STREAM_PRIVATE_H
#define __GVC_MIXER_STREAM_PRIVATE_H
#include <glib-object.h>
#include "gvc-channel-map.h"
G_BEGIN_DECLS
pa_context * gvc_mixer_stream_get_pa_context (GvcMixerStream *stream);
G_END_DECLS
#endif /* __GVC_MIXER_STREAM_PRIVATE_H */

View File

@ -1,964 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 William Jon McCann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <pulse/pulseaudio.h>
#include "gvc-mixer-stream.h"
#include "gvc-mixer-stream-private.h"
#include "gvc-channel-map-private.h"
#define GVC_MIXER_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamPrivate))
static guint32 stream_serial = 1;
struct GvcMixerStreamPrivate
{
pa_context *pa_context;
guint id;
guint index;
gint card_index;
GvcChannelMap *channel_map;
char *name;
char *description;
char *application_id;
char *icon_name;
gboolean is_muted;
gboolean can_decibel;
gboolean is_event_stream;
gboolean is_virtual;
pa_volume_t base_volume;
pa_operation *change_volume_op;
char *port;
char *human_port;
GList *ports;
};
enum
{
PROP_0,
PROP_ID,
PROP_PA_CONTEXT,
PROP_CHANNEL_MAP,
PROP_INDEX,
PROP_NAME,
PROP_DESCRIPTION,
PROP_APPLICATION_ID,
PROP_ICON_NAME,
PROP_VOLUME,
PROP_DECIBEL,
PROP_IS_MUTED,
PROP_CAN_DECIBEL,
PROP_IS_EVENT_STREAM,
PROP_IS_VIRTUAL,
PROP_CARD_INDEX,
PROP_PORT,
};
static void gvc_mixer_stream_class_init (GvcMixerStreamClass *klass);
static void gvc_mixer_stream_init (GvcMixerStream *mixer_stream);
static void gvc_mixer_stream_finalize (GObject *object);
G_DEFINE_ABSTRACT_TYPE (GvcMixerStream, gvc_mixer_stream, G_TYPE_OBJECT)
static guint32
get_next_stream_serial (void)
{
guint32 serial;
serial = stream_serial++;
if ((gint32)stream_serial < 0) {
stream_serial = 1;
}
return serial;
}
pa_context *
gvc_mixer_stream_get_pa_context (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
return stream->priv->pa_context;
}
guint
gvc_mixer_stream_get_index (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
return stream->priv->index;
}
guint
gvc_mixer_stream_get_id (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
return stream->priv->id;
}
const GvcChannelMap *
gvc_mixer_stream_get_channel_map (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
return stream->priv->channel_map;
}
/**
* gvc_mixer_stream_get_volume:
* @stream:
*
* Returns: (type guint32) (transfer none):
*/
pa_volume_t
gvc_mixer_stream_get_volume (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
return (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME];
}
gdouble
gvc_mixer_stream_get_decibel (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
return pa_sw_volume_to_dB(
(pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]);
}
/**
* gvc_mixer_stream_set_volume:
* @stream:
* @volume: (type guint32):
*
* Returns:
*/
gboolean
gvc_mixer_stream_set_volume (GvcMixerStream *stream,
pa_volume_t volume)
{
pa_cvolume cv;
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
pa_cvolume_scale(&cv, volume);
if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE);
g_object_notify (G_OBJECT (stream), "volume");
return TRUE;
}
return FALSE;
}
gboolean
gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
gdouble db)
{
pa_cvolume cv;
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
pa_cvolume_scale(&cv, pa_sw_volume_from_dB(db));
if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE);
g_object_notify (G_OBJECT (stream), "volume");
}
return TRUE;
}
gboolean
gvc_mixer_stream_get_is_muted (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
return stream->priv->is_muted;
}
gboolean
gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
return stream->priv->can_decibel;
}
gboolean
gvc_mixer_stream_set_is_muted (GvcMixerStream *stream,
gboolean is_muted)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
if (is_muted != stream->priv->is_muted) {
stream->priv->is_muted = is_muted;
g_object_notify (G_OBJECT (stream), "is-muted");
}
return TRUE;
}
gboolean
gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream,
gboolean can_decibel)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
if (can_decibel != stream->priv->can_decibel) {
stream->priv->can_decibel = can_decibel;
g_object_notify (G_OBJECT (stream), "can-decibel");
}
return TRUE;
}
const char *
gvc_mixer_stream_get_name (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
return stream->priv->name;
}
const char *
gvc_mixer_stream_get_description (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
return stream->priv->description;
}
gboolean
gvc_mixer_stream_set_name (GvcMixerStream *stream,
const char *name)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
g_free (stream->priv->name);
stream->priv->name = g_strdup (name);
g_object_notify (G_OBJECT (stream), "name");
return TRUE;
}
gboolean
gvc_mixer_stream_set_description (GvcMixerStream *stream,
const char *description)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
g_free (stream->priv->description);
stream->priv->description = g_strdup (description);
g_object_notify (G_OBJECT (stream), "description");
return TRUE;
}
gboolean
gvc_mixer_stream_is_event_stream (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
return stream->priv->is_event_stream;
}
gboolean
gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
gboolean is_event_stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
stream->priv->is_event_stream = is_event_stream;
g_object_notify (G_OBJECT (stream), "is-event-stream");
return TRUE;
}
gboolean
gvc_mixer_stream_is_virtual (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
return stream->priv->is_virtual;
}
gboolean
gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream,
gboolean is_virtual)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
stream->priv->is_virtual = is_virtual;
g_object_notify (G_OBJECT (stream), "is-virtual");
return TRUE;
}
const char *
gvc_mixer_stream_get_application_id (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
return stream->priv->application_id;
}
gboolean
gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
const char *application_id)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
g_free (stream->priv->application_id);
stream->priv->application_id = g_strdup (application_id);
g_object_notify (G_OBJECT (stream), "application-id");
return TRUE;
}
static void
on_channel_map_volume_changed (GvcChannelMap *channel_map,
gboolean set,
GvcMixerStream *stream)
{
if (set == TRUE)
gvc_mixer_stream_push_volume (stream);
g_object_notify (G_OBJECT (stream), "volume");
}
static gboolean
gvc_mixer_stream_set_channel_map (GvcMixerStream *stream,
GvcChannelMap *channel_map)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
if (channel_map != NULL) {
g_object_ref (channel_map);
}
if (stream->priv->channel_map != NULL) {
g_signal_handlers_disconnect_by_func (stream->priv->channel_map,
on_channel_map_volume_changed,
stream);
g_object_unref (stream->priv->channel_map);
}
stream->priv->channel_map = channel_map;
if (stream->priv->channel_map != NULL) {
g_signal_connect (stream->priv->channel_map,
"volume-changed",
G_CALLBACK (on_channel_map_volume_changed),
stream);
g_object_notify (G_OBJECT (stream), "channel-map");
}
return TRUE;
}
const char *
gvc_mixer_stream_get_icon_name (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
return stream->priv->icon_name;
}
/**
* gvc_mixer_stream_get_gicon:
* @stream: a #GvcMixerStream
*
* Returns: (transfer full): a new #GIcon
*/
GIcon *
gvc_mixer_stream_get_gicon (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
if (stream->priv->icon_name == NULL)
return NULL;
return g_themed_icon_new_with_default_fallbacks (stream->priv->icon_name);
}
gboolean
gvc_mixer_stream_set_icon_name (GvcMixerStream *stream,
const char *icon_name)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
g_free (stream->priv->icon_name);
stream->priv->icon_name = g_strdup (icon_name);
g_object_notify (G_OBJECT (stream), "icon-name");
return TRUE;
}
/**
* gvc_mixer_stream_get_base_volume:
* @stream:
*
* Returns: (type guint32) (transfer none):
*/
pa_volume_t
gvc_mixer_stream_get_base_volume (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
return stream->priv->base_volume;
}
/**
* gvc_mixer_stream_set_base_volume:
* @stream:
* @base_volume: (type guint32):
*
* Returns:
*/
gboolean
gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
pa_volume_t base_volume)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
stream->priv->base_volume = base_volume;
return TRUE;
}
const GvcMixerStreamPort *
gvc_mixer_stream_get_port (GvcMixerStream *stream)
{
GList *l;
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
g_return_val_if_fail (stream->priv->ports != NULL, NULL);
for (l = stream->priv->ports; l != NULL; l = l->next) {
GvcMixerStreamPort *p = l->data;
if (g_strcmp0 (stream->priv->port, p->port) == 0) {
return p;
}
}
g_assert_not_reached ();
return NULL;
}
gboolean
gvc_mixer_stream_set_port (GvcMixerStream *stream,
const char *port)
{
GList *l;
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
g_return_val_if_fail (stream->priv->ports != NULL, FALSE);
g_free (stream->priv->port);
stream->priv->port = g_strdup (port);
g_free (stream->priv->human_port);
stream->priv->human_port = NULL;
for (l = stream->priv->ports; l != NULL; l = l->next) {
GvcMixerStreamPort *p = l->data;
if (g_str_equal (stream->priv->port, p->port)) {
stream->priv->human_port = g_strdup (p->human_port);
break;
}
}
g_object_notify (G_OBJECT (stream), "port");
return TRUE;
}
gboolean
gvc_mixer_stream_change_port (GvcMixerStream *stream,
const char *port)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
return GVC_MIXER_STREAM_GET_CLASS (stream)->change_port (stream, port);
}
/**
* gvc_mixer_stream_get_ports:
*
* Return value: (transfer none) (element-type GvcMixerStreamPort):
*/
const GList *
gvc_mixer_stream_get_ports (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
return stream->priv->ports;
}
static int
sort_ports (GvcMixerStreamPort *a,
GvcMixerStreamPort *b)
{
if (a->priority == b->priority)
return 0;
if (a->priority > b->priority)
return 1;
return -1;
}
/**
* gvc_mixer_stream_set_ports:
* @ports: (transfer full) (element-type GvcMixerStreamPort):
*/
gboolean
gvc_mixer_stream_set_ports (GvcMixerStream *stream,
GList *ports)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
g_return_val_if_fail (stream->priv->ports == NULL, FALSE);
stream->priv->ports = g_list_sort (ports, (GCompareFunc) sort_ports);
return TRUE;
}
gint
gvc_mixer_stream_get_card_index (GvcMixerStream *stream)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), PA_INVALID_INDEX);
return stream->priv->card_index;
}
gboolean
gvc_mixer_stream_set_card_index (GvcMixerStream *stream,
gint card_index)
{
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
stream->priv->card_index = card_index;
g_object_notify (G_OBJECT (stream), "card-index");
return TRUE;
}
static void
gvc_mixer_stream_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GvcMixerStream *self = GVC_MIXER_STREAM (object);
switch (prop_id) {
case PROP_PA_CONTEXT:
self->priv->pa_context = g_value_get_pointer (value);
break;
case PROP_INDEX:
self->priv->index = g_value_get_ulong (value);
break;
case PROP_ID:
self->priv->id = g_value_get_ulong (value);
break;
case PROP_CHANNEL_MAP:
gvc_mixer_stream_set_channel_map (self, g_value_get_object (value));
break;
case PROP_NAME:
gvc_mixer_stream_set_name (self, g_value_get_string (value));
break;
case PROP_DESCRIPTION:
gvc_mixer_stream_set_description (self, g_value_get_string (value));
break;
case PROP_APPLICATION_ID:
gvc_mixer_stream_set_application_id (self, g_value_get_string (value));
break;
case PROP_ICON_NAME:
gvc_mixer_stream_set_icon_name (self, g_value_get_string (value));
break;
case PROP_VOLUME:
gvc_mixer_stream_set_volume (self, g_value_get_ulong (value));
break;
case PROP_DECIBEL:
gvc_mixer_stream_set_decibel (self, g_value_get_double (value));
break;
case PROP_IS_MUTED:
gvc_mixer_stream_set_is_muted (self, g_value_get_boolean (value));
break;
case PROP_IS_EVENT_STREAM:
gvc_mixer_stream_set_is_event_stream (self, g_value_get_boolean (value));
break;
case PROP_IS_VIRTUAL:
gvc_mixer_stream_set_is_virtual (self, g_value_get_boolean (value));
break;
case PROP_CAN_DECIBEL:
gvc_mixer_stream_set_can_decibel (self, g_value_get_boolean (value));
break;
case PROP_PORT:
gvc_mixer_stream_set_port (self, g_value_get_string (value));
break;
case PROP_CARD_INDEX:
self->priv->card_index = g_value_get_long (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gvc_mixer_stream_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GvcMixerStream *self = GVC_MIXER_STREAM (object);
switch (prop_id) {
case PROP_PA_CONTEXT:
g_value_set_pointer (value, self->priv->pa_context);
break;
case PROP_INDEX:
g_value_set_ulong (value, self->priv->index);
break;
case PROP_ID:
g_value_set_ulong (value, self->priv->id);
break;
case PROP_CHANNEL_MAP:
g_value_set_object (value, self->priv->channel_map);
break;
case PROP_NAME:
g_value_set_string (value, self->priv->name);
break;
case PROP_DESCRIPTION:
g_value_set_string (value, self->priv->description);
break;
case PROP_APPLICATION_ID:
g_value_set_string (value, self->priv->application_id);
break;
case PROP_ICON_NAME:
g_value_set_string (value, self->priv->icon_name);
break;
case PROP_VOLUME:
g_value_set_ulong (value,
pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map)));
break;
case PROP_DECIBEL:
g_value_set_double (value,
pa_sw_volume_to_dB(pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map))));
break;
case PROP_IS_MUTED:
g_value_set_boolean (value, self->priv->is_muted);
break;
case PROP_IS_EVENT_STREAM:
g_value_set_boolean (value, self->priv->is_event_stream);
break;
case PROP_IS_VIRTUAL:
g_value_set_boolean (value, self->priv->is_virtual);
break;
case PROP_CAN_DECIBEL:
g_value_set_boolean (value, self->priv->can_decibel);
break;
case PROP_PORT:
g_value_set_string (value, self->priv->port);
break;
case PROP_CARD_INDEX:
g_value_set_long (value, self->priv->card_index);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GObject *
gvc_mixer_stream_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_params)
{
GObject *object;
GvcMixerStream *self;
object = G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->constructor (type, n_construct_properties, construct_params);
self = GVC_MIXER_STREAM (object);
self->priv->id = get_next_stream_serial ();
return object;
}
static gboolean
gvc_mixer_stream_real_change_port (GvcMixerStream *stream,
const char *port)
{
return FALSE;
}
static gboolean
gvc_mixer_stream_real_push_volume (GvcMixerStream *stream, gpointer *op)
{
return FALSE;
}
static gboolean
gvc_mixer_stream_real_change_is_muted (GvcMixerStream *stream,
gboolean is_muted)
{
return FALSE;
}
gboolean
gvc_mixer_stream_push_volume (GvcMixerStream *stream)
{
pa_operation *op;
gboolean ret;
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
if (stream->priv->is_event_stream != FALSE)
return TRUE;
g_debug ("Pushing new volume to stream '%s' (%s)",
stream->priv->description, stream->priv->name);
ret = GVC_MIXER_STREAM_GET_CLASS (stream)->push_volume (stream, (gpointer *) &op);
if (ret) {
if (stream->priv->change_volume_op != NULL)
pa_operation_unref (stream->priv->change_volume_op);
stream->priv->change_volume_op = op;
}
return ret;
}
gboolean
gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
gboolean is_muted)
{
gboolean ret;
g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
ret = GVC_MIXER_STREAM_GET_CLASS (stream)->change_is_muted (stream, is_muted);
return ret;
}
gboolean
gvc_mixer_stream_is_running (GvcMixerStream *stream)
{
if (stream->priv->change_volume_op == NULL)
return FALSE;
if ((pa_operation_get_state(stream->priv->change_volume_op) == PA_OPERATION_RUNNING))
return TRUE;
pa_operation_unref(stream->priv->change_volume_op);
stream->priv->change_volume_op = NULL;
return FALSE;
}
static void
gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructor = gvc_mixer_stream_constructor;
gobject_class->finalize = gvc_mixer_stream_finalize;
gobject_class->set_property = gvc_mixer_stream_set_property;
gobject_class->get_property = gvc_mixer_stream_get_property;
klass->push_volume = gvc_mixer_stream_real_push_volume;
klass->change_port = gvc_mixer_stream_real_change_port;
klass->change_is_muted = gvc_mixer_stream_real_change_is_muted;
g_object_class_install_property (gobject_class,
PROP_INDEX,
g_param_spec_ulong ("index",
"Index",
"The index for this stream",
0, G_MAXULONG, 0,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_ID,
g_param_spec_ulong ("id",
"id",
"The id for this stream",
0, G_MAXULONG, 0,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_CHANNEL_MAP,
g_param_spec_object ("channel-map",
"channel map",
"The channel map for this stream",
GVC_TYPE_CHANNEL_MAP,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_PA_CONTEXT,
g_param_spec_pointer ("pa-context",
"PulseAudio context",
"The PulseAudio context for this stream",
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_VOLUME,
g_param_spec_ulong ("volume",
"Volume",
"The volume for this stream",
0, G_MAXULONG, 0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_DECIBEL,
g_param_spec_double ("decibel",
"Decibel",
"The decibel level for this stream",
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_NAME,
g_param_spec_string ("name",
"Name",
"Name to display for this stream",
NULL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_DESCRIPTION,
g_param_spec_string ("description",
"Description",
"Description to display for this stream",
NULL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_APPLICATION_ID,
g_param_spec_string ("application-id",
"Application identifier",
"Application identifier for this stream",
NULL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_ICON_NAME,
g_param_spec_string ("icon-name",
"Icon Name",
"Name of icon to display for this stream",
NULL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_IS_MUTED,
g_param_spec_boolean ("is-muted",
"is muted",
"Whether stream is muted",
FALSE,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_CAN_DECIBEL,
g_param_spec_boolean ("can-decibel",
"can decibel",
"Whether stream volume can be converted to decibel units",
FALSE,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_IS_EVENT_STREAM,
g_param_spec_boolean ("is-event-stream",
"is event stream",
"Whether stream's role is to play an event",
FALSE,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_IS_VIRTUAL,
g_param_spec_boolean ("is-virtual",
"is virtual stream",
"Whether the stream is virtual",
FALSE,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
PROP_PORT,
g_param_spec_string ("port",
"Port",
"The name of the current port for this stream",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_CARD_INDEX,
g_param_spec_long ("card-index",
"Card index",
"The index of the card for this stream",
PA_INVALID_INDEX, G_MAXLONG, PA_INVALID_INDEX,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
g_type_class_add_private (klass, sizeof (GvcMixerStreamPrivate));
}
static void
gvc_mixer_stream_init (GvcMixerStream *stream)
{
stream->priv = GVC_MIXER_STREAM_GET_PRIVATE (stream);
}
static void
free_port (GvcMixerStreamPort *p)
{
g_free (p->port);
g_free (p->human_port);
g_free (p);
}
static void
gvc_mixer_stream_finalize (GObject *object)
{
GvcMixerStream *mixer_stream;
g_return_if_fail (object != NULL);
g_return_if_fail (GVC_IS_MIXER_STREAM (object));
mixer_stream = GVC_MIXER_STREAM (object);
g_return_if_fail (mixer_stream->priv != NULL);
g_object_unref (mixer_stream->priv->channel_map);
mixer_stream->priv->channel_map = NULL;
g_free (mixer_stream->priv->name);
mixer_stream->priv->name = NULL;
g_free (mixer_stream->priv->description);
mixer_stream->priv->description = NULL;
g_free (mixer_stream->priv->application_id);
mixer_stream->priv->application_id = NULL;
g_free (mixer_stream->priv->icon_name);
mixer_stream->priv->icon_name = NULL;
g_free (mixer_stream->priv->port);
mixer_stream->priv->port = NULL;
g_free (mixer_stream->priv->human_port);
mixer_stream->priv->human_port = NULL;
g_list_foreach (mixer_stream->priv->ports, (GFunc) free_port, NULL);
g_list_free (mixer_stream->priv->ports);
mixer_stream->priv->ports = NULL;
if (mixer_stream->priv->change_volume_op) {
pa_operation_unref(mixer_stream->priv->change_volume_op);
mixer_stream->priv->change_volume_op = NULL;
}
G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->finalize (object);
}

View File

@ -1,127 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_MIXER_STREAM_H
#define __GVC_MIXER_STREAM_H
#include <glib-object.h>
#include "gvc-pulseaudio-fake.h"
#include "gvc-channel-map.h"
#include <gio/gio.h>
G_BEGIN_DECLS
#define GVC_TYPE_MIXER_STREAM (gvc_mixer_stream_get_type ())
#define GVC_MIXER_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStream))
#define GVC_MIXER_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass))
#define GVC_IS_MIXER_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_STREAM))
#define GVC_IS_MIXER_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_STREAM))
#define GVC_MIXER_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass))
typedef struct GvcMixerStreamPrivate GvcMixerStreamPrivate;
typedef struct
{
GObject parent;
GvcMixerStreamPrivate *priv;
} GvcMixerStream;
typedef struct
{
GObjectClass parent_class;
/* vtable */
gboolean (*push_volume) (GvcMixerStream *stream,
gpointer *operation);
gboolean (*change_is_muted) (GvcMixerStream *stream,
gboolean is_muted);
gboolean (*change_port) (GvcMixerStream *stream,
const char *port);
} GvcMixerStreamClass;
typedef struct
{
char *port;
char *human_port;
guint priority;
} GvcMixerStreamPort;
GType gvc_mixer_stream_get_type (void);
guint gvc_mixer_stream_get_index (GvcMixerStream *stream);
guint gvc_mixer_stream_get_id (GvcMixerStream *stream);
const GvcChannelMap *gvc_mixer_stream_get_channel_map(GvcMixerStream *stream);
const GvcMixerStreamPort *gvc_mixer_stream_get_port (GvcMixerStream *stream);
const GList * gvc_mixer_stream_get_ports (GvcMixerStream *stream);
gboolean gvc_mixer_stream_change_port (GvcMixerStream *stream,
const char *port);
pa_volume_t gvc_mixer_stream_get_volume (GvcMixerStream *stream);
gdouble gvc_mixer_stream_get_decibel (GvcMixerStream *stream);
gboolean gvc_mixer_stream_push_volume (GvcMixerStream *stream);
pa_volume_t gvc_mixer_stream_get_base_volume (GvcMixerStream *stream);
gboolean gvc_mixer_stream_get_is_muted (GvcMixerStream *stream);
gboolean gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream);
gboolean gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
gboolean is_muted);
gboolean gvc_mixer_stream_is_running (GvcMixerStream *stream);
const char * gvc_mixer_stream_get_name (GvcMixerStream *stream);
const char * gvc_mixer_stream_get_icon_name (GvcMixerStream *stream);
GIcon * gvc_mixer_stream_get_gicon (GvcMixerStream *stream);
const char * gvc_mixer_stream_get_description (GvcMixerStream *stream);
const char * gvc_mixer_stream_get_application_id (GvcMixerStream *stream);
gboolean gvc_mixer_stream_is_event_stream (GvcMixerStream *stream);
gboolean gvc_mixer_stream_is_virtual (GvcMixerStream *stream);
gint gvc_mixer_stream_get_card_index (GvcMixerStream *stream);
/* private */
gboolean gvc_mixer_stream_set_volume (GvcMixerStream *stream,
pa_volume_t volume);
gboolean gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
gdouble db);
gboolean gvc_mixer_stream_set_is_muted (GvcMixerStream *stream,
gboolean is_muted);
gboolean gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream,
gboolean can_decibel);
gboolean gvc_mixer_stream_set_name (GvcMixerStream *stream,
const char *name);
gboolean gvc_mixer_stream_set_description (GvcMixerStream *stream,
const char *description);
gboolean gvc_mixer_stream_set_icon_name (GvcMixerStream *stream,
const char *name);
gboolean gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
gboolean is_event_stream);
gboolean gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream,
gboolean is_event_stream);
gboolean gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
const char *application_id);
gboolean gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
pa_volume_t base_volume);
gboolean gvc_mixer_stream_set_port (GvcMixerStream *stream,
const char *port);
gboolean gvc_mixer_stream_set_ports (GvcMixerStream *stream,
GList *ports);
gboolean gvc_mixer_stream_set_card_index (GvcMixerStream *stream,
gint card_index);
G_END_DECLS
#endif /* __GVC_MIXER_STREAM_H */

View File

@ -1,34 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2008 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 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef __GVC_PULSEAUDIO_FAKE_H
#define __GVC_PULSEAUDIO_FAKE_H
#ifdef WITH_INTROSPECTION
#ifndef PA_API_VERSION
#define pa_channel_position_t int
#define pa_volume_t guint32
#define pa_context gpointer
#endif /* PA_API_VERSION */
#endif /* WITH_INTROSPECTION */
#endif /* __GVC_PULSEAUDIO_FAKE_H */

View File

@ -785,16 +785,19 @@ shell_app_usage_start_element_handler (GMarkupParseContext *context,
}
else if (strcmp (element_name, "context") == 0)
{
char *context = NULL;
char *id = NULL;
const char **attribute;
const char **value;
for (attribute = attribute_names, value = attribute_values; *attribute; attribute++, value++)
{
if (strcmp (*attribute, "id") == 0)
context = g_strdup (*value);
{
id = g_strdup (*value);
break;
}
}
if (context < 0)
if (!id)
{
g_set_error (error,
G_MARKUP_ERROR,
@ -803,7 +806,7 @@ shell_app_usage_start_element_handler (GMarkupParseContext *context,
element_name);
return;
}
data->context = context;
data->context = id;
}
else if (strcmp (element_name, "application") == 0)
{
@ -816,7 +819,10 @@ shell_app_usage_start_element_handler (GMarkupParseContext *context,
for (attribute = attribute_names, value = attribute_values; *attribute; attribute++, value++)
{
if (strcmp (*attribute, "id") == 0)
appid = g_strdup (*value);
{
appid = g_strdup (*value);
break;
}
}
if (!appid)

View File

@ -173,48 +173,52 @@ _st_set_text_from_style (ClutterText *text,
ClutterColor color;
StTextDecoration decoration;
PangoAttrList *attribs;
PangoAttrList *attribs = NULL;
const PangoFontDescription *font;
gchar *font_string;
StTextAlign align;
st_theme_node_get_foreground_color (theme_node, &color);
clutter_text_set_color (text, &color);
font = st_theme_node_get_font (theme_node);
font_string = pango_font_description_to_string (font);
clutter_text_set_font_name (text, font_string);
g_free (font_string);
attribs = pango_attr_list_new ();
clutter_text_set_font_description (text, (PangoFontDescription *) font);
decoration = st_theme_node_get_text_decoration (theme_node);
if (decoration & ST_TEXT_DECORATION_UNDERLINE)
if (decoration)
{
PangoAttribute *underline = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
pango_attr_list_insert (attribs, underline);
attribs = pango_attr_list_new ();
if (decoration & ST_TEXT_DECORATION_UNDERLINE)
{
PangoAttribute *underline = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
pango_attr_list_insert (attribs, underline);
}
if (decoration & ST_TEXT_DECORATION_LINE_THROUGH)
{
PangoAttribute *strikethrough = pango_attr_strikethrough_new (TRUE);
pango_attr_list_insert (attribs, strikethrough);
}
/* Pango doesn't have an equivalent attribute for _OVERLINE, and we deliberately
* skip BLINK (for now...)
*/
}
if (decoration & ST_TEXT_DECORATION_LINE_THROUGH)
{
PangoAttribute *strikethrough = pango_attr_strikethrough_new (TRUE);
pango_attr_list_insert (attribs, strikethrough);
}
/* Pango doesn't have an equivalent attribute for _OVERLINE, and we deliberately
* skip BLINK (for now...)
*/
clutter_text_set_attributes (text, attribs);
pango_attr_list_unref (attribs);
if (attribs)
pango_attr_list_unref (attribs);
align = st_theme_node_get_text_align (theme_node);
if(align == ST_TEXT_ALIGN_JUSTIFY) {
clutter_text_set_justify (text, TRUE);
clutter_text_set_line_alignment (text, PANGO_ALIGN_LEFT);
} else {
clutter_text_set_justify (text, FALSE);
clutter_text_set_line_alignment (text, (PangoAlignment) align);
}
if (align == ST_TEXT_ALIGN_JUSTIFY)
{
clutter_text_set_justify (text, TRUE);
clutter_text_set_line_alignment (text, PANGO_ALIGN_LEFT);
}
else
{
clutter_text_set_justify (text, FALSE);
clutter_text_set_line_alignment (text, (PangoAlignment) align);
}
}
/**

View File

@ -270,12 +270,6 @@ scroll_bar_allocate_children (StScrollBar *bar,
handle_box.y2 = content_box.y2;
}
/* snap to pixel */
handle_box.x1 = (int) handle_box.x1;
handle_box.y1 = (int) handle_box.y1;
handle_box.x2 = (int) handle_box.x2;
handle_box.y2 = (int) handle_box.y2;
clutter_actor_allocate (priv->handle,
&handle_box,
flags);

View File

@ -37,61 +37,7 @@ typedef struct _StScrollViewFadeClass StScrollViewFadeClass;
#define DEFAULT_FADE_OFFSET 68.0f
static const gchar *fade_glsl_shader =
"uniform sampler2D tex;\n"
"uniform float height;\n"
"uniform float width;\n"
"uniform float offset_bottom;\n"
"uniform float offset_top;\n"
"uniform float offset_right;\n"
"uniform float offset_left;\n"
/*
* Used to pass the fade area to the shader
*
* [0][0] = x1
* [0][1] = y1
* [1][0] = x2
* [1][1] = y2
*
*/
"uniform mat2 fade_area;\n"
"\n"
"void main ()\n"
"{\n"
" vec4 color = cogl_color_in * texture2D (tex, vec2 (cogl_tex_coord_in[0].xy));\n"
" float y = height * cogl_tex_coord_in[0].y;\n"
" float x = width * cogl_tex_coord_in[0].x;\n"
" float ratio = 1.0;\n"
" float fade_bottom_start = fade_area[1][1] - offset_bottom;\n"
" float fade_right_start = fade_area[1][0] - offset_right;\n"
" float ratio_top = y / offset_top;\n"
" float ratio_bottom = (fade_area[1][1] - y)/(fade_area[1][1] - fade_bottom_start);\n"
" float ratio_left = x / offset_left;\n"
" float ratio_right = (fade_area[1][0] - x)/(fade_area[1][0] - fade_right_start);\n"
" bool in_scroll_area = fade_area[0][0] <= x && fade_area[1][0] >= x;\n"
" bool fade_top = y < offset_top && in_scroll_area && (y >= fade_area[0][1]);\n"
" bool fade_bottom = y > fade_bottom_start && in_scroll_area && (y <= fade_area[1][1]);\n"
" bool fade_left = x < offset_left && in_scroll_area && (x >= fade_area[0][0]);\n"
" bool fade_right = x > fade_right_start && in_scroll_area && (x <= fade_area[1][0]);\n"
"\n"
" if (fade_top) {\n"
" ratio *= ratio_top;\n"
" }\n"
"\n"
" if (fade_bottom) {\n"
" ratio *= ratio_bottom;\n"
" }\n"
"\n"
" if (fade_left) {\n"
" ratio *= ratio_left;\n"
" }\n"
"\n"
" if (fade_right) {\n"
" ratio *= ratio_right;\n"
" }\n"
"\n"
" cogl_color_out = color * ratio;\n"
"}";
#include "st-scroll-view-fade-generated.c"
struct _StScrollViewFade
{
@ -107,10 +53,10 @@ struct _StScrollViewFade
gint height_uniform;
gint width_uniform;
gint fade_area_uniform;
gint offset_top_uniform;
gint offset_bottom_uniform;
gint offset_left_uniform;
gint offset_right_uniform;
gint vfade_offset_uniform;
gint hfade_offset_uniform;
gint vvalue_uniform;
gint hvalue_uniform;
StAdjustment *vadjustment;
StAdjustment *hadjustment;
@ -175,14 +121,14 @@ st_scroll_view_fade_pre_paint (ClutterEffect *effect)
cogl_program_get_uniform_location (self->program, "width");
self->fade_area_uniform =
cogl_program_get_uniform_location (self->program, "fade_area");
self->offset_top_uniform =
cogl_program_get_uniform_location (self->program, "offset_top");
self->offset_bottom_uniform =
cogl_program_get_uniform_location (self->program, "offset_bottom");
self->offset_left_uniform =
cogl_program_get_uniform_location (self->program, "offset_left");
self->offset_right_uniform =
cogl_program_get_uniform_location (self->program, "offset_right");
self->vfade_offset_uniform =
cogl_program_get_uniform_location (self->program, "vfade_offset");
self->hfade_offset_uniform =
cogl_program_get_uniform_location (self->program, "hfade_offset");
self->vvalue_uniform =
cogl_program_get_uniform_location (self->program, "vvalue");
self->hvalue_uniform =
cogl_program_get_uniform_location (self->program, "hvalue");
}
parent_class = CLUTTER_EFFECT_CLASS (st_scroll_view_fade_parent_class);
@ -261,38 +207,24 @@ st_scroll_view_fade_paint_target (ClutterOffscreenEffect *effect)
if (h_scroll_visible)
fade_area[1][1] -= clutter_actor_get_height (hscroll);
st_adjustment_get_values (self->vadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
if (self->vvalue_uniform > -1)
{
st_adjustment_get_values (self->vadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
value = (value - lower) / (upper - page_size - lower);
cogl_program_set_uniform_1f (self->program, self->vvalue_uniform, value);
}
if (self->offset_top_uniform > -1) {
if (value > lower + 0.1)
cogl_program_set_uniform_1f (self->program, self->offset_top_uniform, self->vfade_offset);
else
cogl_program_set_uniform_1f (self->program, self->offset_top_uniform, 0.0f);
}
if (self->offset_bottom_uniform > -1) {
if (value < upper - page_size - 0.1)
cogl_program_set_uniform_1f (self->program, self->offset_bottom_uniform, self->vfade_offset);
else
cogl_program_set_uniform_1f (self->program, self->offset_bottom_uniform, 0.0f);
}
st_adjustment_get_values (self->hadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
if (self->offset_left_uniform > -1) {
if (value > lower + 0.1)
cogl_program_set_uniform_1f (self->program, self->offset_left_uniform, self->hfade_offset);
else
cogl_program_set_uniform_1f (self->program, self->offset_left_uniform, 0.0f);
}
if (self->offset_right_uniform > -1) {
if (value < upper - page_size - 0.1)
cogl_program_set_uniform_1f (self->program, self->offset_right_uniform, self->hfade_offset);
else
cogl_program_set_uniform_1f (self->program, self->offset_right_uniform, 0.0f);
}
if (self->hvalue_uniform > -1)
{
st_adjustment_get_values (self->hadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
value = (value - lower) / (upper - page_size - lower);
cogl_program_set_uniform_1f (self->program, self->hvalue_uniform, value);
}
if (self->vfade_offset_uniform > -1)
cogl_program_set_uniform_1f (self->program, self->vfade_offset_uniform, self->vfade_offset);
if (self->hfade_offset_uniform > -1)
cogl_program_set_uniform_1f (self->program, self->hfade_offset_uniform, self->hfade_offset);
if (self->tex_uniform > -1)
cogl_program_set_uniform_1i (self->program, self->tex_uniform, 0);
if (self->height_uniform > -1)
@ -549,7 +481,7 @@ st_scroll_view_fade_init (StScrollViewFade *self)
if (clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
cogl_shader_source (shader, fade_glsl_shader);
cogl_shader_source (shader, (const char *) st_scroll_view_fade_glsl);
cogl_shader_compile (shader);
if (!cogl_shader_is_compiled (shader))
{
@ -571,8 +503,10 @@ st_scroll_view_fade_init (StScrollViewFade *self)
self->height_uniform = -1;
self->width_uniform = -1;
self->fade_area_uniform = -1;
self->offset_top_uniform = -1;
self->offset_bottom_uniform = -1;
self->vfade_offset_uniform = -1;
self->hfade_offset_uniform = -1;
self->vvalue_uniform = -1;
self->hvalue_uniform = -1;
self->vfade_offset = DEFAULT_FADE_OFFSET;
self->hfade_offset = DEFAULT_FADE_OFFSET;

View File

@ -0,0 +1,86 @@
/*
* st-scroll-view-fade.glsl: Edge fade effect for StScrollView
*
* Copyright 2010 Intel Corporation.
* Copyright 2011 Adel Gadllah
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#version 120
uniform sampler2D tex;
uniform float height;
uniform float width;
uniform float vfade_offset;
uniform float hfade_offset;
uniform float vvalue;
uniform float hvalue;
/*
* Used to pass the fade area to the shader
*
* [0][0] = x1
* [0][1] = y1
* [1][0] = x2
* [1][1] = y2
*
*/
uniform mat2 fade_area;
/*
* Scale from [0.0, 1.0] to [1.0, 1.0]. Do this by
* changing it to scaling [1.0, 0.0] to [0.0, 0.0]
* and then transforming the end result.
*/
#define FADE(gradient, factor) (1 - (1 - gradient) * factor)
void main ()
{
cogl_color_out = cogl_color_in * texture2D (tex, vec2 (cogl_tex_coord_in[0].xy));
float y = height * cogl_tex_coord_in[0].y;
float x = width * cogl_tex_coord_in[0].x;
if (x < fade_area[0][0] || x > fade_area[1][0] ||
y < fade_area[0][1] || y > fade_area[1][1])
return;
float ratio = 1.0;
float fade_bottom_start = fade_area[1][1] - vfade_offset;
float fade_right_start = fade_area[1][0] - hfade_offset;
bool fade_top = y < vfade_offset && vvalue > 0;
bool fade_bottom = y > fade_bottom_start && vvalue < 1;
bool fade_left = x < hfade_offset && hvalue > 0;
bool fade_right = x > fade_right_start && hvalue < 1;
float vfade_scale = height / vfade_offset;
if (fade_top) {
ratio *= FADE((y / vfade_offset), min(vvalue * vfade_scale, 1.0));
}
if (fade_bottom) {
ratio *= FADE((fade_area[1][1] - y)/(fade_area[1][1] - fade_bottom_start), min((1.0 - vvalue) * vfade_scale, 1.0));
}
float hfade_scale = width / hfade_offset;
if (fade_left) {
ratio *= FADE(x / hfade_offset, min(hvalue * hfade_scale, 1.0));
}
if (fade_right) {
ratio *= FADE((fade_area[1][0] - x)/(fade_area[1][0] - fade_right_start), min((1.0 - hvalue) * hfade_scale, 1.0));
}
cogl_color_out *= ratio;
}

View File

@ -143,13 +143,6 @@ on_stage_destroy (ClutterStage *stage)
g_object_unref (context);
}
static gboolean
emit_changed (StThemeContext *context)
{
g_signal_emit (context, signals[CHANGED], 0);
return FALSE;
}
static void
st_theme_context_changed (StThemeContext *context)
{
@ -157,12 +150,19 @@ st_theme_context_changed (StThemeContext *context)
context->root_node = NULL;
g_hash_table_remove_all (context->nodes);
emit_changed (context);
g_signal_emit (context, signals[CHANGED], 0);
if (old_root)
g_object_unref (old_root);
}
static gboolean
changed_idle (gpointer userdata)
{
st_theme_context_changed (userdata);
return FALSE;
}
static void
on_icon_theme_changed (StTextureCache *cache,
StThemeContext *context)
@ -170,9 +170,9 @@ on_icon_theme_changed (StTextureCache *cache,
/* Note that an icon theme change isn't really a change of the StThemeContext;
* the style information has changed. But since the style factors into the
* icon_name => icon lookup, faking a theme context change is a good way
* to force users such as StIcon to look up icons again. Don't bother recreating
* the root node, though. */
g_idle_add ((GSourceFunc) emit_changed, context);
* to force users such as StIcon to look up icons again.
*/
g_idle_add ((GSourceFunc) changed_idle, context);
}
/**

View File

@ -1401,6 +1401,15 @@ st_theme_node_render_resources (StThemeNode *node,
else
node->border_slices_material = COGL_INVALID_HANDLE;
node->corner_material[ST_CORNER_TOPLEFT] =
st_theme_node_lookup_corner (node, ST_CORNER_TOPLEFT);
node->corner_material[ST_CORNER_TOPRIGHT] =
st_theme_node_lookup_corner (node, ST_CORNER_TOPRIGHT);
node->corner_material[ST_CORNER_BOTTOMRIGHT] =
st_theme_node_lookup_corner (node, ST_CORNER_BOTTOMRIGHT);
node->corner_material[ST_CORNER_BOTTOMLEFT] =
st_theme_node_lookup_corner (node, ST_CORNER_BOTTOMLEFT);
/* Use cairo to prerender the node if there is a gradient, or
* background image with borders and/or rounded corners,
* or large corners, since we can't do those things
@ -1478,15 +1487,6 @@ st_theme_node_render_resources (StThemeNode *node,
node->background_texture);
}
}
node->corner_material[ST_CORNER_TOPLEFT] =
st_theme_node_lookup_corner (node, ST_CORNER_TOPLEFT);
node->corner_material[ST_CORNER_TOPRIGHT] =
st_theme_node_lookup_corner (node, ST_CORNER_TOPRIGHT);
node->corner_material[ST_CORNER_BOTTOMRIGHT] =
st_theme_node_lookup_corner (node, ST_CORNER_BOTTOMRIGHT);
node->corner_material[ST_CORNER_BOTTOMLEFT] =
st_theme_node_lookup_corner (node, ST_CORNER_BOTTOMLEFT);
}
static void

View File

@ -0,0 +1,30 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const CenterLayout = imports.ui.centerLayout;
const UI = imports.testcommon.ui;
function test() {
let stage = new Clutter.Stage({ user_resizable: true });
UI.init(stage);
////////////////////////////////////////////////////////////////////////////////
let container = new St.Widget({ style: 'border: 2px solid black;',
layout_manager: new CenterLayout.CenterLayout() });
container.add_constraint(new Clutter.BindConstraint({ coordinate: Clutter.BindCoordinate.SIZE, source: stage }));
stage.add_actor(container);
let left = new Clutter.Actor({ background_color: Clutter.Color.get_static(Clutter.StaticColor.RED), width: 300 });
let center = new Clutter.Actor({ background_color: Clutter.Color.get_static(Clutter.StaticColor.BLUE), width: 100 });
let right = new Clutter.Actor({ background_color: Clutter.Color.get_static(Clutter.StaticColor.YELLOW), width: 200 });
container.add_actor(left);
container.add_actor(center);
container.add_actor(right);
UI.main(stage);
}
test();

View File

@ -24,7 +24,10 @@ const UI = imports.testcommon.ui;
const BOX_HEIGHT = 20;
const BOX_WIDTHS = [
10, 40, 100, 20, 60, 30, 70, 10, 20, 200, 50, 70, 90, 20, 40
10, 40, 100, 20, 60, 30, 70, 10, 20, 200, 50, 70, 90, 20, 40,
10, 40, 100, 20, 60, 30, 70, 10, 20, 200, 50, 70, 90, 20, 40,
10, 40, 100, 20, 60, 30, 70, 10, 20, 200, 50, 70, 90, 20, 40,
10, 40, 100, 20, 60, 30, 70, 10, 20, 200, 50, 70, 90, 20, 40,
];
const SPACING = 10;
@ -383,6 +386,7 @@ function test() {
}
vfade.connect('clicked', function() { toggleFade(vfade); });
toggleFade(vfade);
UI.main(stage);
}