Compare commits

...

370 Commits

Author SHA1 Message Date
471006ba67 Bump version to 2.27.3 2009-09-15 18:03:36 -04:00
98bd590a5d [runDialog] Add 'debugexit' command
There are few uses for being able to exit the shell directly; my
current one is that the gtype debug infrastructure is implemented
as an atexit() handler.
2009-09-15 17:47:57 -04:00
9d88a13d3c Updated Galician Translation 2009-09-15 23:06:46 +02:00
159690b2d3 Enable Alt-f2 in overview
This isn't a long-term solution; what we really want is for Alt-F2 to
just be an application search with a hack to detect shell commands,
but in the short term this allows us to run the magic 'lg' command
from the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=595116
2009-09-15 16:20:19 -04:00
8a2bfd0e55 Change keyboard handling API to handle nested modal calls
Rename beginModal/endModal to pushModal/popModal.  All of the current callers
just want to ensure that we're in a modal state; they don't actually need to
fail if we already are.

These functions also now take the Clutter keyboard focus, while recording
the previous focus.

https://bugzilla.gnome.org/show_bug.cgi?id=595116
2009-09-15 16:15:16 -04:00
2ddc7cf00f Only enable internal commands if developer_tools is true
'r' is a bit too accidentally-hittable for outside of developer usage.
However it will still be enabled when developer_tools is true.

https://bugzilla.gnome.org/show_bug.cgi?id=595116
2009-09-15 16:14:36 -04:00
04f10ceb4e Add a developer_tools boolean defaulting to true
This will be use to enable various internal tools which should only
be exposed to developers/testers.

https://bugzilla.gnome.org/show_bug.cgi?id=595116
2009-09-15 16:12:11 -04:00
ceefc5eea4 Convert remaining uses of "let me = this;" to Lang.bind
https://bugzilla.gnome.org/show_bug.cgi?id=595293
2009-09-15 13:11:23 -04:00
9feda69888 When in window filtering mode, reset filter before showing window
When we had a filtered set of windows, and want to exit the overview
into a particular window, what we do is re-show all the old windows
first, but don't reset the scaling on them.  This will involve
some overlapping, but that's not a big deal because we'll immediately
get overlap anyways in the normal case zooming the windows back.

https://bugzilla.gnome.org/show_bug.cgi?id=594699
2009-09-14 15:41:19 -04:00
33f9895d71 Don't proxy methods through overview; add a getWorkspacesForWindow()
Duplicating the methods was unnecessary.  Also, we want a getWorkspacesForWindow()
method as preparation for multi-monitor work.

https://bugzilla.gnome.org/show_bug.cgi?id=594699
2009-09-14 15:41:12 -04:00
2812c21322 Allow popup menu to be persistent, and support direct window selection
When the user click+hold+release over the icon, the effect we want
is for the menu to stick around.

Also, allow the user to mouse over the actual windows and select
them directly.  If the user mouses over a window, reflect that in
the menu.

https://bugzilla.gnome.org/show_bug.cgi?id=594699
2009-09-14 15:37:29 -04:00
7ac9fb2dd0 Make popdown,popup methods idempotent; remove 'popdown' for 'cancelled'
Callers will generally expect _popup and _popdown to be a no-op if
the menu is already in that state; make it so.

Also change the 'popdown' signal to be 'cancelled'; this is
clearer and allows us to avoid having activate also call popdown.

https://bugzilla.gnome.org/show_bug.cgi?id=594699
2009-09-14 15:37:26 -04:00
05c99241d6 [Overview] Make content area eat mouse events during animations
There are ton of different kinds of mouse even handlers in the overview;
WindowClone has several mouse-enter/leave handlers, we still have a variety
of classes not ported to ButtonBox and so incorrectly handling double-click,
etc.

Since we at present don't have anything in the overview area for which
it makes sense to interact with during the animation, create a transparent
event-eating box which we raise to the top during the animation.

https://bugzilla.gnome.org/show_bug.cgi?id=594074
2009-09-14 15:31:49 -04:00
9fb8dad80c Added British English translation 2009-09-13 16:24:19 +01:00
004ad86e9d Updated Spanish translation 2009-09-12 14:41:15 +02:00
02c65fab8d Don't show section headers for sections with no results and don't show page
controls if there is only one page of results

This makes the search results display more streamlined.

Make sure that we move the selection to a different section if we are going
from displaying a single section to displaying all and the section that
used to be displayed alone doesn't have any results.
2009-09-11 19:30:11 -04:00
dfe16f4af6 Revert "[AppWell] Allow popup menu to be persistent, and support direct window selection"
This reverts commit 6e31e59b57.
2009-09-11 18:58:30 -04:00
e52cb3c213 [ShellAppMonitor] Handle Iceweasel tripping Firefox window title detection
We have compatibility code which detects from the window title what
an application is.  However, the code didn't handle the case where
we discovered by title, but didn't have the expected .desktop file
installed.
2009-09-11 18:57:44 -04:00
6e31e59b57 [AppWell] Allow popup menu to be persistent, and support direct window selection
When the user click+hold+release over the icon, the effect we want
is for the menu to stick around.

Also, allow the user to mouse over the actual windows and select
them directly.  If the user mouses over a window, reflect that in
the menu.
2009-09-11 18:57:44 -04:00
458778bcfd Add a separate section of search results that shows system preferences
System preferences should not be mixed in with applications in search results.
2009-09-11 17:48:02 -04:00
d8cabbee0b More global-ization 2009-09-11 17:23:42 -04:00
3029a4086b Restructure the search results code to be able to support any number of sections
We will be adding more search results sections, so we should store the intended
order of the search results sections and their properties in an array of data
structures.

This information allows us to have generic code for creating the search results
sections, moving the selection between them and transitioning between showing
all sections and a single section.
2009-09-11 16:42:54 -04:00
5598de6543 Updated French translation 2009-09-11 21:41:27 +02:00
913aeae166 Actually update well menu filtering for review messages
My updates got lost due to accidentally being on a rebase branch.
2009-09-09 17:28:52 -04:00
dddad9e1b5 [AppDisplay] In search/browse, show existing window instead of always launching
This brings search in line with the AppWell behavior which is definitely
right.  For browse we probably want more options.
2009-09-09 16:49:26 -04:00
4bfa68d209 [AppWell] Fix previous commit
Somehow missed changing a call when updating for review comments.
2009-09-09 16:49:07 -04:00
42e3a93c20 More gracefully handle a situation where starting shell failed
If start_shell() threw an exception before, we'd overwrite it with
an exception in the finally() clause.  Handle this and just print a message
and let the exception propagate.
2009-09-09 15:49:31 -04:00
05812ef7f9 [AppWell] Enable lightboxing immediately on popup
Rather than starting lightboxing only when the mouse enters the
menu, start it when an application filter is set.

Also delete a stale function in WindowClone from previous work.

http://bugzilla.gnome.org/show_bug.cgi?id=594555
2009-09-09 11:40:09 -04:00
a0df412deb Extend (+) button sensitivity to corner of screen, for Fittsability
https://bugzilla.gnome.org/show_bug.cgi?id=591984
2009-09-09 11:31:50 -04:00
678a88dbdb Remove some "let global ..."s that snuck back in as part of old patches 2009-09-09 09:42:00 -04:00
5e944c9a3b Move the add workspace button out of the Workspaces object, into Overview
http://bugzilla.gnome.org/show_bug.cgi?id=594049
2009-09-09 09:36:59 -04:00
b28b60b47b Updated Polish translation 2009-09-09 03:06:16 +02:00
16caa74386 Updated Polish translation 2009-09-09 02:57:37 +02:00
470c65d046 [AppWell] Make control-click create a new window
Implement this for now by just re-launching the application, which
visually will normally create a new window.

http://bugzilla.gnome.org/show_bug.cgi?id=594565
2009-09-08 18:48:51 -04:00
ef6ea078dd [AppWell] Position menu components on integral coordinates
This avoids fuzz.

http://bugzilla.gnome.org/show_bug.cgi?id=594553
2009-09-08 18:48:17 -04:00
37ee16b34d Use clutter_event_get_* instead of ShellGlobal
Before Clutter gained accessors for event information, we had
shell_global_ functions.  Now that Clutter has them, use them and
delete the ShellGlobal code.

http://bugzilla.gnome.org/show_bug.cgi?id=594561
2009-09-08 17:58:13 -04:00
5880b3b0ed [ShellButtonBox] Add event to activate signal
This allows access to things such as keyboard modifier state and
event time cleanly.

http://bugzilla.gnome.org/show_bug.cgi?id=594565
2009-09-08 17:58:13 -04:00
80a5f78eb2 [AppWell] Unify drag and drop behavior between Running versus Inactive
This fixes a regression where drag and drop didn't work for inactive
items correctly.

http://bugzilla.gnome.org/show_bug.cgi?id=594542
2009-09-08 17:58:13 -04:00
4b727ef40d Scroll wheel should zoom windows in the overview
Allow using the scroll wheel to zoom in on windows in the overview.

Original patch from JP St. Pierre.
http://bugzilla.gnome.org/show_bug.cgi?id=591849
2009-09-08 17:37:24 -04:00
d0d79c5b3e Make "global" global.
Rather than doing "let global = Shell.Global.get()" everywhere we
need it, just create a global variable called "global".

http://bugzilla.gnome.org/show_bug.cgi?id=594546
2009-09-08 16:21:15 -04:00
0882da0a71 Add error handling to the runDialog
Show the errors to the user instead of silently logging them to the terminal,
also rework positioning to get rid of magic numbers.

Signed-off-by: Adel Gadllah <adel.gadllah@gmail.com>

http://bugzilla.gnome.org/show_bug.cgi?id=593840
2009-09-08 14:35:23 -04:00
25410a730e Bug 591763 - Add application window menu
When we have multiple windows for an application, implement the following
behavior:

* On click + immediate release, go to the most recently used
* On click, hold for 0.6s, pop up a menu with windows, filtering
  the window list to just those windows.
  Mouse over on the window list highlights the moused-over window.

Implement this by splitting well item into InactiveWellItem
and RunningWellItem, sharing a base class BaseWellItem.
2009-09-08 14:31:44 -04:00
22c445cffc Add ShellMenu
An object with methods and signals useful for implementing popup menus.
2009-09-08 14:31:43 -04:00
42bf91fdc4 Distribute app-well-glow.png
Add app-well-glow.png to data/Makefile.am
2009-09-07 20:43:57 +02:00
7f88e02a26 Convert on_tree_changed to a gboolean returning false.
This fixes commit 0a29cf6195 and
g_timer_add_full running in an endless loop.

http://bugzilla.gnome.org/show_bug.cgi?id=592608
2009-09-07 11:13:38 -04:00
d540af847a Updated Italian translation 2009-09-06 18:32:44 +02:00
2f78907aeb Bump version to 2.27.2 2009-09-04 20:14:57 -04:00
d471541495 Bump gobject-introspectio nrequirement to 0.6.5
gobject-introspection 0.6.5 is needed for Gio.VolumeMonitor usage.
2009-09-04 20:13:04 -04:00
fa5fb6b8a8 Bug 594184 - Fix up glow positioning logic
We were allowing the glow allocation to go too far to the right;
clean up the logic.
2009-09-04 20:03:56 -04:00
0a29cf6195 Compress notifications of menu changes with a timeout.
GMenu currently gives us a separate notification on the entire
menu tree for each node in the tree that might potentially have
changed. (See http://bugzilla.gnome.org/show_bug.cgi?id=172046.)
Compress these with a timeout to avoid doing a lot of extra work.

http://bugzilla.gnome.org/show_bug.cgi?id=592608
2009-09-04 19:24:47 -04:00
b7b4c54ab5 Make checking if an item is under the pointer asynchonous again
Checking if an item is under the pointer by calling stage.get_actor_at_pos()
synchronously will trigger a too-early allocation of the stage. Use an idle
at Meta.PRIORITY_BEFORE_REDRAW. (Before 553503d it was using a 5 msec timeout,
553503d made it synchronous.)

http://bugzilla.gnome.org/show_bug.cgi?id=592608
2009-09-04 19:12:07 -04:00
52abf266c0 Redo AppWell glow to be based on a based on a .png instead of cairo
Instead of drawing an ellipse, use a hand-drawn .png file which
looks a bit less regular and blends better.
2009-09-04 17:42:10 -04:00
11872cfb79 Add README and DOAP file
README: Add a short README with basic information.

gnome-shell.doap: Add project information in DOAP format expected
  for GNOME projects.

http://bugzilla.gnome.org/show_bug.cgi?id=591564
2009-09-04 15:23:13 -04:00
21309aa28f Updated Danish translation 2009-09-04 01:26:01 +02:00
38d21c8edf Remove some vestigial code 2009-09-03 09:50:39 -04:00
090908439b Add volumes support to places
Display the mounted volumes in the places section of the overlay.

Signed-off-by: Adel Gadllah <adel.gadllah@gmail.com>
Signed-off-by: Colin Walters <walters@verbum.org>
2009-09-02 15:04:24 -04:00
0a17a28608 Add shell_button_box_fake_release
The application menu code wants to do a popup after a given timeout
while holding.  We can implement that by adding a function to
manually break the grab held by the button box.

Freeze+thaw around the hover and pressed property notification on leave
since handlers may want to depend on the pressed state on a hover
transition.
2009-09-02 15:01:33 -04:00
926643b025 Add shell_texture_cache_pixbufs_equal
Mutter is currently creating separate pixbufs for window icons;
use this to analyze them.
2009-09-02 14:54:49 -04:00
1a834f7d8b Add API to programmatically initiate a drag
For some use cases we have other behavior on mouse press and want
to manually control when a drag starts.  Split out the drag initiation
code into startDrag.
2009-09-02 14:34:57 -04:00
3e54087e42 Add Tweener.slowDownFactor, initialize from $GNOME_SHELL_SLOWDOWN_FACTOR
This allows for easier debugging of glitchy animations
2009-09-02 09:15:37 -04:00
304b377dae Added Punjabi (Gurmukhi)Translation 2009-09-02 05:28:51 +05:30
ac4bcee050 Merge headers when a single section of search results is displayed
There is no need to show two headers when we are only displaying a single
section of search results, so we merge the section header with the main
header in that case.

Show a back button on the left of the main header to get back to the results
for all sections.

Remove this._showTooltip flag from SearchSectionHeader because we no longer
show this type of header when we want to suppress the tooltip.

Add this._appSearchResultsOnlyShown and this._docSearchResultsOnlyShown
flags to track when a single section is shown more cleanly.
2009-09-01 19:06:20 -04:00
553503dace Remove the timeout for checking if an item is drawn under the pointer
We no longer need the timeout for checking if an item is drawn under
the pointer because we display search results in the main pane and there is
no lowering/raising of other overview actors going on as the results are
being displayed.
2009-09-01 16:29:14 -04:00
90381ceea2 Improve key navigation for search results
Select an item by default when the search results are displayed.

Enable moving from one section of search results to another with key navigation.

Reset the selection when the search is updated or a new page is displayed
or the transition between viewing multiple sections and viewing just one is made.
2009-09-01 16:24:47 -04:00
687814b6c6 Update build-setup.sh for gconf, gio python usage
Add pygobject and gnome-python-gconf dependencies to
gnome-shell-build-setup.sh package lists for Fedora and Ubuntu/Debian.

http://bugzilla.gnome.org/show_bug.cgi?id=593458
2009-09-01 09:02:46 -04:00
6153094057 Updated Swedish translation 2009-09-01 00:31:48 +02:00
0245a0cd0e Do not display windows with skip-taskbar hint in overview.
This fixes the bug where the empathy buddy list is always visible on the
last workspace it was shown on, even if it was closed.
2009-08-31 21:35:23 +02:00
bcc3dc0711 Consolidate window tracking filters between app monitor and overview.
The windows we considered for both the app monitor and the overview
workspaces were the same, but the code was duplicated once in C, once
in Javascript.
2009-08-31 21:35:23 +02:00
3d499219da Use AM_PATH_PYTHON to find Python >= 2.5
On OpenSolaris /usr/bin/python is 2.4; use AM_PATH_PYTHON to find
a newer Python. (The PYTHON environment variable can also be set
before running configure to override the search.)

http://bugzilla.gnome.org/show_bug.cgi?id=578196
2009-08-31 13:42:06 -04:00
94b26888cf Build tweaks
Add .AUTOPARALELL which is my GNU-make fix for projects to specify
that the build is parallel-safe, and to automatically parallelize.

Add a missing dependency on built sources, and specify --libtool
to be safe.
2009-08-30 18:08:19 -04:00
156fdf1fa3 Update Catalan translation 2009-08-30 19:26:39 +02:00
2a3f9e8f83 Updated Czech translation 2009-08-30 17:37:51 +02:00
849ce371ff Updated Spanish translation 2009-08-30 11:17:50 +02:00
a76ac5501c Add Simplified Chinese translation. 2009-08-30 09:15:34 +08:00
5803aa7e65 Simplify Button class by using ShellButtonBox
Make Button class purely about adding visuals, and use ShellButtonBox
for behavior. API equivalences:

  shell.button => shell.actor [for consistency]

  staysPressed parameter to constructor => replaced by manually setting
   the 'active' property of button.actor as appropriate

  pressIn/release => button.actor.active = true/false

  enter-event/leave-event signals => button.actor notify::hover

Along the way, this fixes a bug with the user status menu where it was
not getting set to active because the button was getting a leave
(triggered by the menu popping up and grabbing the pointer) before for
button release, which disabled the staysPressed behavior.

Reported by Michael Meeks
http://bugzilla.gnome.org/show_bug.cgi?id=593471
2009-08-29 15:20:19 -04:00
0fd6bc5172 ShellButtonBox: only listen to button 1 and single clicks
Only mouse button 1 is supposed to activate button controls; other
mouse buttons should do nothing unless there is a context menu.

Checking the click count is important, since double-clicks will
otherwise look like unpaired button presses.

http://bugzilla.gnome.org/show_bug.cgi?id=593504
2009-08-29 15:20:18 -04:00
0e3cea41e0 ShellButtonBox: Use default handlers, not self-connections
There's seldom a good justification for connecting to signals on
yourself rather than using the default handler slots in the class.

But in particular using the default handler slots means that
an application can connect to ::button-press-event and get in
before the default handling, to implement a button that does
something on press.

http://bugzilla.gnome.org/show_bug.cgi?id=593503
2009-08-29 15:20:18 -04:00
45c600cd25 Add an active property to ShellButtonBox
Add an 'active' property to ShellButtonBox. This allows ShellButtonBox
to be used as a "toggle button". It's up the application to connect
it to the ::activate signal; there's no default handling of this.

(It's seldom that the only time you want to toggle a toggle button
through the user interface, so you need some connection to the backend
data store in any case. Removing the default handling all-together
prevents weird interactions.)

When we have built-in styling for ShellButtonBox the 'active' state
would be one of the elements that would be affect the styling.

http://bugzilla.gnome.org/show_bug.cgi?id=593502
2009-08-29 15:20:18 -04:00
7fb8e2d0ef Bug 592507 - Javascript exception when ~/.gtk-bookmarks is missing
Check the file exists before trying to access it and simply return if it
is not available.
2009-08-29 14:26:26 +01:00
2d5d54f3cd Update Dutch translation 2009-08-29 15:11:34 +02:00
949359db5d Added Danish translation 2009-08-29 10:25:03 +02:00
5bd2695863 Added Da to list of laguages 2009-08-29 10:23:43 +02:00
dfbbf9b436 Bump version to 2.27.1 2009-08-28 20:10:43 -04:00
a230ad9225 Improve the display of search results
Use bigger font and brighter color for the search results section headers.
Add more padding.

Display "(see all)" tooltip in the section headers on mouse-over.
(Still TODO: supressing that tooltip when all results are already being shown.)
2009-08-28 16:26:06 -04:00
7a87474bcd Switch Find entry text size to px
All our font sizes were in px, other than the size for the text in
the search entry. Switch that from 12 to 16px (which is the same size
at the standard 96dpi), it doesn't become out of scale if the DPI
is different. (Using fixed px sizes isn't probably what we want to
do in the long term; moving to style sheets will be a good place to
fix that. But better to be consistent.)

http://bugzilla.gnome.org/show_bug.cgi?id=593212
2009-08-28 16:21:21 -04:00
479acf2d18 Renable PrintScreen and Super_L in the overview
When we are modal, examine keypresses and look for:

 - 'Print': Run the screenshot command in any mode; very useful for
   bug filing, reviews, etc.

 - Release of Super_L/Super_R - if in the overview, toggle back
   out of the overview.

http://bugzilla.gnome.org/show_bug.cgi?id=593427
2009-08-28 15:15:17 -04:00
943c5e2edc Improve comment about button-release-event handler
Improve the documentation about the button-release-event handler
we put on the status-menu button at Colin's suggestion.

http://bugzilla.gnome.org/show_bug.cgi?id=593362
2009-08-28 12:40:56 -04:00
1340413740 Fix hang when clicking on the user status menu in the overview
shell-global.[ch]: Add shell_global_display_is_grabbed() that
  uses the newly added meta_display_get_grab_op() to check
  for existing grabs.
shell-status-menu.[ch]: Add shell_status_menu_is_active() to
  check if the menu is popped up. Check for active grabs before
  popping the menu up. Use gtk_menu_popdown() rather than
  gtk_widget_hide(). Remove an excess gtk_widget_show() and
  some excess casts.
panel.js: Check whether the status menu is popped up after button
  release, and if it's not popped up, unhighlight the button.

Reported by Nuno Donato
http://bugzilla.gnome.org/show_bug.cgi?id=593362
2009-08-28 12:34:04 -04:00
3adec65e20 Remove pre-GNOME-2.26 panel-replacement code
gnome-shell.in: Remove the code to replace gnome-panel by attaching
  to it with GDB; this was always problematical (required gdb, debug
  symbols, finding the pid of gnome-panel, etc.)

gnome-shell-build-setup.sh: Require 2.26 to be in place before building
  the shell; remove gdb from the list of required packages.

http://bugzilla.gnome.org/show_bug.cgi?id=593325
2009-08-28 12:34:04 -04:00
d116f707c5 Clear save_id when removing idle_save_application_usage()
When we remove the timeout for saving application usage when application
usage is disabled, set the save_id member variable to 0.

http://bugzilla.gnome.org/show_bug.cgi?id=589676
2009-08-28 12:34:04 -04:00
6f94b8cffe Change search box text to "Find..."
We want to find more than apps and documents and the previous
string was too long in some languages and on some display sizes.
2009-08-28 11:56:40 -04:00
14a7e310fc Make the gradient on the top panel the same as the "dash"
The previous top color was a bit too bright.
2009-08-28 11:47:19 -04:00
bf680fdc7c New class ShellButtonBox
This is a Box subclass which adds several signals useful for implementing
"button like" behavior, such as hover and pressed states, as well as
click activation on release.
2009-08-27 18:05:41 -04:00
851bf18265 Restore GNOME based on GNOME configuration
Instead of using pidof to find what was running when we started,
and then hacking in a restart with hardcoded paths in /usr/bin,
approximate how GNOME starts the panel and window manager.

This fixes restarting Compiz correctly:
 http://bugzilla.gnome.org/show_bug.cgi?id=593184

And restarting gnome-shell correctly:
 http://bugzilla.gnome.org/show_bug.cgi?id=591171
2009-08-27 15:33:47 -04:00
452e98e3bc Require an explicit --xephyr option
Instead of starting Xephyr automatically, require --xephyr to be
passed explicitly.

This makes the operation easier to understand and has the benefit
of allowing running in Xephyr mode when some other window manager
(like gnome-shell!) is running. We also want to emphasize that
Xephyr is a development tool, and not a good preview of the
user-interface.

http://bugzilla.gnome.org/show_bug.cgi?id=592881
2009-08-27 15:33:47 -04:00
3cb54f6707 Fix allocation implementations for ShellStack and ShellDrawingArea
In both, using our allocation directly for the child is wrong; we
should create a new allocation that's our width and height.

In ShellDrawingArea, also need to chain up to parent.
2009-08-27 13:11:19 -04:00
ed7881d6c9 [AppMonitor] Handle window title changes causing mapping changes
For Firefox/OpenOffice, right now we have a workaround in the
code where we look at their "title" property.  However, we
weren't monitoring that property for changes, and I'm fairly
certain Firefox at least was mapping a window and then very
quickly changing its title after.  So we need to handle
dynamic changes.

Split out the wm_class mapping from the title hack.  It was
messy and weird to have the two mixed because they're not
at all related, and we're not trying to handle WM_CLASS changes
right now.

Explicitly connect to notify::title in the case where we had
a title fallback.  When a title changes, just treat it as
an add+remove.

In the Application Menu area in the panel, hook up to app-added
and app-removed so we get notification of the active app changing.
2009-08-27 02:22:25 -04:00
ea1a45a878 Also remove libtidy-1.0.la from Makefile 2009-08-27 02:18:55 -04:00
003807334b Delete Tidy
It wasn't used any more.
2009-08-27 02:00:23 -04:00
24a5c3c19a Add "mozilla" as a vendor prefix
Clean up the vendor prefix handling a bit, and add "mozilla" so that
we pick up "mozilla-firefox.desktop" from Firefox's (recent?) change
to have a WM_CLASS of "Firefox".
2009-08-27 01:49:15 -04:00
62b2d69c2b Bug 592402 - Better handling of Nautilus window
Separate the application monitor logic for "tracking" and "usage tracking".
The first means we associate an application with a window.  The second
means we count focus time inside that window, and consider the window
interesting from a user point of view.

(Really, should probably split ShellAppMonitor into two classes along
 this line, with the second consuming the first).

For the purposes of counting running applications and returning
the list of open windows for an application, skip not-usage-tracked
windows.

Together this allows us to associate the Nautilus desktop window
with the nautilus.desktop, but not show "File Manager" open all
of the time.
2009-08-27 01:41:25 -04:00
cdbb7f8f5f Display only first page of search results by default and display a total results count
Display only first page of search results by default for each section and
allow clicking on the section header to view all the results for a given
section. This design will allow us to easily move from paging to scrolling
without having to stack multiple scrollbars in a single pane.

Display a total results count next to the section name. This serves as an
indicator that there are more results. The section header pre-lights to
indicate that it can be clicked on.

Make sure we go back to the first page of results when we exit a single
section mode. Make sure we re-instate all result sections if the search
mode is left.

Close the only section search mode on Esc, and only close the search
when Esc is hit again.
2009-08-26 18:46:58 -04:00
ecc1f964c9 Add 'r' as an alias to 'restart' in run dialog
For even faster turnaround inspection of changes.

Also add a comment about the idle_add in the 'lg' command.
2009-08-26 18:43:44 -04:00
0f4e9189c5 Split out "AppIcon" and make WellDisplayItem a subclass of it 2009-08-26 16:28:42 -04:00
799f56fe87 Use new plugin-modality functionality in Mutter
We now have functionality in Mutter to grab the keyboard on behalf
of a plugin. This avoids interactions with the key handling code
in Mutter that could leave the user with an inconsistent state
and no way to get out of it.

src/shell-global.[ch]: Change shell_global_grab_keyboard() and
  shell_global_grab_keyboard() to shell_global_begin_modal()
  shell_global_end_modal() and call mutter_plugin_begin_modal()
  mutter_plugin_end_modal() rather than directly grabbing the
  keyboard.
main.js: Call global.begin_modal/end_modal from Main.startModal()
  and Main.endModal()
altTab.js; Remove call to Main.startModal() - we're letting Mutter
  handle modality for Alt-Tab.
main.js lookingGlass.js overview.js runDialog.js: Rename
  Main.startModal() to Main.beginModal() for consistency with
  naming in mutter and ShellGlobal.

http://bugzilla.gnome.org/show_bug.cgi?id=590686
2009-08-26 14:07:02 -04:00
af9ab5dbb6 Only respawn if gnome-shell exits abnormally
If Mutter exits with an exit status of 0, then that most likely
means that it was replaced by another window manager and we shoudln't
try to start the previous window manager and the panel.

(We don't actually know about the panel, but assume that if someone
is replacing us they know what they are doing.)

When Mutter exits with a signal, we know we want to restart.

When Mutter exits with a non-signal non-zero exit status, it's
ambiguous - we could be exiting because we lost the connection to
the X server, or because of a assertion failure in gnome-shell.
We assume the latter; if the X server is gone, all that will happen
is a bit of noise.

To know why Mutter exited accurately, we always wait() and
kill() the Mutter process, and then, if running in Xephyr, clean up
Xephyr afterwards. This has the nice side effect of exiting when
gnome-shell does and not forcing the user to close Xephyr manually.

http://bugzilla.gnome.org/show_bug.cgi?id=591171
2009-08-25 19:01:42 -04:00
3486fcc89a Updated Swedish translation 2009-08-25 07:48:31 +02:00
1e2018d1b7 Update and improve Dutch translation
Improvements mentioned by Wouter Bolsterlee in gnome-nl-list.
2009-08-24 22:39:53 +02:00
fb46bad665 Add Korean translation 2009-08-23 04:51:56 +09:00
e2d912c037 Added Galician Translation 2009-08-22 16:40:06 +02:00
2879d9cdef Updated Spanish translation 2009-08-22 12:22:25 +02:00
300cefd66a Display search results in the dash
Display search results in the dash instead of showing them in a separate pane.
We get dynamic allocation for the section height based on the number of
results, but a lot of the problems with the previous search results display,
such as displaying empty sections and paging overflow are still present.

Also, we don't yet close the browse pane for applications or documents when
we display the search results and only replace it if we are showing the
details pane, so all that looks weird. We'll need to work out the interaction
for these cases.
2009-08-21 18:21:35 -04:00
72b4d2a234 Make hotCorner a class variable
This fixes a bug where we were already using this._hotCorner
in _onHotCornerEnvironsLeft() and were incorrectly setting
this._hotCornerEntered to false when the hot corner was
re-entered from the environs.
2009-08-21 15:56:07 -04:00
02e438b1f8 Add Dutch (nl) translation 2009-08-21 20:10:13 +02:00
58690c210e [ShellAppSystem] fix missing break; in _unref 2009-08-21 13:19:28 -04:00
61f19a6c22 Added Norwegian bokmål translation. 2009-08-21 12:44:31 +02:00
7465338ea1 [appDisplay] Always relaunch application on drag and drop
Rather than just launching if we weren't already running, always
relaunch, which happens to make Firefox, etc. work.  See
the comment in the commit for more explanation.
2009-08-20 20:03:28 -04:00
9dff05a394 places: Implement drag&drop for overview
Add drag and drop.  We need to be able to recreate the icon texture,
so instead of passing it directly into PlaceDisplay, pass
a factory function which knows how to create a new texture.
2009-08-20 19:37:51 -04:00
9f5a5ad635 appDisplay: Don't leave overview for drag&drop of an app
The design says we stay in the overview for these situations.
2009-08-20 19:37:50 -04:00
2dcd0511c4 dash: Make recent docs display two columns
The design has smaller icons in two columns.  Add a new
custom display to docDisplay for it.

Clean up some of the texture cache handling for recent URIs so
it's not size-dependent, since the dash size is now different
from the default GenericDisplay size.
2009-08-20 19:37:50 -04:00
dd1a309cb6 dnd: Centralize drag actor positioning code, use shellWorkspaceLaunch for workspaces
We had multiple copies of the code to position a drag actor given a particular
source.  Instead, just put it inside dnd.js.

Second, rather than test for GenericDisplay/WellDisplayItem etc.,
in various places, add a new method on each source "shellWorkspaceLaunch"
which both marks the item as being droppable on a workspace, and is
called by the workspaces code to launch the item.
2009-08-20 19:37:50 -04:00
9563515e97 Fixed problem in tr.po file. 2009-08-21 00:45:14 +03:00
ba77c51ee0 Added Turkish (tr) translation. 2009-08-21 00:43:21 +03:00
2e83b95484 Updated Italian translation 2009-08-20 23:30:23 +02:00
756374b2e4 Unmark GdmUser property strings for translation 2009-08-20 18:09:33 +02:00
527ff6fb1d Added Swedish translation 2009-08-20 16:57:28 +02:00
fb4fc496da Updated German translation. 2009-08-20 16:51:19 +02:00
8d9bd87c22 Updated Italian translation 2009-08-20 16:48:37 +02:00
36acb0a63d Added Italian translation
* Added it to LINGUAS
2009-08-20 11:42:39 +02:00
3e0f5aec0c Bug 587951 - Don't show empty categories
When loading menus, skip ones which entirely consist of NoDisplay=true
items.
2009-08-18 23:27:49 -04:00
4f5c3b4b74 Bug 591267 - Fix places icon centering
Pack the place icon in a vertical centering box to avoid the horizontal
box stretching it vertically.
2009-08-18 23:15:57 -04:00
a4bf54e465 ShellAppMonitor: create "applications" for unknown windows
Use MetaGroup for a window when looking up applications.  If
we know the application for a TYPE_NORMAL window in the group,
use that.

However, we aren't always going to know the application for a window.  In
that case, create a fake one.

ShellAppInfo has a "transient" flag so we know not to write these
fake apps to the usage file.

Clean up the idle focus handler to better handle the case where
no window is focused, and where we don't want to track the
particular window.

Update track_window to create the fake window.

When a window goes away, we want to delete the usage.

Rewrite shell_app_monitor_get_running_apps to be based
on the window_to_app hash, because that's what has the pointer
to ShellAppInfo*.  Before we were looking up all ids through
ShellAppSystem, but that shouldn't be holding a ref to transients.

Change the well display icon to be centered, since our icons for
window apps aren't 48 pixels.
2009-08-18 23:07:16 -04:00
d94606587b Add shell_app_system_create_from_window
For various cases such as when we don't know a .desktop file
for a window, it's desirable to "fake" an application from
the contents of a MetaWindow*.
2009-08-18 23:00:47 -04:00
74ea9f9305 Add shell_texture_cache_bind_pixbuf_property
This utility function is targeted for MetaWindow; we can create
a ClutterTexture which tracks the value of an "icon" property.
2009-08-18 22:58:27 -04:00
4dc04d8c53 Update .gitignore for i18n files 2009-08-18 18:19:16 -04:00
6e298759a4 Use g_shell_parse_argv() in run dialog
http://bugzilla.gnome.org/show_bug.cgi?id=581137
2009-08-18 18:17:02 -04:00
3b320de8d7 Updated Polish translation 2009-08-18 23:26:25 +02:00
30d3c1fe72 Use a larger area around the hot corner to decide if the user has left the hot corner
Using a larger area around the hot corner to decide if the user has left the
hot corner prevents triggering the hot corner multiple times due to an
accidental jitter.
2009-08-18 14:59:53 -04:00
7469a2626a Bug 591859 - Use glib/gi18n-lib to get correct gettext package
We need to use the -lib variant which in turn uses the
GETTEXT_PACKAGE define, because the default translation
domain is actually mutter, not gnome-shell.
2009-08-17 08:53:59 -04:00
d534597589 Add a po/POTFILES.skip with gnome-shell.desktop.in
It's generated from the .in.in.
2009-08-17 08:47:29 -04:00
ec3c8464d3 Updated Spanish translation 2009-08-16 16:23:35 +02:00
6319f649c2 Some search appearance fixes for last commit
Add a close-black.svg.  Add some padding around the content.
Fix magnifier.svg to be 18 pixels wide.
2009-08-16 10:09:34 -04:00
44d34aba19 Highlight the search entry when the user clicks or starts typing in it
This will give the user a visual indication that the search is active.

We need to replace the gray close button in the search entry with a black one.
2009-08-15 16:40:59 -04:00
4245c573df Clean up our .typelib generation rules
- Prepend to the LD_LIBRARY_PATH not append
- Use $(G_IR_COMPILER) instead of g-ir-compiler
- Use $(AM_V_GEN)
2009-08-15 10:17:36 -04:00
c27b6493d6 autoconf-2.64 compat: Don't use $(builddir)
$(builddir) is not a standard automake variable. With autoconf < 2.64
it ends up getting set in every Makefile.in to '.' (because autoconf
defines it), but that is no longer the case for 2.64.

Since $(builddir) was always '.', just use that instead.
2009-08-15 10:17:35 -04:00
7200207009 Initial Czech translation 2009-08-15 15:35:32 +02:00
9ba66fd800 Remove whitespace so l10n.gnome.org is happy 2009-08-15 14:49:48 +02:00
e4552fca40 Updated Irish translation 2009-08-15 06:01:33 -06:00
b7d892e4c6 Added Spanish translation 2009-08-15 12:53:00 +02:00
5b096be68b Added es to LINGUAS 2009-08-15 12:51:29 +02:00
e843d11566 Added missing files to POTFILES.in 2009-08-15 12:43:09 +02:00
9c7803030e Added Irish translation 2009-08-15 04:24:19 -06:00
67ef36ef8e Hungarian translation added 2009-08-15 11:37:06 +02:00
4c1614f6a5 added hu to LINGUAS 2009-08-15 11:36:42 +02:00
3766784799 Pass foreign option to automake
We don't want a ChangeLog file.  NEWS maybe.
2009-08-14 20:02:07 -04:00
56e16ef712 Add Catalan translation. 2009-08-15 00:14:28 +02:00
559c313fc7 Fix untranslatable string: "Find apps or documents" 2009-08-15 00:13:55 +02:00
5e10d56d89 Added Brazilian Portuguese translation. 2009-08-14 18:11:00 -04:00
d289ce6aca Updated German translation. 2009-08-14 23:43:27 +02:00
c68e69bd6e 2009-08-14 Hendrik Brandt <heb@gnome-de.org>
* Update LINGUAS, add de
2009-08-14 20:42:51 +02:00
a6f312cfd3 2009-08-14 Hendrik Brandt <heb@gnome-de.org>
* po/de.po: Initial German translation.
2009-08-14 20:40:16 +02:00
ca51a8c926 Add initial calls to Gettext
We don't have a lot of strings, and what ones we do have we've
been avoiding duplication.  This patch adds calls to _() i.e. gettext
for those strings we do have.
2009-08-14 09:32:15 -04:00
ec95a1c2d3 Add test fr translation
Useful to verify that translation infrastructure is working.
2009-08-14 09:32:12 -04:00
a418558b73 Add localization
Infrastructure for localization; hook up intltool, create po/
and po/POTFILES.in.  We need to call bindtextdomain/bind_textdomain_codeset.

Switch to gnome-autogen.sh to call intltool.
2009-08-14 09:14:34 -04:00
f097304f3b Bug 582763 - Remove maximization effects
The maximize effect looked really ugly.  In the absence of any cooler
effects, none at all is better than what we have.  Current compiz
doesn't have one either.

Note that in the future when we merge the frame into the panel
in the maximize case, we may want an effect for that.
2009-08-14 08:41:00 -04:00
ea4ea4a9b2 Disable sidebar by default
The sidebar is a bit neglected currently; we'll revisit it when
we have more design and code time to focus on it.
2009-08-13 22:51:16 -04:00
b94452ee42 Redo highlight-drawing logic slightly, as suggested by Owen 2009-08-13 13:51:48 -04:00
51db34d223 Implement distinct 2-window and multi-window highlights 2009-08-13 13:19:24 -04:00
059c330d95 Clear _searchTimeoutId when removing search
When we remove the search because the search empty is
entry, we need to reset _searchTimeoutId to 0.

http://bugzilla.gnome.org/show_bug.cgi?id=591719
2009-08-13 13:15:02 -04:00
557f9ceb97 Bug 591590 - Fix some applications not appearing in menu
Use the correct address for the entry, instead of treating the
ShellAppInfo pointer as one.
2009-08-13 13:02:29 -04:00
4aae57c274 Explicitly set the size of the workspace actors
Instead of counting on the implicit sizing of ClutterGroup, which isn't
going to work well because of current limitations of ClutterClone, set
the size of workspace explicitly based on the screen size.

This should fix various problems with drag-and-drop being unreliable;
if a workspace was sized to big it could overlap other workspaces or
elements of the overview.

http://bugzilla.gnome.org/show_bug.cgi?id=591643
2009-08-13 08:50:05 -04:00
fb0ca1ba9d Make dragging an item to the Add Workspace button launch it on a new workspace
It is convenient to drag an item to the Add Workspace button and
have it be launched on a new workspace.

Based on a patch from Josh Adams.
2009-08-12 20:13:24 -04:00
51723bb93b Bug 591626 - Fix crash in ShellAppMonitor
Pass application into signal as expected.  Be sure to reference
it across the call, since removal from the hash unrefs it.
2009-08-12 19:45:17 -04:00
1e41f869de Bug 591624 - dash: Rename searchId to searchTimeoutId
From review comments.
2009-08-12 19:37:47 -04:00
28517e4c34 places: Use consistent variable for bookmark monitor timeout
We had an inconsistent usage of the timeout variable name.  Fix
it to consistently be a member property of this.
2009-08-12 19:34:02 -04:00
619066780f dash: Clean up search pane creation
There was some weirdness relating to when the search pane is shown
in a timeout, and how that relates to setSearch.  Instead of doing
this in the timeout, just call setSearch() in the timeout.  The
pane hide/show state is directly controlled from the handler.
2009-08-12 19:33:08 -04:00
1636e6c187 dash: Don't expand displayControl
It shouldn't take up more space than it needs.
2009-08-12 19:32:50 -04:00
d17c94f9b9 Initialize ShellAppMonitor/ShellAppSystem at predicatable time
Currently ShellAppMonitor relies on all the .desktop files being
loaded.  We should initialize it very early to ensure that anything
that uses it has up-to-date information right away.
2009-08-12 17:10:17 -04:00
4b47803162 Implement the multi-window highlight on WellDisplayItem 2009-08-12 17:08:19 -04:00
15a3f39f65 Add finer-grained signals to ShellAppMonitor, update appDisplay 2009-08-12 17:08:19 -04:00
f7d85e618c Bug591246 - Minor code-cosmetic fixes
Missed these two in original commit.
2009-08-12 16:33:39 -04:00
f00500d3d5 Bug 591246 - Move towards shell-black02 mockup
Remove the last use of passing width into Dash by having the
Pane with the previews scaling dynamically and relying on
Clutter scaling.

If we only have one workspace, don't display a selection frame
for it.

Rework Dash into a searchArea and sectionArea, which get
explicitly sized by overlay.js.  We use the workspaces size
to choose the size of those dash areas.

Switch dash colors/boxes etc. to ones from shell-black02.

Add a gradient to the panel.

Add a magnifier.svg for use in search.
2009-08-12 16:07:05 -04:00
25a5da074c ShellTextureCache: Don't try to scale pixbuf to 0 size
If we pass in -1 for both width and height, we'd attempt
to scale the image to 0x0.  Don't do that; just avoid
scaling the pixbuf and let ClutterTexture do it for us.
2009-08-12 15:56:43 -04:00
43d737c663 Ensure dash is raised over workspaces
Having the workspace actor on top of the dash broke drag and drop.
2009-08-12 15:12:55 -04:00
789e24b59a ShellAppMonitor: Correctly handle transients
If looking up the application for a transient window, try look up
its transient source.  Ignore transients for the purposes of counting
open windows.
2009-08-12 10:10:19 -04:00
b51bcf3e2b Catch exception trying to create a preview of an unknown image type 2009-08-12 01:30:58 +02:00
babb13f603 Remove unused button width and height arguments and specify button height explicitly
minWidth and minHeight arguments of the Button class were not used.

Panel buttons need their height to be explicitly specified as
PANEL_HEIGHT to take up full panel height. This fixes the problem with the
user not being able to click at the very top edge of the panel to activate
the button.
2009-08-11 18:16:33 -04:00
21ef33df65 Replace libgnomegnomeui with gnome-desktop in gnome-shell-build-setup.sh
With the recent switch to use libgnome-desktop for thumbnailing instead
of libngomeui, we should require that instead.

(Updated for Debian/Ubuntu, Fedora, OpenSuSE, unable to figure out
the right name for Mandriva in a quick web search.)
2009-08-11 16:39:43 -04:00
83b1cedb86 Use distinct filenames for all code generation tempories
Because of a history of cut and paste, the different enumeration
and marshal generation generation shell snippets were using the
same temporary file names. This caused problems for parallel
builds.

http://bugzilla.gnome.org/show_bug.cgi?id=591474
2009-08-11 16:05:31 -04:00
36ee36283a ShellAppMonitor: Add static to definition of sequence_ref 2009-08-11 13:35:08 -04:00
74eac21870 Add application menu area to panel
This is a start at the "Active Appliction Item" component of the
shell design.  Currently we just show the currently focused
application.  When launching a new application, we show that as well.

The implementation here is not complete; basically when launching
we de-focus the active one, and the application well shows the
most recent startup sequence.

This kind of fails in the case of multiple sequences, and we
also don't correctly de-focus the current window in other
launch paths.
2009-08-11 13:09:41 -04:00
e330c5ea17 panel: Switch to fully dynamic layout
There was lots of fixed positioning in the Panel; now it is completely
dynamic, and width/height is driven from main.js.  We still have a
global constant Panel.PANEL_HEIGHT, but this is a big step towards
eliminating it.

Also, this avoids overdraw in the "way too many tray icons" case.  The
clock will shift left.
2009-08-11 13:08:19 -04:00
e6644b7feb Use GnomeDesktopThumbnailFactory instead of GnomeThumbnailFactory
http://bugzilla.gnome.org/show_bug.cgi?id=591008
2009-08-11 11:27:52 -04:00
47af454115 Bug 591437 - Rename overlay.js to overview.js
Replace 'overlay' with the more descriptive name 'overview'
where the Activities Overview is meant. Call it Overview
(capitalized) in code comments.

The overlay-group and overlay-key provided by Mutter are not
affected, since they may be used for other components than
the Activities Overview.
2009-08-11 15:15:25 +02:00
1f31e80c47 Bug 584609 - Zoom the whole overlay when showing or hiding
Instead of only transforming the active workspace, create a
zooming effect when showing or hiding the overlay. This makes
the transitions simpler: the workspaces are now fixed to the
overlay actor group and will not slide over the Dash.

overlay.js: Add zoom animations, fade in/out Dash during those,
    remove obsolete Dash clipping and stacking logic, add public
    get[Scale|Position]() and getZoomedIn[Scale|Position]()
    functions.
workspaces.js: Remove zoom animations, add fade animations for
    the remove button, add helper functions for the overlay
    zooming, keep the movement of windows linear to that of
    their workspaces, remove the updatePosition() and
    updateInOverlay() functions and fullSize variables that
    were left from the old overlay design.
2009-08-11 02:21:13 +02:00
b0c7dac56b Distribute places.js
Add places.js to the Makefile.am
2009-08-10 18:36:54 -04:00
e5aa67421d Fix distcheck-hook for missing distributed JS files
Use git ls-files not git-ls-files, since git-ls-files is no longer
on the path with Git 1.6
2009-08-10 18:18:29 -04:00
fdd50f09dd Don't dist gnome-shell.in
We only want to include gnome-shell.in.in in the tarball. If we
include gnome-shell.in, then it won't be regenerated, and paths
won't be correct for the install location.
2009-08-10 18:02:41 -04:00
26a074588b Bug 591114 - Remove expanded background
The "expanded background" that is behind the workspaces etc. in the overview
should be removed.  It isn't in the designs, it is distracting, and it breaks
the overview metaphor.

At least temporarily, just make the background of the overview black.
Change the pane popup to black as well, but keep a blue border so that
it is visually distinguished from the background.

Based on a patch by Colin Walters, with fixes from  Marina Zhurakhinskaya.
2009-08-10 17:25:05 -04:00
00cc32d95a Ignore clicks on hot corner during transition
It's both intuitive to go to the corner of the screen
and click the activities button at the same time.

Both actions bring up the overlay,  but combined
they cancel each other out.  This commit makes
clicking the hot corner not cancel the act of
going to the hot corner.

Based on a patch from Ray Strode.
2009-08-10 14:19:07 -04:00
df8f727bba Add .desktop file to .gitignore 2009-08-10 13:57:40 -04:00
de8084ed40 Specify the clutter-1.0 branch of Clutter
For now, we want to stick to the stable branch of clutter rather
than tracking new developments. Now that Clutter has branched for
1.0 switch our moduleset to the clutter-1.0 branch.
2009-08-10 12:13:09 -04:00
9fa88caded Bug 591316 - Fix bad notify:: parameters
We weren't using them, and they were wrong.
2009-08-10 11:18:19 -04:00
06d17e08c0 Reposition windows when scaling workspaces
The scale of windows within a workspace is determined by the
scale of the workspace since we never scale a window bigger
than the original size of the window. So when we rescale
workspaces we have to rerun Workspace.positionWindows().

http://bugzilla.gnome.org/show_bug.cgi?id=591124
2009-08-10 10:09:25 -04:00
4830808d2f When fading in window icons, use the final position not current position
The onComplete when positioning windows may come before the
final stage of the workspace positioning animation. So we can't
use actor.get_transformed_position() to figure out where to put
the icons. Compute the final position manually ourselves instead.

http://bugzilla.gnome.org/show_bug.cgi?id=591123
2009-08-10 09:59:40 -04:00
02ee6f69b3 Fix updating of workspace frame actor
Both the position and size of the frame actor depend on the scale
of the workspace, so update them both when the scale changes.

On the other hand, the the frame actor doesn't need to be
repositioned when the workspace moves (since it is relative to the
workspace). We do base the frame  position of the desktop actor, but
that will presumably stay fixed (at 0,0) in most all cases.

http://bugzilla.gnome.org/show_bug.cgi?id=591122
2009-08-10 09:56:35 -04:00
5d0808e1c0 Use the size of the window, not of the clone to position windows
When Workspace._positionWindows is called, the clone might nto
yet have its final size (because of the clone is is a clone of
the window texture and the window texture isn't updated until
right before painting.) So get the size from the MetaWindow
instead ... the MetaWindow size is determined synchronously when
the window is managed.

http://bugzilla.gnome.org/show_bug.cgi?id=590741
2009-08-10 09:54:38 -04:00
1f864fba7f Show bookmarks with spaces in the name correctly
Take everything in the ~/.gtk-bookmark lines after the URI
as label, not only the first word. (eg. if there's a line like
"file:///home/rainct/Ubuntu%20One Ubuntu One", now "Ubuntu One"
is taken as the label, instead of only "Ubuntu").
2009-08-09 19:19:07 +02:00
cc83aee401 Show "Network" item on Ubuntu
If gnome-network-scheme.desktop can't be found, look for
network-scheme.desktop (which is used, for example, on
Ubuntu).
2009-08-09 19:00:00 +02:00
185ccecec1 Make <AppSystem>.load_from_desktop_file() raise an exception again
Pass the error variable to g_key_file_load_from_data_dirs in
Shell.AppSystem.get_default().load_from_desktop_file again, and
use a try/catch in places.js.
2009-08-09 18:32:22 +02:00
f96193dc8c Thumbnail generation without GtkRecentlyUsed in TextureCache
This fixes Shell.TextureCache.get_default().load_thumbnail so
that it can be used to get thumbnails (with an icon matching
the mimetype or, in the worst case, gtk-file, as fallback) for
items which don't have a GtkRecentlyUsed object. This is needed
for the Zeitgeist integration.
2009-08-09 17:46:21 +02:00
205c57d6af Fix FTBFS and crash triggered by <AppSystem>.load_from_desktop_file()
- Avoid error '"iconname" may be used uninitialized in this function'
  by initializing said variable to NULL.

- Define shell_util_get_file_description as static (like the other
  similar functions) to avoid another compiler error.

- Don't save errors from g_key_file_load_from_data_dirs into the
  variable "error" (ie. pass NULL to it instead). Without this,
  gnome-shell crashes if the key file can't be found (with message
  "Error invoking Shell.load_from_desktop_file: Valid key file could
  not be found in search dirs").

- Check the result of the load_from_desktop_file() call in places.js,
  as it may be null.
2009-08-09 17:39:17 +02:00
5c97d21889 Fix comment header for shell_texture_cache_load_uri 2009-08-09 09:53:06 -04:00
e323593f4a Add Places
Implement the Places mockup.  This commit adds a link to Home,
Network, Connect to server, and the GTK+ bookmarks.
2009-08-09 09:53:06 -04:00
3bae3fa203 Add shell-uri-util.[ch]; functions ported from gnome-panel for URIs
These two functions are useful for the Places implementation to
get name/icon for a desktop-related URI such as Documents or
Downloads.
2009-08-09 09:53:06 -04:00
9bd22dc033 ShellAppSystem: Support loading a .desktop file directly
Previously, ShellAppSystem only loaded (and cached) the set of
.desktop files from applications.menu and settings.menu, using
the gnome-menus library.  The ShellAppInfo structure was
a "hidden typedef" for GMenuTreeEntry.

But we need to support loading an arbitrary .desktop file.  Thus,
refactor the ShellAppInfo into a real struct, with a refcount,
and allow it to point to either a GMenuTreeEntry or a GKeyFile.

Also, in the case where we fail to lookup an icon for an
application, ensure we return a 0 opacity texture.
2009-08-09 09:53:06 -04:00
5064d873bb Add shell_texture_cache_load_from_name
Utility function to load a texture for a themed icon from a
string name.
2009-08-09 09:53:05 -04:00
4495f98dce Fix negative height request in WellGrid
When WellGrid had no child it was doing a division by zero,
which screwed up the calculation for the height request and
having it ask for a negative number. This commit fixes this
by always requesting 0 in this case.
2009-08-09 03:34:35 +02:00
5a75b44f71 Consider height when positioning windows in the overlay
I've done some little modifications to the window positioning code
used in the overlay so that it considers the height of the windows
and they don't overlap or get out of the workspace.

I've also raised the hard-coded scales a bit to have the windows as
big as possible without overlapping (this could use some testing on
a non-widescreen monitor).
2009-08-08 22:10:40 +02:00
ebd6f4bc8f appDisplay: Reimplement well layout to be width-independent
Use ShellGenericContainer to implement a fully dynamic layout
for the application well.  It's still fixed to 4 columns by default,
but no longer requires a fixed width to be passed in on start.

With another chunk of work, it could likely try to adjust to
the case where we can only fit fewer than 4 items in the well.

Remove the border highlighting on mouseover, since that caused
reallocations, and the grid layout isn't trivial.

Delete the unused shell_global_get_word_with function.
2009-08-08 15:47:49 -04:00
687a87d3d0 Define stable ordering for application favorites and running apps
For both of these, because of optimizations a few patches ago, we
ended up relying on hash table ordering which caused instability
in the application well among other things. Define an ordering
for both.

The favorites is just the order of the GConf keys, and new items
get appended.  In the future we should allow insertion at any
point which the grid could use.

For running applications order, define a new "initially_seen_sequence"
transient variable which is just an monotonically incrementing
integer assigned to an application for the first time we saw it
running in this session.  When an application is closed, it's reset.
2009-08-08 15:47:49 -04:00
464842ea36 Change to $HOME before launching gnome-panel again
When exiting from --replace mode, we want to start the new
gnome-panel with a reasonable working directory so that if, you say,
open a terminal from it it doesn't start off in the gnome-shell
directory.

(gnome-shell itself is running in $HOME because mutter changes
directory itself at startup.)

Reported by Mathieu Bridon
http://bugzilla.gnome.org/show_bug.cgi?id=591145
2009-08-08 12:51:01 -04:00
91911da302 Bug 590985 - Fix frequent apps list being empty
We shouldn't append .desktop again, that was a leftover from
the old WM_CLASS based application code.
2009-08-08 11:57:09 -04:00
3c87d76741 dnd: Fix used of undefined variables
The variables this._yOffset and this._xOffset are included in the
drop coordinates, but as far as I can tell never defined.  Looking
back on the commit that introduced this code, they weren't removed
from anywhere else either.

The drop coordinates seem correct without them, so just delete them.
2009-08-08 10:09:30 -04:00
ccafa53bd6 Enable hot corner for triggering the overview mode
Use the 1x1 actor in the top left corner of the screen to enter and leave
the overview mode by just moving the mouse over to it.

No delay is used for triggering the hot corner because a delay significant
enough to allow moving away the mouse to avoid triggering it ruins the desired
flow when triggering the hot corner is actually intended.

The hot corner is not enabled in the full screen mode because the application
or the virtual system might have a hot corner of its own in that place.
2009-08-07 16:45:35 -04:00
4e23f4cfc9 Bug 591077 - Hide overlay when activating an application
It's easier to explicitly call Main.overlay.hide() instead
of chaining activation signals, this got lost in a mix between
the big dash rewrite and ongoing changes to the Application well.
2009-08-07 15:45:52 -04:00
544a80fc6e Add a desktop file for gnome-shell
Add a desktop file for GNOME Shell. This allows making GNOME Shell
your desktop default by adding it to your auto-start items.

http://bugzilla.gnome.org/show_bug.cgi?id=591089
2009-08-07 14:13:24 -04:00
4d52c10958 Bug 589316 - Add application/window icon to overlay windows
To better distinguish between vast fields of white of which many
windows are composed, add the application icon to the bottom
right of the window.

We fade them in to avoid an abrupt feel.  The icons are in the
workspaces group, not individual workspace groups to avoid
having to adjust them when we scale the workspaces.

Replace Workspace._lookupIndexAndClone with Workspace.lookupIndex,
and make the caller go from index to clone, or clone and index.
2009-08-07 13:29:34 -04:00
c23b9ee192 dnd: Emit drag-end in after snapback complete
Emit the signal at the correct time to take action
on snapback (i.e. after the end of the snapback animation).

Add a boolean to the drag-end signal saying whether it was accepted,
which ensures consumers know whether the drag was successful.
2009-08-07 13:29:34 -04:00
296e0c2054 Remove residual references to libXScrnSaver in required packages
See 5527fa2bc3. Now that we don't use it at all, no need to install the package either.
2009-08-07 15:28:05 +02:00
5527fa2bc3 Remove residual references to libXScrnSaver
Now that we are no longer using the screen saver X extension, remove the check
for the .pc file and the include of the header file.
2009-08-06 18:30:47 -04:00
59532ab0c7 Check the result of fgets() to deal with warn_unused_result
Some C library versions have __attribute__((warn_unused_result)) on
fgets(). We really don't care since we are just throwing the data
away, but check the result anyways.
2009-08-06 17:59:20 -04:00
ad5a9d8f8b Turn on "silent-rules" for automake >= 1.11
When AM_SILENT_RULES is available, use it to strip down the output
of make so we can see what's important rather than gigantic long
compile lines.

Use 'make V=1' to see everything again.

Fix a couple of places where we had 'cmp' rather than 'cmp' and were
getting standard-error spew about missing files when generating
enum-types.h files.

http://bugzilla.gnome.org/show_bug.cgi?id=591002
2009-08-06 16:58:40 -04:00
d243634602 Fix compiler warnings
src/shell-global.c src/shell-process.c: Remove dead code
src/shell-texture-cache.c src/shell-status-menu.c: Remove
  <foo>_new() functions that weren't in the header file and
  not used anyways:
src/shell-texture-cache.[ch]: Fix a prototype that used ()
  when (void) was intended.

http://bugzilla.gnome.org/show_bug.cgi?id=590998
2009-08-06 16:46:55 -04:00
e89d3c7b07 Turn on -Werror and -Wmissing-prototypes
When compiling with GCC turn on -Wmissing-prototypes, and by default
turn on -Werror as well.

As with most gnome modules:

 --enable-compile-warnings=minimum/maximum

Can be used to disable -Werror (they are the same)

http://bugzilla.gnome.org/show_bug.cgi?id=590998
2009-08-06 16:46:55 -04:00
354112fb41 Tweak sizing of windows in overview
Tweak arrangements with 2,3,4,5 windows in a desktop so:

 - Windows are a bit bigger
 - All windows for 5 windows are equally sized instead of making
   the windows in the bottom row larger

This does cause some more problems with tall windows overlapping
or running off the edge of the workspace, but it's an overall
small improvement to the behavior.
2009-08-06 15:19:04 -04:00
f7746ec3f6 Initialize GStreamer from shell_recorder_init()
Move the GStreamer initialization from the Javascript code into
shell_recorder_init(). This avoids a dependency on the GStreamer
introspection information and will make it easier to drop the
gir-repository module dependency.
2009-08-06 15:19:04 -04:00
03e0fe1e95 Replace _getIndexOfDisplayedActor with a function in OverflowList
Said function in genericDisplay.js was returning the index of the
actor based upon its position in the entire list, while everywhere
else indexes relative to the currently displayed page were used.

This made actions in the details pane break (bug #590949), so I
replace it with a new function in shell-overflow-list.c,
shell_overflow_list_get_actor_index, which is page based.
2009-08-06 19:51:11 +02:00
22c98e6240 Fix incorrect variable name: mimeType -> this.mimeType. 2009-08-06 17:25:58 +02:00
90979faedd ShellAppMonitor: Fix case of not seeing apps being closed
Remove the app from the window_to_app hash *before* emitting
CHANGED, otherwise a signal handler could see stale data.
2009-08-05 20:13:44 -04:00
21858d928a Clear text in the run dialog when it's hidden with escape 2009-08-06 02:04:04 +02:00
be95ca553a Fix indentation issues in altTab.js, plus minor cleanup in some other files. 2009-08-06 01:54:22 +02:00
c4b4248707 Bug 589086 - Fix non-integer positioning in altTab
Non-integer makes fonts look awful.  Fix this by rounding
down.
2009-08-05 11:43:54 -04:00
91353c6d60 Add ShellGenericContainer, which makes it possible to write containers in JS
Subclass ClutterGroup (to avoid having to implement all of dispose,
raise, lower, add, etc.), and have it proxy the allocation requests
out into signals.  We have to group up the two out parameters
into a struct unfortunately.

Included example code in the C file source for now.
2009-08-05 11:36:33 -04:00
31851cbc32 Install missing svg files. #590814 2009-08-05 08:59:57 -04:00
41f6e8ef86 Add dash.js to js/ui/Makefile.am. #590813 2009-08-05 08:58:35 -04:00
85b4b97b7b Rewrite Dash, remove hardcoded width/height from GenericDisplay
This patch is a near-total rewrite of the Dash.  First, the dash
code moves into a separate file, dash.js.

Inside dash.js, the components are more broken up into separate
classes; in particular there's now a Pane class and a MoreLink
class.  Instead of each section of the dash, when activated,
attempting to close all N-1 other sections, instead there
is the concept of a single "active pane", and when e.g. activating
the More link for documents, if we know there's an active pane
which happens to be the apps, close it.

Many redundant containers were removed from the dash, and all
manual width, height and x/y offsets are entirely gone.  We move
the visual apperance closer to the design by using the view-more.svg,
etc.

To complete the removal of height/width calculations from the dash,
we also had to do the same for GenericDisplay.  Also clean up
the positioning inside overlay.js so calculation of children's
positioning is inside a single function that flows from screen.width
and screen.height, so in the future we can stop passing the width
into the Dash constructor and call this once and work on screen
resizing.
2009-08-05 04:04:27 -04:00
2726fdb831 Bug 588343 - Major rework of window monitoring to be application-based
The previous application monitoring code was originally designed
to be based on WM_CLASS, which was then resolved on a server.
We have that resolution code locally now, so instead
of saving WM_CLASS data, save application IDs.

Also, inside the WM we have a much better
infrastructure for tracking windows.  In particular, rather
than polling, we can just watch for focus notification on
the display, and window add/remove.

Instead of polling XScreensaver, use DBus to watch org.gnome.Session
which already has an idle time watch.

Now there is no polling at all inside the monitor.
2009-08-04 18:40:37 -04:00
b1150eb147 Bug 589276 - Use 0 opacity while loading textures, preserve aspect ratio by default
When we fail to load a texture, make sure we keep it 0 opacity to avoid
a white square.  Also this is useful to avoid the square while loading
a texture asynchronously.
2009-08-04 16:48:12 -04:00
898d76af53 lookingGlass: Add hierarchy list and property inspector
Add a Notebook class which we then use to pack in separate Hierarchy
and Properties tabs.

Split out the inspector into its own class to avoid bloat in the
main class.
2009-08-04 11:12:02 -04:00
7c26303b25 lookingGlass: Add to Makefile.am
Signed-off-by: Colin Walters <walters@verbum.org>
2009-08-04 10:01:06 -04:00
902956ca0d lookingGlass: Draw a red border around target actor 2009-08-04 09:55:52 -04:00
3429abff40 lookingGlass: Faster history save, avoid empty lines
5 seconds is should help ensure we lose work less often on
Alt-f2 restart.

Avoid saving empty lines to history, and filter them out if
we find them.

Minor fixes for the still-not-enabled inspector.
2009-08-04 09:55:46 -04:00
61b28c5c7d Adjust tray spacing to cope with many icons
This patch attempts to adjust if we have many tray icons; currently
the simple algorithm is to drop down to a spacing of 8 if we have
more than 6.  In the future we should fix the panel layout so that
the clock moves to the side.
2009-08-03 20:42:00 -04:00
e84e842c1e Fix 'redeclaration of global' error in lookingGlass.js. 2009-08-04 02:36:53 +02:00
0792f8d4a3 lookingGlass: Fix spacing and line appearance 2009-08-03 20:21:07 -04:00
52ae75d4b8 LookingGlass - JavaScript prompt and interactive Clutter controller
Add a dropdown pane triggered by Alt-F2, "lg" which supports interactive
JavaScript evaluation, saving/restoring a history file, as well as
an inspector element to pick by using the mouse.
2009-08-03 20:17:08 -04:00
224538c885 Cleanups for runDialog
Using an internal boolean rather than the visibility property seems
more reliable to me.  Add a list of internal functions rather than
an if/else chain, so for example an extension could hook something on.

Delete the javascript evaluator in favor of the upcoming lookingGlass.js.
2009-08-03 20:16:15 -04:00
45dc34bfa2 Add mesa-utils to build-setup.sh for Debian/Utils
At least on Ubuntu 9.04 and Debian Squeeze, glxinfo is in the
mesa-utils package, so pull that in.

Reported by Flamarion Jorge
http://bugzilla.gnome.org/show_bug.cgi?id=590480
2009-08-03 15:14:53 -04:00
0b801a0d2d Fix the amount of fitting elements calculation in the OverflowList
Before this in certain conditions (depending on the available
height) two items could be drawn in the same position. Bug #590278.
2009-08-02 20:06:32 +02:00
d7f5fd5d24 Give the runDialog a rounded corner
Just makes things a bit nicer looking.
2009-08-01 21:46:02 -04:00
026f014d32 Bug 589937 - Raise clone on window activation
We had duplicate code in appDisplay and workspaces for handling activating
a window; unify that inside workspaces, add an API to Main.overlay to
access it from both contexts.

Also, explicitly raise the clone we're activating to the top
before starting the animation to leave the overlay.
2009-07-31 19:26:32 -04:00
a439a58f13 Remove taskpanel
The new design doesn't have the task panel at the bottom; remove it.

Signed-off-by: Colin Walters <walters@verbum.org>
2009-07-31 17:42:49 -04:00
29ffa46d08 Move drawing functions from shell-global into new shell-drawing.c file
Just to avoid shell-global.c bloat.
2009-07-31 17:26:47 -04:00
0a1aac862f Fix details pane repositioning
Two calls to _repositionDetails() were done too early,
before the visibility of the results pane had changed,
so they had no effect. Thus when a search was done while
a details pane was active, the pane with the results was
hidden by the details pane.

In addition to fixing this, move the two remaining calls to
the line after changing the results pane's visibility
to make it clearer why the calls are there.
2009-07-31 16:12:19 +02:00
f7fff83647 Fix showing small item previews
Don't use a clone of an actor that's not part of the scene graph for the
item previews. This patch fixes previews in the details pane for documents
for which we don't have full previews and for applications.

Use create_icon_texture() from AppInfo instead of looking up the file
for gicon when creating an application icon for the details pane.
2009-07-29 17:56:13 -04:00
66e48da7cb Bug 589260 - Don't replace panel in Xephyr mode
Avoid grabbing the org.gnome.Panel name if we're running in
Xephyr, since that affects the main desktop.
2009-07-29 17:47:34 -04:00
93ea4b07c1 Add appInfo.get_desktop_file_path method
Add shell_app_info_get_desktop_file_path, matching *_get_executable,
*_get_id, etc. This is useful for Zeitgeist.
2009-07-29 23:40:23 +02:00
77c92d75d5 Toggle the info pane when clicking the info icon (#587550)
Now clicking on the information icon of the same item a second
time will hide the details pane. Clicking it another time will
show it again, etc.

This is achieved by adding a 'toggle-details' signal which
switches the visibility of the details pane.

Other than the necessary changes, function _selectIndex (in
genericDisplay.js) has been restructured a bit to avoid
duplicating checks.
2009-07-29 19:35:11 +02:00
119516424d Update to using Clutter 1.0
Change the pkg-config and .gir requirements.
2009-07-29 13:00:41 -04:00
f3efbf432f Replace lastVisited method in DocInfo with timestamp attribute
This is not only more consistent with the name, uri and
mimeType attributes, but makes adding Zeitgeist support easier.
2009-07-29 10:52:33 +02:00
04538c65b5 Changed logout menu to include Log Out and Shutdown options, #583955 2009-07-27 23:28:00 -04:00
efcf8bae9d Align category labels vertically
Add a box to contain the MenuItem labels and align them vertically.

Clean up the style in the MenuItem code.
2009-07-27 19:02:46 -04:00
adfb419ceb Don't line wrap application names in wells, fix running alignment
The experiment with avoiding ellipsization was a definite failure;
several translations have very long names, and we'd end up
with a single column.

Also fix extra padding; we only want some space at the top, not
left/right.
2009-07-27 18:35:41 -04:00
09948ce033 Remove unused gdm-user-chooser-*.[ch] files
These widgets aren't currently used, delete them for now.
2009-07-27 17:23:32 -04:00
ff6ee2c0c2 DocsWidget -> RecentDocsWidget
Rename DocsWidget to RecentDocsWidget (as widgets for most used docs,
docs related to the currently open documents, etc. may be added in the
future), and change the title so that it doesn't abbreviate 'Docs' (for
consistency with the overlay).
2009-07-27 14:50:54 -04:00
96cf9c739e Avoid ellipsizing app names; Draw glow around running
Corresponding with the design, if an application is in a running
state (has > 0 windows open), draw a glow behind the name.

To make the display look a bit nicer, set the width of each item
to be equal to the longest word among all the items.
2009-07-27 12:45:22 -04:00
9f4ccb83e3 Make dash background darker
Make dash background darker so that the blue color used for indicating
running apps can be visible. Use the dark blue (almost black) color from
Jeremy's mockup.

Make the dash height be the full screen height minus the height of the panel.
Don't use padding on top or on the bottom.

Remove the border from the main dash, but leave it for the results and details
panes. Make the border slightly transparent.

Make sure the details pane is correctly positioned by not applying the
additional padding when determining its x position.
2009-07-24 17:25:20 -04:00
978ab8a4dd Return false from the timeout callback function
Timeout callback function should not be rescheduled again with the same timeout
because we compute a new timeout and schedule it again instead. So the callback
function needs to return false to not be scheduled again by default.
2009-07-24 12:58:53 -04:00
2cc650e389 Bug 589437 - Switch to workspace of target app to activate
The user explicitly selected a window, so take them to it.
2009-07-23 12:28:31 -04:00
f24169735a Fix updating last visited time for the doc display items.
Make sure that we calculate the next update time correctly.

Store timeout time instead of the timeout delta, so that it doesn't get outdated.

Create a new callback when the time update happens for the original callback.

Make sure last visited time is updated in the details pane by keeping track
of the description actors created for the detail actors.

Add comments to the new functions.
2009-07-22 18:57:05 -04:00
75c875f073 Fix time updating for recent files 2009-07-22 12:46:05 -04:00
6ea2822fa3 Merge branch 'bug589185-docinfo-time' 2009-07-22 12:11:06 -04:00
b4cf178cc5 Display last visited time as docInfo description
It's useful information, and takes up some of the blank space.
2009-07-21 23:05:08 -04:00
a7c1ff3729 Fix prototype for shell_app_monitor_get_window_app
It contained a stale definition for the old version of _id, it
now returns the app.
2009-07-21 21:27:56 -04:00
fdd9b85448 If org.gnome.Panel exists on the bus, replace it rather than using gdb
Avoid depending on gdb for replacing an existing panel, since it
requires debuginfo and gdb installed.

Instead we grab the org.gnome.Panel DBus name, using DBus name
replacement semantics.
2009-07-21 13:29:49 -04:00
e12587619b Fix reference counting of textures loaded via _load_uri_sync
Avoid double unref, fixes image previews.
2009-07-20 18:23:03 -04:00
8d9fc28872 Bug 588050 - Cache information icon forever, only look up recent once
Extend ShellTextureCache by adding the concept of a policy, which
we expose to the public API for loading URIs.

This lets us have the shell tell the cache to keep the information
icon texture around forever.

Secondly, fix the caching of recent info; we shouldn't always be
loading the backup pixbuf.  Move recent info loading entirely
into ShellTextureCache.
2009-07-17 17:35:53 -04:00
2c5d520395 Fix srcdir != builddir issue when installing schemeas
Since we aren't (currently) generating our GConf schemas by merging in
.po files, the schemas file is in sourcedir not builddir.
2009-07-17 13:14:35 -04:00
9e85d197fd Bug 588462 - Use a plain black panel with a different layout
The semi-transparent gradient on the panel is replaced by a
solid black background. The shadow below the panel is removed.
The clock is put at the center instead of the right side of
the panel and has the date removed. The user icon is hidden.
Instead of boldface, a regular font is used. Padding is added
on each side and between panel elements.

button.js: Allow for custom text colors and fonts.
panel.js: Change the panel colors and layout, remove the shadow.
2009-07-16 22:02:32 +02:00
2aea9c59a4 Bug 588173 - No remove button on the first workspace
If there is only one workspace and it's empty, it should
not get a remove button. Add a workspaceNum != 0 check to
workspaces.js.
2009-07-14 14:58:24 +02:00
001af72727 Merge branch 'bug588050-doc-textures' 2009-07-13 16:24:55 -04:00
9d594d7f26 Always clear details pane when unsetting more mode
We don't want a detail pane hanging around for an item no
longer visible.
2009-07-13 11:01:50 -04:00
2161e90cda Fixes for GenericDisplay
GenericDisplay wasn't quite completely converted to the ShellOverflowList
model.  Since the list now holds all actors, the indexing/wrapping
was incorrect.

Add a property which lets us keep track of how many items are displayed,
use this in genericDisplay.

Avoid setting selectedIndex to -2 when going up with no items.

If we're not displaying any results at all, don't attempt keynav (for now).
2009-07-13 11:01:49 -04:00
f7a82d6400 Bug 588445 - Use BigBox vertical alignment for the clock
panel.js: Replace the manual vertical padding calculation
    for the panel's clock with an y_align property on its
    BigBox container.
2009-07-13 16:16:44 +02:00
10e30f7dc7 Bug 588405 - Handle status menu button appearance in JavaScript
Make the ClutterText and ClutterTexture from the status menu
button available to JavaScript, and from there improve the
font definition of the user name.

shell-status-menu.[ch]: Add public get_name() and get_icon()
    functions that return the user name label and icon
    texture, remove the markup from update_name_text().
panel.js: Set the font for the button consistently with that
    of the other panel labels.
2009-07-13 13:54:38 +02:00
177edc5444 Bug 587955 - Small cleanups to iconButton
Missing trailing ; after "this._fadeOut()". A few missing spaces after "if". Parameter inconsistently named "icon" instead of "texture".
2009-07-11 18:44:21 +02:00
b45cd0a4eb Small fixes for sidebar application bits
We need to set the .name property, also skip unknown apps.
2009-07-10 17:04:39 -04:00
8a56b990dd Bug 587949 - Handle locale-encoded names from struct pwent
Convert to utf8 internally.
2009-07-10 10:19:17 -04:00
f353283a40 Merge up to commit 92e608bd0f3807314c45ee5f5daf6ba781c27d58 of gdm
Pull in a few fixes from gdm trunk for gdm-user.c
2009-07-10 10:19:17 -04:00
5d067ec718 Better caching for document textures and information
Move thumbnail creation into ShellTextureCache.  It's now asynchronous,
and we cache the result.

Create a DocManager class which keeps around the DocInfo objects between
invocations.  This is also where we ensure we remove thumbnails for
recent items not known anymore.
2009-07-09 13:58:45 -04:00
1cb6fc004b Add magic "js " prefix to runDialog to run arbitrary JavaScript
This is useful for debugging things; e.g. you can "js Meta.quit(0)"
to exit the WM, "js Shell.Global.get().<whatever>..." etc.
2009-07-08 17:30:09 -04:00
3b603ef7e0 Don't fail if we can't find an application
Instead of logging and passing null through, explicitly skip
apps we don't know about.  It's valid to have say uninstalled
an app.
2009-07-08 11:54:15 -04:00
0971ba54b8 Bug 587952 - Immediately fade in information button
0.5s is a pretty long time, start immediate fade in.
2009-07-08 11:41:40 -04:00
c136acc879 Remove inadvertent early return in apps search 2009-07-08 11:38:22 -04:00
cc2d3fd56d Major rework of application data structures and caching
Before, we looked up application data in several ways; the ShellAppSystem
exported just application ids (though it parsed the .desktop files internally),
and we'd create a Gio.DesktopAppInfo object (reparsing the desktop file again),
wrapping that inside a JavaScript AppInfo class, and finally the AppDisplay
would again parse the .desktop file to get the categories.

Also, to look up applications by id previously, we traversed the entire
menu structure each time.

Some qualities such as the NoDisplay flag were not easily exposed in the old
system.  And if we wanted to expose them we'd have to change several different
application information wrapper classes.

All in all, it was quite suboptimal.

The theme of this new code is basically "just use libgnome-menus".  We do
not call into Gio for app lookups anymore.  The new Shell.AppInfo class
is a disguised pointer for the GMenuTreeEntry item.

To fix the caching, we keep a simple hash table of desktop id -> ShellAppInfo.
2009-07-08 11:33:47 -04:00
72e6e7839f Reset page number when changing the active category 2009-07-07 11:59:51 +01:00
732573331a Fix DND to left side of the screen
Set the size of the Dash actor to 0x0 so that it doesn't
interfere with drag and drop.

http://bugzilla.gnome.org/show_bug.cgi?id=587899
2009-07-07 10:58:49 +01:00
00407d6971 Explicitly include gio/gio.h in ShellGlobal
Because we use GFile.
2009-07-06 23:13:58 -04:00
db630b2945 More for applications now displays a category list
Rework the previously extant Application category code to display
in the expanded list.  Add a "Frequent" category which corresponds
to the most_used_apps, and selected by default.

Instead of adding the background and shadow as expanded items to
the results/details panes as fixed, we slave the background/shadow
sizes to the results using notify::allocation.

Also clean up the code for sizing the details pane, using a common
function which adjusts its x position in one place.
2009-07-06 16:15:12 -04:00
a15ee28177 Add ShellDrawingArea and ShellStack
ShellDrawingArea is a size-independent wrapper for a ClutterCairoTexture.
Useful when drawing non-fixed size areas.

ShellStack is a simple container class which holds items
in a completely overlapping Z stack.  The main difference
from ClutterGroup is that items will be constrained to
(and allocated) the size of the stack, not getting their
preferred size always.
2009-07-06 14:11:18 -04:00
92e9bc85a1 AppWell: If an application is running, activate an existing window
Instead of relaunching, pick the first window and activate
2009-07-06 13:43:19 -04:00
70c51beeeb Add a sidebar show/hide menu item to the status menu
This is how it is in the mockups, but we may want to revisit it
2009-07-06 11:55:17 -04:00
9890887126 Add GConf schemas for sidebar prefs, and use those prefs from sidebar.js 2009-07-06 11:55:17 -04:00
203ec385c5 Add ShellGConf
Although methods like gconf_client_get/set_bool() and such are usable
from gjs, get_list/set_list is not, since there's only one method for
all list types. So ShellGConf wraps GConfClient and adds separate
typed list methods.

Also, add a detailed "changed" signal that can easily be connected to
from js, since we can't currently use gconf_client_notify_add()
directly.
2009-07-06 11:55:17 -04:00
5a0d8eca9f Fix Chrome.removeActor()
The split between this.actor and this.nonOverlayActor in chrome.js is
annoying, but aside from actually subclassing ClutterGroup (which
would have to be done from C), all of the other possibilities are
annoying too.
2009-07-06 11:55:17 -04:00
ae779c7f20 Fixes to allow widgets to be initially collapsed 2009-07-06 11:55:16 -04:00
3852176e80 Use a fading icon button in genericDisplay
Add a new icon button in button.js that fades in/out with a short delay when the mouse enters/leaves its parent. Use it for the information button of genericDisplay.
2009-07-05 10:40:50 +02:00
7a0ce6c57b ShellOverflowList: Implement pick
This gives us the correct event behavior.
2009-07-04 19:50:55 -04:00
15e862f974 Switch GenericDisplay to ShellOverflowList for dynamic height
This converts GenericDisplay to totally dynamic layout, where
we display as many items as we can, and the rest cleanly overflow
into pages.

For now, remove multi-column; to readd this, we can pack multiple
display items into a single ShellOverflowList item.
2009-07-04 15:30:12 -04:00
a1908d9db1 Add ShellOverflowList, a dynamic list with paging
This container class will be used for GenericDisplay.
2009-07-04 15:29:51 -04:00
8ee740e425 Don't include NoDisplay items, except for window identification
Searching across NoDisplay desktop items can produce weird
results to the user (including duplicates, and items that
aren't really applications at all.) So, don't include them
normally.

But continue including NoDisplay items when we look up the
desktop file for a window, since we want to catch applications
like Evince and Nautilus which are otherwise NoDisplay.

http://bugzilla.gnome.org/show_bug.cgi?id=587548
2009-07-04 15:07:10 +01:00
f44b3e0553 Hide the running-apps area when empty
It looks funny to have the "more running apps area" there as a gap
when empty and dragging to it is an unintuitive way to remove stuff
from the favorites list, in any case, so just hide the area when
empty.

http://bugzilla.gnome.org/show_bug.cgi?id=587720
2009-07-04 14:19:25 +01:00
bddcb40237 Fix expand flags for the contents of the Dash
Pack everything we don't want to expand with BigBoxPackFlags.NONE;
this fixes the More... button for the docs section ending up with
a gap underneath it.

Since the More... button for the docs now ends is right at the bottom
of the dash, add some padding to it.

http://bugzilla.gnome.org/show_bug.cgi?id=587720
2009-07-04 14:16:57 +01:00
66ea19fbfb Switch to dynamic layout for Dash
Instead of laying out the dash contents "manually" and having
the content items explicitly passed their height, just give them
a set width.
2009-07-04 13:45:27 +01:00
e9966b4aff Add partial implementation of dynamic width/height layout to TidyGrid
This is not a complete patch; it doesn't attempt to handle the homogenous
property or column major.

(Based on patch by Colin Walters <walters@verbum.org>)

http://bugzilla.gnome.org/show_bug.cgi?id=587720
2009-07-04 13:45:27 +01:00
a71ae65f8b Allow dragging a Workspace.WindowClone into favorites well
It's a natural thing to do, though in the future we may want
to split the WindowClone into js/misc/window.js or the like.
2009-07-02 05:04:33 -04:00
96a2747e0b Wire up search up/down
This is not a complete fix; the search selection will not cross
the apps/docs boundary.  But it's good enough until we have a more
final search design.
2009-07-02 01:04:40 -04:00
8ef48ca33c Animate panel appearance on startup 2009-07-02 01:04:40 -04:00
8a0cebccdc Display full application title, allow DnD from More
For now display the full application name, centered to avoid
excessive ellipsization.

Highlight on mouseover, and allow DnD from the More display.
2009-07-02 01:04:40 -04:00
5ae6239344 SuSE needs xorg-x11-proto-devel for X11 screen saver extension header
libXScrnSaver-devel was a Mandriva package, not available on SuSE.
2009-07-02 00:37:05 +02:00
aaeb980688 Add info.svg to Makefile.am 2009-07-01 13:43:27 -04:00
77c325772a fix tag name in schema 2009-07-01 10:34:24 -04:00
2eb0d20221 Make the sidebar's horizontal padding symmetric
Widgets should be horizontally centered in the sidebar. Else they look
out of place (in particular the clock and the applications widgets).
Due to little tricks with the sidebar starting out of the screen to
hide rounded corners, this implies playing with paddings. The patch
decreases the widgets padding from 4 to 2 pixels, removes additionnal
padding on the right, and adds an out-of-screen padding to the widget
box to make up for the negative horizontal position of the sidebar.
2009-07-01 09:28:03 -04:00
454ca09575 Make individual dash panes reactive instead of making the dash Group actor reactive
The width of a Group actor ends up including the width of its hidden children,
so we were getting a reactive object as wide as the details pane that was
blocking the clicks to the workspaces underneath it even when the details
pane was actually hidden.

Not making the dash Group actor reactive solves this problem. However, we
have to make individual parts of the dash reactive instead so that the clicks
are not passed to the transparent actor underneath them. That transparent
actor is used for dismissing the additional panes when the user clicks over
the workspaces area.
2009-06-30 19:45:56 -04:00
8f0bf5deae Fix double free and under-dup in ShellAppMonitor
The hash table is keeping ownership of appid, we don't need
to free it again.  However we do need to re-dup it when we
insert as a key.
2009-06-30 18:16:39 -04:00
09d9d91297 Include NoDisplay applications in application data
For now, we want to get Evince and Nautilus at least in the application
list.
2009-06-30 18:16:39 -04:00
a5e3227b64 Set GCONF_DEFAULT_SOURCE_PATH from the gnome-shell wrapper script
Needed so that a jhbuilt gnome-shell can find its schemas at runtime
2009-06-30 17:29:40 -04:00
8a790e1c38 Fix schema install 2009-06-30 17:29:20 -04:00
db52e024e8 Use a separate icon image as a drag actor instead of using the clone of the icon
Clutter no longer allows using a clone of an actor that is not a part of
the scene graph. This is what used to happen when we created a clone for
the icon of the item that was being dragged, and then closed the More panes
with the original item, removing the icon from the scene graph. This was
also when happened when the user hit Esc while dragging, which prompted the
overlay to close, removing the original icon from the scene graph.

Rename getIcon() methods to createIcon() to better reflect on the fact that
a new icon is created each time the method is called (we do use cache in
some cases).

Remove a stray log message in overlay.js

Fixes http://bugzilla.gnome.org/show_bug.cgi?id=585490
and http://bugzilla.gnome.org/show_bug.cgi?id=585489
2009-06-30 16:42:00 -04:00
79c166c38d Make workspaces accept a drop of AppDisplay.WellDisplayItem
AppDispplay.WellDisplayItem needed to be added along with the
GenericDisplay.GenericDisplayItem as a type of a drop object
that workspaces accept.
2009-06-30 16:42:00 -04:00
04fbaf4f27 Avoid duplicating most used applications in the AppDisplay cache
All used applications should be in the database from the menus
anyways.
2009-06-30 16:42:00 -04:00
b92263e80c Fix invalid function signature and a memory leak
Add the missing GParamSpec to on_n_workspaces_changed.

Also, we don't need to re-dup the appid, since it's already dup'd.
2009-06-30 16:42:00 -04:00
12f78a08cd Replace Dash application display with AppWell
The new class AppWell implements the application favorite well
in the Dash component.  The previous AppDisplay remains for use
in the More... mode now.

Delete DEFAULT_APPLICATIONS; this is now in GConf.

Rename getMostUsedApps to getTopApps since we now have the
idea of explicit favorites.

Delete some GenericDisplay-related calls from overlay related
to the seletion - we'll reimplement keyboard nav in a more
coherent way later.
2009-06-30 16:41:54 -04:00
88c9a23866 ShellAppSystem: Add favorites API and shell_app_system_lookup_basename
Add a GConf key for favorites, and API for retrieving them.

Also add shell_app_system_lookup_basename, which we use from
the app monitor to look up WM_CLASS ids.
2009-06-30 16:35:16 -04:00
94f92072c2 ShellAppMonitor now always assocates windows with desktop files
Track all windows; at the time of opening (and shell startup)
we call into ShellAppSystem to take the WM_CLASS property and
try to find an associated .desktop file.

Add mozilla-firefox to the list of our WM_CLASS workarounds.

Add shell_global_get_screen, since it's often used.
2009-06-30 16:20:24 -04:00
5ca4b41063 Use a single ItemResults class instead of AppResults and DocResults
AppResults and DocResults classes were identical with an exception of
the display class they used and the text label for the results. Merged
them into a single ItemResults class that takes these two additional
arguments.
2009-06-30 15:38:18 -04:00
45c97862e5 Move the activate and select functionality inside the callbacks
Move the activate and select functionality inside the callbacks for
'button-release-event' signals of the display item and the information
button correspondingly. This way it is more obvious that this is an
event handling code that needs to return a boolean value for whether
the signal has been fully handled by the actor.
2009-06-30 15:38:18 -04:00
3a7447dacc Use TextureCache to load the information icon
Use TextureCache to load the information icon, so that we don't create a
new ClutterTexture for information icons corresponding to each display
item.
2009-06-30 15:38:18 -04:00
dc7b2b03e1 Make sure we show the information button when a new item appears under the pointer
Update the code for checking a display item under the pointer to expect
the item itself rather than its child to be returned by stage_get_actor_at_pos().

This code is now used to display an information button when an item is
drawn under the pointer, so update the comment accordingly.
2009-06-30 15:38:18 -04:00
8b15724c2a Show and hide dash panes instead of adding and removing each time
Add results and details panes up-front, and show and hide them instead
of adding and removing them each time
2009-06-30 15:38:17 -04:00
587f04f807 Add a comment about the use of the transparent background and set its opacity to 0
Add a comment about the use of the transparent background to catch clicks
in the workspaces area when the dash panes are being displayed and dismiss
the dash panes.

Set opacity for the background to 0 instead of using a transparent background
color so that Clutter optimizes the drawing of the background actor.
2009-06-30 15:38:17 -04:00
9faf161aae Fix up horizontal gradient code and its use
Fix up the comments about the horizontal gradient code and use 8x1 texture
instead of 8x8.

Make sure the values we assign to the three-stop horizontal gradient
require the use of the three stop gradient, with the middle value not being
right between the side values.
2009-06-30 15:38:17 -04:00
3b56807e78 Display search results automatically
Display a pane with search results for both applications and documents
automatically when a search string is entered.

Allow viewing search results for the individual section when More link
for applications or documents is clicked.

Move text labels for the applications and documents sections into the
respective classes.
2009-06-30 15:38:17 -04:00
d5882c0cd3 Add back search functionality
Enable typing in the search box and display results in the results pane.
This means that the user has to open the details pane for applications
or documents to view the results for now.

Connect Enter to launch the seleted item.

Connect Escape to clear search, remove results and details panes,
or exit overlay.
2009-06-30 15:38:17 -04:00
c92268a615 Hide details panel by default
Don't show the details panel when the overlay is activated,
only when explicitly requested by clicking the info icon.
2009-06-30 15:38:17 -04:00
e1fa61cd58 Fix the height allocated to the results sections
The results sections no longer include a label on top of them, so the
height of that label needs to be subtracted when specifying the height
for the sections. This ensures that display controls are positioned
correctly on the bottom of the section.
2009-06-30 15:38:17 -04:00
98c5f35324 Select an item when information button is clicked, launch on single click
Clicking the information button for an item selects it (i.e. highlights it)
and shows details about the item.
Clicking the rest of the item area launches it.
Item does not become draggable if the dragging is started over the information
icon (i.e. if the user presses the information icon, but releases elsewhere).

Make sure we emit "activated" signal and close the overlay when an item from
one of the results displays is launched.
2009-06-30 15:38:17 -04:00
3841e8da74 Add an icon for the information link
Use an (i) icon supplied by Jeremy for the information link and display
it on hover. Make sure it is positioned nicely and the text doesn't
overlap with it.
2009-06-30 15:38:17 -04:00
e3291aa5ba Remove pop-up previews
Pop-up previews are not part of the new design and interfere with the information link.

Make sure details display for applications has the appropriate width set.
2009-06-30 15:38:17 -04:00
fab13dbb89 Make sure at most one item is selected in the overlay
Make sure at most one item is selected in the overlay and we always show
a details pane for the selected item.

Improve the positioning of the search box.

Remove a duplicate variable DASH_PAD and use DASH_SECTION_PADDING everywhere instead.
2009-06-30 15:38:17 -04:00
c0c79e59fc Split out separate AppResults, DocResults classes. Readd search as stub.
Avoid bloating the Dash class by separating out a bit more functionality.
2009-06-30 15:38:17 -04:00
90b7d9a7fa Change selected item color and make sure only one item is selected at a time
A blue selected item color fits better with the new color scheme than a green one.

Only one item should be selected across all the displays we are showing.
2009-06-30 15:38:17 -04:00
662c995515 Display a pane with item details
Display a pane with item details, such as a full image previews, when an item is single clicked.

Add a placeholder information link that shows up when an item is moused over.
2009-06-30 15:38:16 -04:00
3c54893656 Add icons from Jeremy
These icons are for the "more", "close", and "info" images in the overlay.
2009-06-30 15:38:16 -04:00
580794f3fb Display all recent documents in the results pane
Display all recent documents in the results pane, in addition to the first
few displayed in the main dash. All documents can be viewed with the help
of a paging control.
2009-06-30 15:38:16 -04:00
1154a1e8d7 Add a results pane in the overlay
Display the results pane above the workspaces. The results pane is somewhat
transparent and has a blue gradient background. The dash pane is slightly
transparent and also has a blue gradient background.

The results pane shows up when a More control is clicked. It disappears when
a Less control is clicked, an area outside of the dash area is clicked,
an item starts being dragged, or the overlay mode is exited.

Add shell_global_create_horizontal_gradient() to shell-global.[ch]
2009-06-30 15:38:16 -04:00
837683004d Remove a lot of obsolete code from old Sideshow (now Dash) 2009-06-30 15:38:16 -04:00
14bb73220b Increase priority of region-updating idle
Increase the priority of the idle for updating work area and struts
to META_PRIORITY_BEFORE_REDRAW. This prevents it from being starved
by a constantly-redrawing client.

http://bugzilla.gnome.org/show_bug.cgi?id=585500
2009-06-29 15:11:51 -04:00
f1a9ada5f0 Improve postioning of status menu
Currently we position the user status menu at the upper left of
the user status button. Then, because Mutter is inappropriately
positioning override-redirect windows it get shoved into the
workarea. Once that bug is fixed (bug 582639), we'll have to
position the menu ourselves.

This patch aligns the user status menu at the left end of
and beneath the top panel.

http://bugzilla.gnome.org/show_bug.cgi?id=586156
2009-06-29 15:11:51 -04:00
116 changed files with 16565 additions and 6394 deletions

11
.gitignore vendored
View File

@ -16,7 +16,17 @@ config.log
config.status
config
configure
data/gnome-shell.desktop
data/gnome-shell.desktop.in
intltool-extract.in
intltool-merge.in
intltool-update.in
libtool
omf.make
po/*.gmo
po/Makefile.in.in
po/POTFILES
po/stamp-it
scripts/launcher.pyc
src/*.gir
src/*.typelib
@ -29,3 +39,4 @@ src/gnome-shell
src/test-recorder
src/test-recorder.ogg
stamp-h1
xmldocs.make

View File

@ -1,4 +1,4 @@
SUBDIRS = data js src
SUBDIRS = data js src po
EXTRA_DIST = \
.project \
@ -7,7 +7,7 @@ EXTRA_DIST = \
distcheck-hook:
@echo "Checking disted javascript against files in git"
@failed=false; \
for f in `cd $(srcdir) && git-ls-files js` ; do \
for f in `cd $(srcdir) && git ls-files js` ; do \
if ! test -e $(distdir)/$$f ; then \
echo File missing from distribution: $$f ; \
failed=true ; \

20
README
View File

@ -0,0 +1,20 @@
GNOME Shell provides core user interface functions for the GNOME 3 desktop,
like switching to windows and launching applications. GNOME Shell takes
advantage of the capabilities of modern graphics hardware and introduces
innovative user interface concepts to provide a visually attractive and
easy to use experience.
For more information about GNOME Shell, including instructions on how
to build GNOME Shell from source and how to get involved with the project,
see:
http://live.gnome.org/GnomeShell
Bugs should be reported at http://bugzilla.gnome.org against the 'gnome-shell'
product.
License
=======
GNOME Shell is distributed under the terms of the GNU General Public License,
version 2 or later. See the COPYING file for details.

View File

@ -1,8 +1,22 @@
#!/bin/sh
#!/bin/bash
# Run this to generate all the initial makefiles, etc.
(cd `dirname $0`;
touch ChangeLog NEWS &&
autoreconf --install --symlink &&
autoreconf &&
./configure --enable-maintainer-mode $@
)
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
PKG_NAME="gnome-shell"
REQUIRED_AUTOMAKE_VERSION=1.10
(test -f $srcdir/configure.ac \
&& test -d $srcdir/src) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level gnome-shell directory"
exit 1
}
which gnome-autogen.sh || {
echo "You need to install gnome-common from GNOME Subversion (or from"
echo "your OS vendor's package manager)."
exit 1
}
USE_GNOME2_MACROS=1 USE_COMMON_DOC_BUILD=yes . gnome-autogen.sh

View File

@ -1,10 +1,12 @@
AC_INIT(gnome-shell, 0.0.1)
AC_INIT(gnome-shell, 2.27.3)
AC_CONFIG_AUX_DIR(config)
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip])
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip foreign])
AM_MAINTAINER_MODE
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
AC_CONFIG_HEADERS(config.h)
AC_DISABLE_STATIC
@ -20,8 +22,16 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
PKG_PROG_PKG_CONFIG(0.16)
IT_PROG_INTLTOOL(0.26)
AM_GLIB_GNU_GETTEXT
AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
AM_GCONF_SOURCE_2
# Get a value to substitute into gnome-shell.in
AM_PATH_PYTHON([2.5])
AC_SUBST(PYTHON)
# We need at least this, since gst_plugin_register_static() was added
# in 0.10.16, but nothing older than 0.10.21 has been tested.
GSTREAMER_MIN_VERSION=0.10.16
@ -33,23 +43,23 @@ if $PKG_CONFIG --exists gstreamer-0.10 '>=' $GSTREAMER_MIN_VERSION ; then
AC_MSG_RESULT(yes)
build_recorder=true
recorder_modules="gstreamer-0.10 gstreamer-base-0.10 xfixes"
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-0.9)
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0)
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
PKG_CHECK_MODULES(MUTTER_PLUGIN, gtk+-2.0 dbus-glib-1 mutter-plugins gjs-gi-1.0 xscrnsaver libgnome-menu $recorder_modules gconf-2.0 gdk-x11-2.0 clutter-x11-0.9 clutter-glx-0.9)
PKG_CHECK_MODULES(TIDY, clutter-0.9)
PKG_CHECK_MODULES(BIG, clutter-0.9 gtk+-2.0 librsvg-2.0)
# Collect more than 20 libraries for a prize!
PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-unix-2.0 gtk+-2.0 dbus-glib-1 mutter-plugins
gjs-gi-1.0 libgnome-menu $recorder_modules gconf-2.0
gdk-x11-2.0 clutter-x11-1.0 clutter-glx-1.0
gnome-desktop-2.0 >= 2.26 libstartup-notification-1.0
gobject-introspection-1.0 >= 0.6.5)
PKG_CHECK_MODULES(TIDY, clutter-1.0)
PKG_CHECK_MODULES(BIG, clutter-1.0 gtk+-2.0 librsvg-2.0)
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
PKG_CHECK_MODULES(TRAY, gtk+-2.0)
PKG_CHECK_MODULES(TASKPANEL, libwnck-1.0 dbus-glib-1)
# We require libgnomeui for generating thumbnails for recent files with GnomeThumbnailFactory.
# We'll switch to using GnomeDesktopThumbnailFactory once the branch of gnome-desktop that contains
# it becomes stable.
PKG_CHECK_MODULES(LIBGNOMEUI, libgnomeui-2.0)
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
# FIXME: metacity-plugins.pc should point directly to its .gir file
@ -80,17 +90,31 @@ AC_SUBST(GIRDIR)
TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
AC_SUBST(TYPELIBDIR)
changequote(,)dnl
if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-Wall[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wall" ;;
esac
# Stay command-line compatible with the gnome-common configure option. Here
# minimum/yes/maximum are the same, however.
AC_ARG_ENABLE(compile_warnings,
AC_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],
[Turn on compiler warnings]),,
enable_compile_warnings=error)
case " $OBJCFLAGS " in
*[\ \ ]-Wall[\ \ ]*) ;;
*) OBJCFLAGS="$OBJCFLAGS -Wall" ;;
esac
changequote(,)dnl
if test "$enable_compile_warnings" != no ; then
if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-Wall[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wall" ;;
esac
case " $CFLAGS " in
*[\ \ ]-Wmissing-prototypes[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
esac
if test "$enable_compile_warnings" = error ; then
case " $CFLAGS " in
*[\ \ ]-Werror[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -Werror" ;;
esac
fi
fi
fi
changequote([,])dnl
@ -104,4 +128,5 @@ AC_OUTPUT([
js/misc/Makefile
js/ui/Makefile
src/Makefile
po/Makefile.in
])

View File

@ -1,14 +1,40 @@
desktopdir=$(datadir)/applications
desktop_DATA = gnome-shell.desktop
# We substitute in bindir so it works as an autostart
# file when built in a non-system prefix
gnome-shell.desktop.in: gnome-shell.desktop.in.in
$(AM_V_GEN) sed -e "s|@bindir[@]|$(bindir)|" \
-e "s|@VERSION[@]|$(VERSION)|" \
$< > $@ || rm $@
# Placeholder until we add intltool
gnome-shell.desktop: gnome-shell.desktop.in
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
imagedir = $(pkgdatadir)/images
dist_image_DATA = \
add-workspace.svg \
app-well-glow.png \
back.svg \
close.svg \
close-black.svg \
info.svg \
magnifier.svg \
remove-workspace.svg
schemadir = @GCONF_SCHEMA_FILE_DIR@
schema_DATA = gnome-shell.schemas
install-data-local:
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(top_builddir)/data/$(schema_DATA)
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(schema_DATA)
EXTRA_DIST = \
EXTRA_DIST = \
gnome-shell.desktop.in.in \
$(schema_DATA)
CLEANFILES = \
gnome-shell.desktop.in \
$(desktop_DATA)

BIN
data/app-well-glow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

7
data/back.svg Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.0" id="Foreground" x="0px" y="0px" width="12" height="16" viewBox="0 0 12 16" enable-background="new 0 0 29 18" xml:space="preserve" sodipodi:version="0.32" inkscape:version="0.46+devel" sodipodi:docname="back.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata id="metadata16"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><defs id="defs14"><inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 9 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="29 : 9 : 1" inkscape:persp3d-origin="14.5 : 6 : 1" id="perspective18"/></defs><sodipodi:namedview inkscape:window-height="728" inkscape:window-width="1103" inkscape:pageshadow="2" inkscape:pageopacity="1" guidetolerance="10.0" gridtolerance="10.0" objecttolerance="10.0" borderopacity="1.0" bordercolor="#666666" pagecolor="#000000" id="base" showgrid="true" inkscape:zoom="27.260185" inkscape:cx="12.592456" inkscape:cy="8.2696842" inkscape:window-x="145" inkscape:window-y="38" inkscape:current-layer="Foreground" inkscape:snap-global="true" showguides="false"><inkscape:grid type="xygrid" id="grid2391" empspacing="5" visible="true" enabled="true" snapvisiblegridlinesonly="true"/></sodipodi:namedview>
<path style="fill: rgb(255, 255, 255); fill-opacity: 1; stroke: none;" d="M 10,2 10,14 2,8 10,2 z" id="path43"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

66
data/close-black.svg Normal file
View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Foreground"
x="0px"
y="0px"
width="16px"
height="16px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve"
sodipodi:version="0.32"
inkscape:version="0.46+devel"
sodipodi:docname="close-black.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata2399"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs2397"><linearGradient
id="linearGradient3173"><stop
style="stop-color:#c4c4c4;stop-opacity:1;"
offset="0"
id="stop3175" /><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3177" /></linearGradient><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 8 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="16 : 8 : 1"
inkscape:persp3d-origin="8 : 5.3333333 : 1"
id="perspective2401" /></defs><sodipodi:namedview
inkscape:window-height="811"
inkscape:window-width="1272"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showgrid="false"
inkscape:zoom="32.125"
inkscape:cx="8"
inkscape:cy="10.440056"
inkscape:window-x="40"
inkscape:window-y="40"
inkscape:current-layer="Foreground" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10.5,3.5l2,2L10,8l2.5,2.5l-2,2L8,10l-2.5,2.5l-2-2L6,8L3.5,5.5l2-2L8,6L10.5,3.5 z M0,8c0-4.418,3.582-8,8-8s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z"
id="path2394"
style="fill-opacity:1;fill:#000000" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

74
data/close.svg Normal file
View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Foreground"
x="0px"
y="0px"
width="16px"
height="16px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve"
sodipodi:version="0.32"
inkscape:version="0.46"
sodipodi:docname="x_circle_16.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata2399"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs2397"><linearGradient
id="linearGradient3173"><stop
style="stop-color:#c4c4c4;stop-opacity:1;"
offset="0"
id="stop3175" /><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3177" /></linearGradient><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 8 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="16 : 8 : 1"
inkscape:persp3d-origin="8 : 5.3333333 : 1"
id="perspective2401" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3173"
id="linearGradient3179"
x1="7.844358"
y1="16"
x2="7.7198443"
y2="-0.062256809"
gradientUnits="userSpaceOnUse" /></defs><sodipodi:namedview
inkscape:window-height="713"
inkscape:window-width="1197"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showgrid="false"
inkscape:zoom="32.125"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-x="40"
inkscape:window-y="40"
inkscape:current-layer="Foreground" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10.5,3.5l2,2L10,8l2.5,2.5l-2,2L8,10l-2.5,2.5l-2-2L6,8L3.5,5.5l2-2L8,6L10.5,3.5 z M0,8c0-4.418,3.582-8,8-8s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z"
id="path2394"
style="fill-opacity:1;fill:url(#linearGradient3179)" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,15 @@
[Desktop Entry]
Type=Application
_Name=GNOME Shell
_Comment=Window management and application launching
Exec=@bindir@/gnome-shell
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-shell
X-GNOME-Bugzilla-Component=general
X-GNOME-Bugzilla-Version=@VERSION@
Categories=GNOME;GTK;Utility;Core;
OnlyShowIn=GNOME;
NoDisplay=true
X-GNOME-Autostart-Phase=WindowManager
X-GNOME-Provides=panel;windowmanager;
X-GNOME-Autostart-Notify=true

View File

@ -1,6 +1,21 @@
<gconfschemafile>
<schemalist>
<schema>
<key>/schemas/desktop/gnome/shell/development_tools</key>
<applyto>/desktop/gnome/shell/development_tools</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Enable internal tools useful for developers and testers from Alt-F2</short>
<long>
Allows access to internal debugging and monitoring tools using
the Alt-F2 dialog.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/app_monitor/enable_monitoring</key>
<applyto>/desktop/gnome/shell/app_monitor/enable_monitoring</applyto>
@ -15,6 +30,64 @@
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/favorite_apps</key>
<applyto>/desktop/gnome/shell/favorite_apps</applyto>
<owner>gnome-shell</owner>
<type>list</type>
<list_type>string</list_type>
<default>[mozilla-firefox.desktop,evolution.desktop,openoffice.org-writer.desktop]</default>
<locale name="C">
<short>List of desktop file IDs for favorite applications</short>
<long>
The applications corresponding to these identifiers will be displayed in the favorites area.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/sidebar/visible</key>
<applyto>/desktop/gnome/shell/sidebar/visible</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Whether or not to display the sidebar</short>
<long>
Determines whether or not the sidebar is visible.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/sidebar/expanded</key>
<applyto>/desktop/gnome/shell/sidebar/expanded</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Whether the sidebar should be in the expanded (wide) mode</short>
<long>
Controls the expanded/collapsed state of the sidebar.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/sidebar/widgets</key>
<applyto>/desktop/gnome/shell/sidebar/widgets</applyto>
<owner>gnome-shell</owner>
<type>list</type>
<list_type>string</list_type>
<default>[imports.ui.widget.ClockWidget,imports.ui.widget.AppsWidget,imports.ui.widget.RecentDocsWidget]</default>
<locale name="C">
<short>The widgets to display in the sidebar</short>
<long>
The widgets to display in the sidebar, in order from top to bottom. Each widget "name" is actually a JavaScript expression referring to a widget constructor object.
</long>
</locale>
</schema>
</schemalist>
</gconfschemafile>

74
data/info.svg Normal file
View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Foreground"
x="0px"
y="0px"
width="16px"
height="16px"
viewBox="0 0 16 16"
enable-background="new 0 0 16 16"
xml:space="preserve"
sodipodi:version="0.32"
inkscape:version="0.46"
sodipodi:docname="info_16.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata2389"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs2387"><linearGradient
id="linearGradient3710"><stop
style="stop-color:#c4c4c4;stop-opacity:1;"
offset="0"
id="stop3712" /><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3714" /></linearGradient><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 8 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="16 : 8 : 1"
inkscape:persp3d-origin="8 : 5.3333333 : 1"
id="perspective2391" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3710"
id="linearGradient3716"
x1="7.9066148"
y1="15.937743"
x2="7.9377432"
y2="0.031128405"
gradientUnits="userSpaceOnUse" /></defs><sodipodi:namedview
inkscape:window-height="713"
inkscape:window-width="722"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showgrid="false"
inkscape:zoom="32.125"
inkscape:cx="8"
inkscape:cy="8.154146"
inkscape:window-x="20"
inkscape:window-y="20"
inkscape:current-layer="Foreground" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M7,3h2v2H7V3z M5.5,12H7V8H5.5V7H9v5h1.5v1h-5V12z M0,8c0-4.418,3.582-8,8-8 s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z"
id="path2384"
style="fill-opacity:1;fill:url(#linearGradient3716)" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

80
data/magnifier.svg Normal file
View File

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

After

Width:  |  Height:  |  Size: 2.9 KiB

53
gnome-shell.doap Normal file
View File

@ -0,0 +1,53 @@
<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:gnome="http://api.gnome.org/doap-extensions#"
xmlns="http://usefulinc.com/ns/doap#">
<name xml:lang="en">GNOME Shell</name>
<shortdesc xml:lang="en">Next generation GNOME desktop shell</shortdesc>
<!--
<homepage rdf:resource="http://live.gnome.org/GnomeShell" />
-->
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gnome-shell-list" />
<download-page rdf:resource="http://download.gnome.org/sources/gnome-shell/" />
<bug-database rdf:resource="http://bugzilla.gnome.org/browse.cgi?product=gnome-shell" />
<category rdf:resource="http://api.gnome.org/doap-extensions#desktop" />
<maintainer>
<foaf:Person>
<foaf:name>William Jon McCann</foaf:name>
<foaf:mbox rdf:resource="mailto:jmccann@redhat.com" />
<gnome:userid>mccann</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Owen Taylor</foaf:name>
<foaf:mbox rdf:resource="mailto:otaylor@redhat.com" />
<gnome:userid>otaylor</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Colin Walters</foaf:name>
<foaf:mbox rdf:resource="mailto:walters@verbum.org" />
<gnome:userid>cwalters</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>
<foaf:mbox rdf:resource="mailto:marinaz@redhat.com" />
<gnome:userid>marinaz</gnome:userid>
</foaf:Person>
</maintainer>
</Project>

View File

@ -1,5 +1,4 @@
jsmiscdir = $(pkgdatadir)/js/misc
dist_jsmisc_DATA = \
appInfo.js \
docInfo.js

View File

@ -1,135 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
// TODO - move this into GConf once we're not a plugin anymore
// but have taken over metacity
// This list is taken from GNOME Online popular applications
// http://online.gnome.org/applications
// but with nautilus removed (since it should already be running)
// and evince, totem, and gnome-file-roller removed (since they're
// usually started by opening documents, not by opening the app
// directly)
const DEFAULT_APPLICATIONS = [
'mozilla-firefox.desktop',
'gnome-terminal.desktop',
'evolution.desktop',
'gedit.desktop',
'mozilla-thunderbird.desktop',
'rhythmbox.desktop',
'epiphany.desktop',
'xchat.desktop',
'openoffice.org-1.9-writer.desktop',
'emacs.desktop',
'gnome-system-monitor.desktop',
'openoffice.org-1.9-calc.desktop',
'eclipse.desktop',
'openoffice.org-1.9-impress.desktop',
'vncviewer.desktop'
];
function AppInfo(appId) {
this._init(appId);
}
AppInfo.prototype = {
_init : function(appId) {
this.appId = appId;
this._gAppInfo = Gio.DesktopAppInfo.new(appId);
if (!this._gAppInfo)
throw new Error('Unknown appId ' + appId);
this.id = this._gAppInfo.get_id();
this.name = this._gAppInfo.get_name();
this.description = this._gAppInfo.get_description();
this.executable = this._gAppInfo.get_executable();
this._gicon = this._gAppInfo.get_icon();
},
getIcon : function(size) {
if (this._gicon)
return Shell.TextureCache.get_default().load_gicon(this._gicon, size);
else
return new Clutter.Texture({ width: size, height: size });
},
getIconPath : function(size) {
if (this._gicon) {
let iconTheme = Gtk.IconTheme.get_default();
let previewIconInfo = iconTheme.lookup_by_gicon(this._gicon, size, 0);
if (previewIconInfo)
return previewIconInfo.get_filename();
}
return null;
},
launch : function() {
this._gAppInfo.launch([], Main.createAppLaunchContext());
}
};
var _infos = {};
// getAppInfo:
// @appId: an appId
//
// Gets an #AppInfo for @appId. This is preferable to calling
// new AppInfo() directly, because it caches #AppInfos.
//
// Return value: the new or cached #AppInfo, or %null if @appId
// doesn't point to a valid .desktop file
function getAppInfo(appId) {
let info = _infos[appId];
if (info === undefined) {
try {
info = _infos[appId] = new AppInfo(appId);
} catch (e) {
info = _infos[appId] = null;
}
}
return info;
}
// getMostUsedApps:
// @count: maximum number of apps to retrieve
//
// Gets a list of #AppInfos for the @count most-frequently-used
// applications
//
// Return value: the list of #AppInfo
function getMostUsedApps(count) {
let appMonitor = Shell.AppMonitor.get_default();
// Ask for more apps than we need, since the list of recently used
// apps might contain an app we don't have a desktop file for
let apps = appMonitor.get_most_used_apps (0, Math.round(count * 1.5));
let matches = [], alreadyAdded = {};
for (let i = 0; i < apps.length && matches.length <= count; i++) {
let appId = apps[i] + ".desktop";
let appInfo = getAppInfo(appId);
if (appInfo) {
matches.push(appInfo);
alreadyAdded[appId] = true;
}
}
// Fill the list with default applications it's not full yet
for (let i = 0; i < DEFAULT_APPLICATIONS.length && matches.length <= count; i++) {
let appId = DEFAULT_APPLICATIONS[i];
if (alreadyAdded[appId])
continue;
let appInfo = getAppInfo(appId);
if (appInfo)
matches.push(appInfo);
}
return matches;
}

View File

@ -5,6 +5,8 @@ const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const Signals = imports.signals;
const Main = imports.ui.main;
const THUMBNAIL_ICON_MARGIN = 2;
@ -16,40 +18,17 @@ function DocInfo(recentInfo) {
DocInfo.prototype = {
_init : function(recentInfo) {
this._recentInfo = recentInfo;
// We actually used get_modified() instead of get_visited()
// here, as GtkRecentInfo doesn't updated get_visited()
// correctly. See http://bugzilla.gnome.org/show_bug.cgi?id=567094
this.timestamp = recentInfo.get_modified().getTime() / 1000;
this.name = recentInfo.get_display_name();
this.uri = recentInfo.get_uri();
this.mimeType = recentInfo.get_mime_type();
},
getIcon : function(size) {
let icon = new Clutter.Texture();
let iconPixbuf;
if (this.uri.match("^file://"))
iconPixbuf = Shell.get_thumbnail(this.uri, this.mimeType);
if (iconPixbuf) {
// We calculate the width and height of the texture so as
// to preserve the aspect ratio of the thumbnail. Because
// the images generated based on thumbnails don't have an
// internal padding like system icons do, we create a
// slightly smaller texture and then create a group around
// it for padding purposes
let scalingFactor = (size - THUMBNAIL_ICON_MARGIN * 2) / Math.max(iconPixbuf.get_width(), iconPixbuf.get_height());
icon.set_width(Math.ceil(iconPixbuf.get_width() * scalingFactor));
icon.set_height(Math.ceil(iconPixbuf.get_height() * scalingFactor));
Shell.clutter_texture_set_from_pixbuf(icon, iconPixbuf);
let group = new Clutter.Group({ width: size,
height: size });
group.add_actor(icon);
icon.set_position(THUMBNAIL_ICON_MARGIN, THUMBNAIL_ICON_MARGIN);
return group;
} else {
Shell.clutter_texture_set_from_pixbuf(icon, this._recentInfo.get_icon(size));
return icon;
}
createIcon : function(size) {
return Shell.TextureCache.get_default().load_recent_thumbnail(size, this._recentInfo);
},
launch : function() {
@ -63,7 +42,7 @@ DocInfo.prototype = {
if (appInfo != null) {
appInfo.launch_uris([this.uri], Main.createAppLaunchContext());
} else {
log("Failed to get default application info for mime type " + mimeType +
log("Failed to get default application info for mime type " + this.mimeType +
". Will try to use the last application that registered the document.");
let appName = this._recentInfo.last_application();
let [success, appExec, count, time] = this._recentInfo.get_application_info(appName);
@ -101,14 +80,62 @@ DocInfo.prototype = {
exists : function() {
return this._recentInfo.exists();
},
lastVisited : function() {
// We actually used get_modified() instead of get_visited()
// here, as GtkRecentInfo doesn't updated get_visited()
// correctly. See
// http://bugzilla.gnome.org/show_bug.cgi?id=567094
return this._recentInfo.get_modified();
}
};
var docManagerInstance = null;
function getDocManager() {
if (docManagerInstance == null)
docManagerInstance = new DocManager();
return docManagerInstance;
}
function DocManager() {
this._init();
}
DocManager.prototype = {
_init: function() {
this._recentManager = Gtk.RecentManager.get_default();
this._items = {};
this._recentManager.connect('changed', Lang.bind(this, function(recentManager) {
this._reload();
this.emit('changed');
}));
this._reload();
},
_reload: function() {
let docs = this._recentManager.get_items();
let newItems = {};
for (let i = 0; i < docs.length; i++) {
let recentInfo = docs[i];
if (!recentInfo.exists())
continue;
let docInfo = new DocInfo(recentInfo);
// we use GtkRecentInfo URI as an item Id
newItems[docInfo.uri] = docInfo;
}
let deleted = {};
for (var uri in this._items) {
if (!(uri in newItems))
deleted[uri] = this._items[uri];
}
/* If we'd cached any thumbnail references that no longer exist,
dump them here */
let texCache = Shell.TextureCache.get_default();
for (var uri in deleted) {
texCache.evict_recent_thumbnail(this._items[uri]);
}
this._items = newItems;
},
getItems: function() {
return this._items;
}
}
Signals.addSignalMethods(DocManager.prototype);

View File

@ -3,15 +3,19 @@ jsuidir = $(pkgdatadir)/js/ui
dist_jsui_DATA = \
altTab.js \
appDisplay.js \
appIcon.js \
button.js \
chrome.js \
dash.js \
dnd.js \
docDisplay.js \
genericDisplay.js \
link.js \
lookingGlass.js \
main.js \
overlay.js \
overview.js \
panel.js \
places.js \
runDialog.js \
sidebar.js \
tweener.js \

View File

@ -36,38 +36,34 @@ function AltTabPopup() {
AltTabPopup.prototype = {
_init : function() {
let global = Shell.Global.get();
this.actor = new Big.Box({ background_color : POPUP_BG_COLOR,
this.actor = new Big.Box({ background_color : POPUP_BG_COLOR,
corner_radius: POPUP_GRID_SPACING,
padding: POPUP_GRID_SPACING,
spacing: POPUP_GRID_SPACING,
orientation: Big.BoxOrientation.VERTICAL });
// Icon grid. It would be nice to use Tidy.Grid for the this,
// but Tidy.Grid is lame in various ways. (Eg, it seems to
// have a minimum size of 200x200.) So we create a vertical
// Big.Box containing multiple horizontal Big.Boxes.
this._grid = new Big.Box({ spacing: POPUP_GRID_SPACING,
// Icon grid. TODO: Investigate Nbtk.Grid once that lands. Currently
// just implemented using a chain of Big.Box.
this._grid = new Big.Box({ spacing: POPUP_GRID_SPACING,
orientation: Big.BoxOrientation.VERTICAL });
let gcenterbox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
x_align: Big.BoxAlignment.CENTER });
gcenterbox.append(this._grid, Big.BoxPackFlags.NONE);
this.actor.append(gcenterbox, Big.BoxPackFlags.NONE);
this.actor.append(gcenterbox, Big.BoxPackFlags.NONE);
// Selected-window label
this._label = new Clutter.Text({ font_name: "Sans 16px",
this._label = new Clutter.Text({ font_name: "Sans 16px",
ellipsize: Pango.EllipsizeMode.END });
let labelbox = new Big.Box({ background_color: POPUP_INDICATOR_COLOR,
corner_radius: POPUP_GRID_SPACING / 2,
padding: POPUP_GRID_SPACING / 2 });
labelbox.append(this._label, Big.BoxPackFlags.EXPAND);
labelbox.append(this._label, Big.BoxPackFlags.NONE);
let lcenterbox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
x_align: Big.BoxAlignment.CENTER,
width: POPUP_LABEL_MAX_WIDTH + POPUP_GRID_SPACING });
lcenterbox.append(labelbox, Big.BoxPackFlags.NONE);
this.actor.append(lcenterbox, Big.BoxPackFlags.NONE);
this.actor.append(lcenterbox, Big.BoxPackFlags.NONE);
// Indicator around selected icon
this._indicator = new Big.Rectangle({ border_width: POPUP_INDICATOR_WIDTH,
@ -76,10 +72,10 @@ AltTabPopup.prototype = {
color: POPUP_TRANSPARENT });
this.actor.append(this._indicator, Big.BoxPackFlags.FIXED);
this._items = [];
this._items = [];
this._toplevels = global.window_group.get_children();
global.stage.add_actor(this.actor);
global.stage.add_actor(this.actor);
// Dark translucent window used to cover all but the
// currently-selected window while Alt-Tabbing. Actually
@ -142,10 +138,6 @@ AltTabPopup.prototype = {
},
show : function(initialSelection) {
let global = Shell.Global.get();
Main.startModal();
global.window_group.add_actor(this._overlay);
this._overlay.raise_top();
this._overlay.show();
@ -154,18 +146,16 @@ AltTabPopup.prototype = {
time: SHOW_TIME,
transition: "easeOutQuad" });
this.actor.show_all();
this.actor.x = (global.screen_width - this.actor.width) / 2;
this.actor.y = (global.screen_height - this.actor.height) / 2;
this.actor.show_all();
this.actor.x = Math.floor((global.screen_width - this.actor.width) / 2);
this.actor.y = Math.floor((global.screen_height - this.actor.height) / 2);
this.select(initialSelection);
},
destroy : function() {
this.actor.destroy();
this.actor.destroy();
this._overlay.destroy();
Main.endModal();
},
select : function(n) {
@ -240,8 +230,6 @@ AltTabPopup.prototype = {
},
_adjust_overlay : function() {
let global = Shell.Global.get();
if (this._selected && this._selected.icon_rect) {
// We want to highlight a specific rectangle within the
// task bar, so rearrange the pieces of the overlay to

File diff suppressed because it is too large Load Diff

133
js/ui/appIcon.js Normal file
View File

@ -0,0 +1,133 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const GenericDisplay = imports.ui.genericDisplay;
const Main = imports.ui.main;
const GLOW_COLOR = new Clutter.Color();
GLOW_COLOR.from_pixel(0x4f6ba4ff);
const GLOW_PADDING_HORIZONTAL = 3;
const GLOW_PADDING_VERTICAL = 3;
const APP_ICON_SIZE = 48;
function AppIcon(appInfo) {
this._init(appInfo);
}
AppIcon.prototype = {
_init : function(appInfo) {
this.appInfo = appInfo;
this.windows = Shell.AppMonitor.get_default().get_windows_for_app(appInfo.get_id());
for (let i = 0; i < this.windows.length; i++) {
this.windows[i].connect('notify::user-time', Lang.bind(this, this._resortWindows));
}
this._resortWindows();
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
corner_radius: 2,
padding: 1,
reactive: true });
let iconBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
x_align: Big.BoxAlignment.CENTER,
y_align: Big.BoxAlignment.CENTER });
this.icon = appInfo.create_icon_texture(APP_ICON_SIZE);
iconBox.append(this.icon, Big.BoxPackFlags.NONE);
this.actor.append(iconBox, Big.BoxPackFlags.EXPAND);
this._windows = Shell.AppMonitor.get_default().get_windows_for_app(appInfo.get_id());
let nameBox = new Shell.GenericContainer();
nameBox.connect('get-preferred-width', Lang.bind(this, this._nameBoxGetPreferredWidth));
nameBox.connect('get-preferred-height', Lang.bind(this, this._nameBoxGetPreferredHeight));
nameBox.connect('allocate', Lang.bind(this, this._nameBoxAllocate));
this._nameBox = nameBox;
this._name = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
font_name: "Sans 12px",
line_alignment: Pango.Alignment.CENTER,
ellipsize: Pango.EllipsizeMode.END,
text: appInfo.get_name() });
nameBox.add_actor(this._name);
this._glowBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
let glowPath = GLib.filename_to_uri(global.imagedir + 'app-well-glow.png', '');
for (let i = 0; i < this._windows.length && i < 3; i++) {
let glow = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
glowPath, -1, -1);
glow.keep_aspect_ratio = false;
this._glowBox.append(glow, Big.BoxPackFlags.EXPAND);
}
this._nameBox.add_actor(this._glowBox);
this._glowBox.lower(this._name);
this.actor.append(nameBox, Big.BoxPackFlags.NONE);
},
_nameBoxGetPreferredWidth: function (nameBox, forHeight, alloc) {
let [min, natural] = this._name.get_preferred_width(forHeight);
alloc.min_size = min + GLOW_PADDING_HORIZONTAL * 2;
alloc.natural_size = natural + GLOW_PADDING_HORIZONTAL * 2;
},
_nameBoxGetPreferredHeight: function (nameBox, forWidth, alloc) {
let [min, natural] = this._name.get_preferred_height(forWidth);
alloc.min_size = min + GLOW_PADDING_VERTICAL * 2;
alloc.natural_size = natural + GLOW_PADDING_VERTICAL * 2;
},
_nameBoxAllocate: function (nameBox, box, flags) {
let childBox = new Clutter.ActorBox();
let [minWidth, naturalWidth] = this._name.get_preferred_width(-1);
let [minHeight, naturalHeight] = this._name.get_preferred_height(-1);
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let targetWidth = availWidth;
let xPadding = 0;
if (naturalWidth < availWidth) {
xPadding = Math.floor((availWidth - naturalWidth) / 2);
}
childBox.x1 = xPadding;
childBox.x2 = availWidth - xPadding;
childBox.y1 = GLOW_PADDING_VERTICAL;
childBox.y2 = availHeight - GLOW_PADDING_VERTICAL;
this._name.allocate(childBox, flags);
// Now the glow
if (this._glowBox != null) {
let glowPaddingHoriz = Math.max(0, xPadding - GLOW_PADDING_HORIZONTAL);
glowPaddingHoriz = Math.max(GLOW_PADDING_HORIZONTAL, glowPaddingHoriz);
childBox.x1 = glowPaddingHoriz;
childBox.x2 = availWidth - glowPaddingHoriz;
childBox.y1 = 0;
childBox.y2 = availHeight;
this._glowBox.allocate(childBox, flags);
}
},
_resortWindows: function() {
this.windows.sort(function (a, b) {
let timeA = a.get_user_time();
let timeB = b.get_user_time();
if (timeA == timeB)
return 0;
else if (timeA > timeB)
return -1;
return 1;
});
},
getDragActor: function() {
return this.appInfo.create_icon_texture(APP_ICON_SIZE);
},
getDragActorSource: function() {
return this.icon;
}
};

View File

@ -2,6 +2,11 @@
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Tweener = imports.ui.tweener;
const DEFAULT_BUTTON_COLOR = new Clutter.Color();
DEFAULT_BUTTON_COLOR.from_pixel(0xeeddcc66);
@ -9,14 +14,20 @@ DEFAULT_BUTTON_COLOR.from_pixel(0xeeddcc66);
const DEFAULT_PRESSED_BUTTON_COLOR = new Clutter.Color();
DEFAULT_PRESSED_BUTTON_COLOR.from_pixel(0xccbbaa66);
function Button(widget, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight) {
this._init(widget, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight);
const DEFAULT_TEXT_COLOR = new Clutter.Color();
DEFAULT_TEXT_COLOR.from_pixel(0x000000ff);
const DEFAULT_FONT = 'Sans Bold 16px';
// Padding on the left and right side of the button.
const SIDE_PADDING = 14;
function Button(widget, buttonColor, pressedButtonColor, textColor, font) {
this._init(widget, buttonColor, pressedButtonColor, textColor, font);
}
Button.prototype = {
_init : function(widgetOrText, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight) {
let me = this;
_init : function(widgetOrText, buttonColor, pressedButtonColor, textColor, font) {
this._buttonColor = buttonColor
if (buttonColor == null)
this._buttonColor = DEFAULT_BUTTON_COLOR;
@ -25,90 +36,138 @@ Button.prototype = {
if (pressedButtonColor == null)
this._pressedButtonColor = DEFAULT_PRESSED_BUTTON_COLOR;
this._staysPressed = staysPressed
if (staysPressed == null)
this._staysPressed = false;
this._textColor = textColor;
if (textColor == null)
this._textColor = DEFAULT_TEXT_COLOR;
if (minWidth == null)
minWidth = 0;
if (minHeight == null)
minHeight = 0;
this._font = font;
if (font == null)
this._font = DEFAULT_FONT;
// if this._staysPressed is true, this._active will be true past the first release of a button, until a subsequent one (the button
// is unpressed) or until release() is called explicitly
this._active = false;
this._isBetweenPressAndRelease = false;
this._mouseIsOverButton = false;
this.button = new Big.Box({ reactive: true,
corner_radius: 5,
padding_left: 4,
padding_right: 4,
orientation: Big.BoxOrientation.HORIZONTAL,
y_align: Big.BoxAlignment.CENTER
});
this.actor = new Shell.ButtonBox({ reactive: true,
corner_radius: 5,
padding_left: SIDE_PADDING,
padding_right: SIDE_PADDING,
orientation: Big.BoxOrientation.HORIZONTAL,
y_align: Big.BoxAlignment.CENTER
});
if (typeof widgetOrText == 'string') {
this._widget = new Clutter.Text({ font_name: "Sans Bold 16px",
this._widget = new Clutter.Text({ font_name: this._font,
color: this._textColor,
text: widgetOrText });
} else {
this._widget = widgetOrText;
}
this.button.append(this._widget, Big.BoxPackFlags.EXPAND);
this.actor.append(this._widget, Big.BoxPackFlags.EXPAND);
this._minWidth = minWidth;
this._minHeight = minHeight;
this.button.connect('button-press-event',
function(o, event) {
me._isBetweenPressAndRelease = true;
me.button.backgroundColor = me._pressedButtonColor;
return false;
});
this.button.connect('button-release-event',
function(o, event) {
me._isBetweenPressAndRelease = false;
if (!me._staysPressed || me._active) {
me.release();
} else {
me._active = true;
}
return false;
});
this.button.connect('enter-event',
function(o, event) {
me._mouseIsOverButton = true;
if (!me._active) {
me.button.backgroundColor = me._buttonColor;
}
return false;
});
this.button.connect('leave-event',
function(o, event) {
me._isBetweenPressAndRelease = false;
me._mouseIsOverButton = false;
if (!me._active) {
me.button.backgroundColor = null;
}
return false;
});
this.actor.connect('notify::hover', Lang.bind(this, this._updateColors));
this.actor.connect('notify::pressed', Lang.bind(this, this._updateColors));
this.actor.connect('notify::active', Lang.bind(this, this._updateColors));
},
pressIn : function() {
if (!this._isBetweenPressAndRelease && this._staysPressed) {
this._active = true;
this.button.backgroundColor = this._pressedButtonColor;
}
},
release : function() {
if (!this._isBetweenPressAndRelease && this._staysPressed) {
this._active = false;
if (this._mouseIsOverButton) {
this.button.backgroundColor = this._buttonColor;
} else {
this.button.backgroundColor = null;
}
}
_updateColors : function() {
if (this.actor.active || this.actor.pressed)
this.actor.backgroundColor = this._pressedButtonColor;
else if (this.actor.hover)
this.actor.backgroundColor = this._buttonColor;
else
this.actor.backgroundColor = null;
}
};
Signals.addSignalMethods(Button.prototype);
/* Delay before the icon should appear, in seconds after the pointer has entered the parent */
const ANIMATION_TIME = 0.25;
/* This is an icon button that fades in/out when mouse enters/leaves the parent.
* A delay is used before the fading starts. You can force it to be shown if needed.
*
* parent -- used to show/hide the button depending on mouse entering/leaving it
* size -- size in pixels of both the button and the icon it contains
* texture -- optional, must be used if the texture for the icon is already created (else, use setIconFromName)
*/
function iconButton(parent, size, texture) {
this._init(parent, size, texture);
}
iconButton.prototype = {
_init : function(parent, size, texture) {
this._size = size;
if (texture)
this.actor = texture;
else
this.actor = new Clutter.Texture({ width: this._size, height: this._size });
this.actor.set_reactive(true);
this.actor.set_opacity(0);
parent.connect("enter-event", Lang.bind(this, function(actor, event) {
this._shouldHide = false;
// Nothing to do if the cursor has come back from a child of the parent actor
if (actor.get_children().indexOf(event.get_related()) != -1)
return;
this._fadeIn();
}));
parent.connect("leave-event", Lang.bind(this, function(actor, event) {
// Nothing to do if the cursor has merely entered a child of the parent actor
if (actor.get_children().indexOf(event.get_related()) != -1)
return;
// Remember that we should not be visible to hide the button if forceShow is unset
if (this._forceShow) {
this._shouldHide = true;
return;
}
this._fadeOut();
}));
},
/// Private methods ///
setIconFromName : function(iconName) {
let iconTheme = Gtk.IconTheme.get_default();
let iconInfo = iconTheme.lookup_icon(iconName, this._size, 0);
if (!iconInfo)
return;
let iconPath = iconInfo.get_filename();
this.actor.set_from_file(iconPath);
},
// Useful if we want to show the button immediately,
// e.g. in case the mouse is already in the parent when the button is created
show : function() {
this.actor.set_opacity(255);
},
// If show is true, prevents the button from fading out
forceShow : function(show) {
this._forceShow = show;
// Hide the button if it should have been hidden under normal conditions
if (!this._forceShow && this._shouldHide) {
this._fadeOut();
}
},
/// Private methods ///
_fadeIn : function() {
Tweener.removeTweens(this.actor);
Tweener.addTween(this.actor, { opacity: 255,
time: ANIMATION_TIME,
transition :"easeInQuad" });
},
_fadeOut : function() {
Tweener.removeTweens(this.actor);
Tweener.addTween(this.actor, { opacity: 0,
time: ANIMATION_TIME,
transition :"easeOutQuad" });
}
};

View File

@ -9,7 +9,7 @@ const Shell = imports.gi.Shell;
const Main = imports.ui.main;
// This manages the shell "chrome"; the UI that's visible in the
// normal mode (ie, outside the overlay), that surrounds the main
// normal mode (ie, outside the Overview), that surrounds the main
// workspace content.
function Chrome() {
@ -18,13 +18,11 @@ function Chrome() {
Chrome.prototype = {
_init: function() {
let global = Shell.Global.get();
// The group itself has zero size so it doesn't interfere with DND
this.actor = new Clutter.Group({ width: 0, height: 0 });
global.stage.add_actor(this.actor);
this.nonOverlayActor = new Clutter.Group();
this.actor.add_actor(this.nonOverlayActor);
this.nonOverviewActor = new Clutter.Group();
this.actor.add_actor(this.nonOverviewActor);
this._obscuredByFullscreen = false;
@ -37,10 +35,10 @@ Chrome.prototype = {
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._queueUpdateRegions));
Main.overlay.connect('showing',
Lang.bind(this, this._overlayShowing));
Main.overlay.connect('hidden',
Lang.bind(this, this._overlayHidden));
Main.overview.connect('showing',
Lang.bind(this, this._overviewShowing));
Main.overview.connect('hidden',
Lang.bind(this, this._overviewHidden));
this._queueUpdateRegions();
},
@ -78,27 +76,27 @@ Chrome.prototype = {
else if (shapeActor && !this._verifyAncestry(shapeActor, actor))
throw new Error('shapeActor is not a descendent of actor');
this.nonOverlayActor.add_actor(actor);
this.nonOverviewActor.add_actor(actor);
if (shapeActor)
this._trackActor(shapeActor, true, true);
},
// setVisibleInOverlay:
// setVisibleInOverview:
// @actor: an actor in the chrome layer
// @visible: overlay visibility
// @visible: Overview visibility
//
// By default, actors in the chrome layer are automatically hidden
// when the overlay is shown. This can be used to override that
// when the Overview is shown. This can be used to override that
// behavior
setVisibleInOverlay: function(actor, visible) {
setVisibleInOverview: function(actor, visible) {
if (!this._verifyAncestry(actor, this.actor))
throw new Error('actor is not a descendent of the chrome layer');
if (visible)
actor.reparent(this.actor);
else
actor.reparent(this.nonOverlayActor);
actor.reparent(this.nonOverviewActor);
},
// addInputRegionActor:
@ -126,9 +124,11 @@ Chrome.prototype = {
//
// Removes @actor from the chrome layer
removeActor: function(actor) {
this.actor.remove_actor(actor);
// We don't have to do anything else; the parent-set handlers
// will do the rest.
if (actor.get_parent() == this.nonOverviewActor)
this.nonOverviewActor.remove_actor(actor);
else
this.actor.remove_actor(actor);
this._untrackActor(actor, true, true);
},
_findActor: function(actor) {
@ -170,7 +170,7 @@ Chrome.prototype = {
this._trackedActors.push(actorData);
actor = actor.get_parent();
if (actor != this.actor)
if (actor != this.actor && actor != this.nonOverviewActor)
this._trackActor(actor, false, false);
if (inputRegion || strut)
@ -198,7 +198,7 @@ Chrome.prototype = {
actor.disconnect(actorData.parentSetId);
actor = actor.get_parent();
if (actor && actor != this.actor)
if (actor && actor != this.actor && actor != this.nonOverviewActor)
this._untrackActor(actor, false, false);
}
@ -209,33 +209,33 @@ Chrome.prototype = {
_actorReparented: function(actor, oldParent) {
if (this._verifyAncestry(actor, this.actor)) {
let newParent = actor.get_parent();
if (newParent != this.actor)
if (newParent != this.actor && newParent != this.nonOverviewActor)
this._trackActor(newParent, false, false);
}
if (oldParent != this.actor)
if (oldParent != this.actor && oldParent != this.nonOverviewActor)
this._untrackActor(oldParent, false, false);
},
_overlayShowing: function() {
_overviewShowing: function() {
this.actor.show();
this.nonOverlayActor.hide();
this.nonOverviewActor.hide();
this._queueUpdateRegions();
},
_overlayHidden: function() {
_overviewHidden: function() {
if (this._obscuredByFullscreen)
this.actor.hide();
this.nonOverlayActor.show();
this.nonOverviewActor.show();
this._queueUpdateRegions();
},
_queueUpdateRegions: function() {
if (!this._updateRegionIdle)
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions));
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
Meta.PRIORITY_BEFORE_REDRAW);
},
_windowsRestacked: function() {
let global = Shell.Global.get();
let windows = global.get_windows();
// The chrome layer should be visible unless there is a window
@ -269,7 +269,7 @@ Chrome.prototype = {
break;
}
let shouldBeVisible = !this._obscuredByFullscreen || Main.overlay.visible;
let shouldBeVisible = !this._obscuredByFullscreen || Main.overview.visible;
if (this.actor.visible != shouldBeVisible) {
this.actor.visible = shouldBeVisible;
this._queueUpdateRegions();
@ -277,7 +277,6 @@ Chrome.prototype = {
},
_updateRegions: function() {
let global = Shell.Global.get();
let rects = [], struts = [], i;
delete this._updateRegionIdle;

963
js/ui/dash.js Normal file
View File

@ -0,0 +1,963 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk;
const Mainloop = imports.mainloop;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Lang = imports.lang;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const AppDisplay = imports.ui.appDisplay;
const DocDisplay = imports.ui.docDisplay;
const Places = imports.ui.places;
const GenericDisplay = imports.ui.genericDisplay;
const Button = imports.ui.button;
const Main = imports.ui.main;
const DEFAULT_PADDING = 4;
const DEFAULT_SPACING = 4;
const DASH_SECTION_PADDING = 6;
const DASH_SECTION_SPACING = 40;
const DASH_CORNER_RADIUS = 5;
const DASH_PADDING_SIDE = 14;
const BACKGROUND_COLOR = new Clutter.Color();
BACKGROUND_COLOR.from_pixel(0x000000c0);
const PRELIGHT_COLOR = new Clutter.Color();
PRELIGHT_COLOR.from_pixel(0x4f6fadaa);
const TEXT_COLOR = new Clutter.Color();
TEXT_COLOR.from_pixel(0x5f5f5fff);
const BRIGHTER_TEXT_COLOR = new Clutter.Color();
BRIGHTER_TEXT_COLOR.from_pixel(0xbbbbbbff);
const BRIGHT_TEXT_COLOR = new Clutter.Color();
BRIGHT_TEXT_COLOR.from_pixel(0xffffffff);
const SEARCH_TEXT_COLOR = new Clutter.Color();
SEARCH_TEXT_COLOR.from_pixel(0x333333ff);
const SEARCH_CURSOR_COLOR = BRIGHT_TEXT_COLOR;
const HIGHLIGHTED_SEARCH_CURSOR_COLOR = SEARCH_TEXT_COLOR;
const HIGHLIGHTED_SEARCH_BACKGROUND_COLOR = new Clutter.Color();
HIGHLIGHTED_SEARCH_BACKGROUND_COLOR.from_pixel(0xc4c4c4ff);
const SEARCH_BORDER_BOTTOM_COLOR = new Clutter.Color();
SEARCH_BORDER_BOTTOM_COLOR.from_pixel(0x191919ff);
const SECTION_BORDER_COLOR = new Clutter.Color();
SECTION_BORDER_COLOR.from_pixel(0x262626ff);
const SECTION_BORDER = 1;
const SECTION_INNER_BORDER_COLOR = new Clutter.Color();
SECTION_INNER_BORDER_COLOR.from_pixel(0x000000ff);
const SECTION_BACKGROUND_TOP_COLOR = new Clutter.Color();
SECTION_BACKGROUND_TOP_COLOR.from_pixel(0x161616ff);
const SECTION_BACKGROUND_BOTTOM_COLOR = new Clutter.Color();
SECTION_BACKGROUND_BOTTOM_COLOR.from_pixel(0x000000ff);
const SECTION_INNER_SPACING = 8;
const BROWSE_ACTIVATED_BG = new Clutter.Color();
BROWSE_ACTIVATED_BG.from_pixel(0x303030f0);
const PANE_BORDER_COLOR = new Clutter.Color();
PANE_BORDER_COLOR.from_pixel(0x101d3cfa);
const PANE_BORDER_WIDTH = 2;
const PANE_BACKGROUND_COLOR = new Clutter.Color();
PANE_BACKGROUND_COLOR.from_pixel(0x000000f4);
const APPS = "apps";
const PREFS = "prefs";
const DOCS = "docs";
/*
* Returns the index in an array of a given length that is obtained
* if the provided index is incremented by an increment and the array
* is wrapped in if necessary.
*
* index: prior index, expects 0 <= index < length
* increment: the change in index, expects abs(increment) <= length
* length: the length of the array
*/
function _getIndexWrapped(index, increment, length) {
return (index + increment + length) % length;
}
function _createDisplay(displayType) {
if (displayType == APPS)
return new AppDisplay.AppDisplay();
else if (displayType == PREFS)
return new AppDisplay.AppDisplay(true);
else if (displayType == DOCS)
return new DocDisplay.DocDisplay();
return null;
}
function Pane() {
this._init();
}
Pane.prototype = {
_init: function () {
this._open = false;
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
background_color: PANE_BACKGROUND_COLOR,
border: PANE_BORDER_WIDTH,
border_color: PANE_BORDER_COLOR,
padding: DEFAULT_PADDING,
reactive: true });
this.actor.connect('button-press-event', Lang.bind(this, function (a, e) {
// Eat button press events so they don't go through and close the pane
return true;
}));
let chromeTop = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: 6 });
let closeIconUri = "file://" + global.imagedir + "close.svg";
let closeIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
closeIconUri,
16,
16);
closeIcon.reactive = true;
closeIcon.connect('button-press-event', Lang.bind(this, function (b, e) {
this.close();
return true;
}));
chromeTop.append(closeIcon, Big.BoxPackFlags.END);
this.actor.append(chromeTop, Big.BoxPackFlags.NONE);
this.content = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: DEFAULT_PADDING });
this.actor.append(this.content, Big.BoxPackFlags.EXPAND);
// Hidden by default
this.actor.hide();
},
open: function () {
if (this._open)
return;
this._open = true;
this.actor.show();
this.emit('open-state-changed', this._open);
},
close: function () {
if (!this._open)
return;
this._open = false;
this.actor.hide();
this.emit('open-state-changed', this._open);
},
destroyContent: function() {
let children = this.content.get_children();
for (let i = 0; i < children.length; i++) {
children[i].destroy();
}
},
toggle: function () {
if (this._open)
this.close();
else
this.open();
}
}
Signals.addSignalMethods(Pane.prototype);
function ResultArea(displayType, enableNavigation) {
this._init(displayType, enableNavigation);
}
ResultArea.prototype = {
_init : function(displayType, enableNavigation) {
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
this.resultsContainer = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: DEFAULT_PADDING
});
this.actor.append(this.resultsContainer, Big.BoxPackFlags.EXPAND);
this.navContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
this.resultsContainer.append(this.navContainer, Big.BoxPackFlags.NONE);
this.display = _createDisplay(displayType);
this.navArea = this.display.getNavigationArea();
if (enableNavigation && this.navArea)
this.navContainer.append(this.navArea, Big.BoxPackFlags.EXPAND);
this.resultsContainer.append(this.display.actor, Big.BoxPackFlags.EXPAND);
this.controlBox = new Big.Box({ x_align: Big.BoxAlignment.CENTER });
this.controlBox.append(this.display.displayControl, Big.BoxPackFlags.NONE);
this.actor.append(this.controlBox, Big.BoxPackFlags.NONE);
this.display.load();
}
}
// Utility function shared between ResultPane and the DocDisplay in the main dash.
// Connects to the detail signal of the display, and on-demand creates a new
// pane.
function createPaneForDetails(dash, display) {
let detailPane = null;
display.connect('show-details', Lang.bind(this, function(display, index) {
if (detailPane == null) {
detailPane = new Pane();
detailPane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) {
if (!isOpen) {
/* Ensure we don't keep around large preview textures */
detailPane.destroyContent();
}
}));
dash._addPane(detailPane);
}
if (index >= 0) {
detailPane.destroyContent();
let details = display.createDetailsForIndex(index);
detailPane.content.append(details, Big.BoxPackFlags.EXPAND);
detailPane.open();
} else {
detailPane.close();
}
}));
return null;
}
function ResultPane(dash) {
this._init(dash);
}
ResultPane.prototype = {
__proto__: Pane.prototype,
_init: function(dash) {
Pane.prototype._init.call(this);
this._dash = dash;
},
// Create a display of displayType and pack it into this pane's
// content area. Return the display.
packResults: function(displayType, enableNavigation) {
let resultArea = new ResultArea(displayType, enableNavigation);
createPaneForDetails(this._dash, resultArea.display);
this.content.append(resultArea.actor, Big.BoxPackFlags.EXPAND);
this.connect('open-state-changed', Lang.bind(this, function(pane, isOpen) {
resultArea.display.resetState();
}));
return resultArea.display;
}
}
function SearchEntry() {
this._init();
}
SearchEntry.prototype = {
_init : function() {
this.actor = new Big.Box({ padding: DEFAULT_PADDING,
border_bottom: SECTION_BORDER,
border_color: SEARCH_BORDER_BOTTOM_COLOR,
corner_radius: DASH_CORNER_RADIUS,
reactive: true });
let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
y_align: Big.BoxAlignment.CENTER });
this.actor.append(box, Big.BoxPackFlags.EXPAND);
this.actor.connect('button-press-event', Lang.bind(this, function () {
this._resetTextState(true);
return false;
}));
this.pane = null;
this._defaultText = _("Find...");
let textProperties = { font_name: "Sans 16px" };
let entryProperties = { editable: true,
activatable: true,
single_line_mode: true,
color: SEARCH_TEXT_COLOR,
cursor_color: SEARCH_CURSOR_COLOR };
Lang.copyProperties(textProperties, entryProperties);
this.entry = new Clutter.Text(entryProperties);
this.entry.connect('notify::text', Lang.bind(this, function () {
this._resetTextState(false);
}));
box.append(this.entry, Big.BoxPackFlags.EXPAND);
// Mark as editable just to get a cursor
let defaultTextProperties = { ellipsize: Pango.EllipsizeMode.END,
text: this._defaultText,
editable: true,
color: TEXT_COLOR,
cursor_visible: false,
single_line_mode: true };
Lang.copyProperties(textProperties, defaultTextProperties);
this._defaultText = new Clutter.Text(defaultTextProperties);
box.add_actor(this._defaultText);
this.entry.connect('notify::allocation', Lang.bind(this, function () {
this._repositionDefaultText();
}));
this._iconBox = new Big.Box({ x_align: Big.BoxAlignment.CENTER,
y_align: Big.BoxAlignment.CENTER,
padding_right: 4 });
box.append(this._iconBox, Big.BoxPackFlags.END);
let magnifierUri = "file://" + global.imagedir + "magnifier.svg";
this._magnifierIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
magnifierUri, 18, 18);
let closeUri = "file://" + global.imagedir + "close-black.svg";
this._closeIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
closeUri, 18, 18);
this._closeIcon.reactive = true;
this._closeIcon.connect('button-press-event', Lang.bind(this, function () {
// Resetting this.entry.text will trigger notify::text signal which will
// result in this._resetTextState() being called, but we should not rely
// on that not short-circuiting if the text was already empty, so we call
// this._resetTextState() explicitly in that case.
if (this.entry.text == '')
this._resetTextState(false);
else
this.entry.text = '';
// Return true to stop the signal emission, so that this.actor doesn't get
// the button-press-event and re-highlight itself.
return true;
}));
this._repositionDefaultText();
this._resetTextState();
},
setPane: function (pane) {
this._pane = pane;
},
reset: function () {
this.entry.text = '';
},
getText: function () {
return this.entry.text;
},
_resetTextState: function (searchEntryClicked) {
let text = this.getText();
this._iconBox.remove_all();
// We highlight the search box if the user starts typing in it
// or just clicks in it to indicate that the search is active.
if (text != '' || searchEntryClicked) {
if (!searchEntryClicked)
this._defaultText.hide();
this._iconBox.append(this._closeIcon, Big.BoxPackFlags.NONE);
this.actor.background_color = HIGHLIGHTED_SEARCH_BACKGROUND_COLOR;
this.entry.cursor_color = HIGHLIGHTED_SEARCH_CURSOR_COLOR;
} else {
this._defaultText.show();
this._iconBox.append(this._magnifierIcon, Big.BoxPackFlags.NONE);
this.actor.background_color = BACKGROUND_COLOR;
this.entry.cursor_color = SEARCH_CURSOR_COLOR;
}
},
_repositionDefaultText: function () {
// Offset a little to show the cursor
this._defaultText.set_position(this.entry.x + 4, this.entry.y);
this._defaultText.set_size(this.entry.width, this.entry.height);
}
};
Signals.addSignalMethods(SearchEntry.prototype);
function MoreLink() {
this._init();
}
MoreLink.prototype = {
_init : function () {
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
padding_right: DEFAULT_PADDING,
padding_left: DEFAULT_PADDING,
reactive: true,
x_align: Big.BoxAlignment.CENTER,
y_align: Big.BoxAlignment.CENTER,
border_left: SECTION_BORDER,
border_color: SECTION_BORDER_COLOR });
this.pane = null;
let text = new Clutter.Text({ font_name: "Sans 12px",
color: BRIGHT_TEXT_COLOR,
text: _("Browse") });
this.actor.append(text, Big.BoxPackFlags.NONE);
this.actor.connect('button-press-event', Lang.bind(this, function (b, e) {
if (this.pane == null) {
// Ensure the pane is created; the activated handler will call setPane
this.emit('activated');
}
this._pane.toggle();
return true;
}));
},
setPane: function (pane) {
this._pane = pane;
this._pane.connect('open-state-changed', Lang.bind(this, function(pane, isOpen) {
}));
}
}
Signals.addSignalMethods(MoreLink.prototype);
function BackLink() {
this._init();
}
BackLink.prototype = {
_init : function () {
this.actor = new Shell.ButtonBox({ orientation: Big.BoxOrientation.HORIZONTAL,
padding_right: DEFAULT_PADDING,
padding_left: DEFAULT_PADDING,
reactive: true,
x_align: Big.BoxAlignment.CENTER,
y_align: Big.BoxAlignment.CENTER,
border_right: SECTION_BORDER,
border_color: SECTION_BORDER_COLOR });
let backIconUri = "file://" + global.imagedir + "back.svg";
let backIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
backIconUri,
12,
16);
this.actor.append(backIcon, Big.BoxPackFlags.NONE);
}
}
function SectionHeader(title, suppressBrowse) {
this._init(title, suppressBrowse);
}
SectionHeader.prototype = {
_init : function (title, suppressBrowse) {
this.actor = new Big.Box({ border: SECTION_BORDER,
border_color: SECTION_BORDER_COLOR });
this._innerBox = new Big.Box({ border: SECTION_BORDER,
border_color: SECTION_INNER_BORDER_COLOR,
padding_left: DEFAULT_PADDING,
padding_right: DEFAULT_PADDING,
orientation: Big.BoxOrientation.HORIZONTAL,
spacing: DEFAULT_SPACING });
this.actor.append(this._innerBox, Big.BoxPackFlags.EXPAND);
let backgroundGradient = Shell.create_vertical_gradient(SECTION_BACKGROUND_TOP_COLOR,
SECTION_BACKGROUND_BOTTOM_COLOR);
this._innerBox.add_actor(backgroundGradient);
this._innerBox.connect('notify::allocation', Lang.bind(this, function (actor) {
let [width, height] = actor.get_size();
backgroundGradient.set_size(width, height);
}));
this.backLink = new BackLink();
this._innerBox.append(this.backLink.actor, Big.BoxPackFlags.NONE);
this.backLink.actor.hide();
this.backLink.actor.connect('activate', Lang.bind(this, function (actor) {
this.emit('back-link-activated');
}));
let textBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
padding_top: DEFAULT_PADDING,
padding_bottom: DEFAULT_PADDING });
this.text = new Clutter.Text({ color: TEXT_COLOR,
font_name: "Sans Bold 12px",
text: title });
textBox.append(this.text, Big.BoxPackFlags.NONE);
this.countText = new Clutter.Text({ color: TEXT_COLOR,
font_name: 'Sans Bold 14px' });
textBox.append(this.countText, Big.BoxPackFlags.END);
this.countText.hide();
this._innerBox.append(textBox, Big.BoxPackFlags.EXPAND);
if (!suppressBrowse) {
this.moreLink = new MoreLink();
this._innerBox.append(this.moreLink.actor, Big.BoxPackFlags.END);
}
},
setTitle : function(title) {
this.text.text = title;
},
setBackLinkVisible : function(visible) {
if (visible)
this.backLink.actor.show();
else
this.backLink.actor.hide();
},
setCountText : function(countText) {
if (countText == "") {
this.countText.hide();
} else {
this.countText.show();
this.countText.text = countText;
}
}
}
Signals.addSignalMethods(SectionHeader.prototype);
function SearchSectionHeader(title, onClick) {
this._init(title, onClick);
}
SearchSectionHeader.prototype = {
_init : function(title, onClick) {
let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
padding_top: DASH_SECTION_PADDING,
padding_bottom: DASH_SECTION_PADDING,
spacing: DEFAULT_SPACING });
let titleText = new Clutter.Text({ color: BRIGHTER_TEXT_COLOR,
font_name: 'Sans Bold 12px',
text: title });
this.tooltip = new Clutter.Text({ color: BRIGHTER_TEXT_COLOR,
font_name: 'Sans 12px',
text: _("(see all)") });
this.countText = new Clutter.Text({ color: BRIGHTER_TEXT_COLOR,
font_name: 'Sans Bold 14px' });
box.append(titleText, Big.BoxPackFlags.NONE);
box.append(this.tooltip, Big.BoxPackFlags.NONE);
box.append(this.countText, Big.BoxPackFlags.END);
this.tooltip.hide();
let button = new Button.Button(box, PRELIGHT_COLOR, BACKGROUND_COLOR,
TEXT_COLOR);
button.actor.height = box.height;
button.actor.padding_left = DEFAULT_PADDING;
button.actor.padding_right = DEFAULT_PADDING;
button.actor.connect('activate', onClick);
button.actor.connect('notify::hover', Lang.bind(this, this._updateTooltip));
this.actor = button.actor;
},
_updateTooltip : function(actor) {
if (actor.hover)
this.tooltip.show();
else
this.tooltip.hide();
}
}
function Section(titleString, suppressBrowse) {
this._init(titleString, suppressBrowse);
}
Section.prototype = {
_init: function(titleString, suppressBrowse) {
this.actor = new Big.Box({ spacing: SECTION_INNER_SPACING });
this.header = new SectionHeader(titleString, suppressBrowse);
this.actor.append(this.header.actor, Big.BoxPackFlags.NONE);
this.content = new Big.Box({spacing: SECTION_INNER_SPACING });
this.actor.append(this.content, Big.BoxPackFlags.EXPAND);
}
}
function Dash() {
this._init();
}
Dash.prototype = {
_init : function() {
// dash and the popup panes need to be reactive so that the clicks in unoccupied places on them
// are not passed to the transparent background underneath them. This background is used for the workspaces area when
// the additional dash panes are being shown and it handles clicks by closing the additional panes, so that the user
// can interact with the workspaces. However, this behavior is not desirable when the click is actually over a pane.
//
// We have to make the individual panes reactive instead of making the whole dash actor reactive because the width
// of the Group actor ends up including the width of its hidden children, so we were getting a reactive object as
// wide as the details pane that was blocking the clicks to the workspaces underneath it even when the details pane
// was actually hidden.
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
background_color: BACKGROUND_COLOR,
corner_radius: DASH_CORNER_RADIUS,
padding_left: DASH_PADDING_SIDE,
padding_right: DASH_PADDING_SIDE,
reactive: true });
// Size for this one explicitly set from overlay.js
this.searchArea = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
this.sectionArea = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: DASH_SECTION_SPACING });
this.actor.append(this.searchArea, Big.BoxPackFlags.NONE);
this.actor.append(this.sectionArea, Big.BoxPackFlags.NONE);
// The currently active popup display
this._activePane = null;
/***** Search *****/
this._searchActive = false;
this._searchEntry = new SearchEntry();
this.searchArea.append(this._searchEntry.actor, Big.BoxPackFlags.EXPAND);
this._searchTimeoutId = 0;
this._searchEntry.entry.connect('text-changed', Lang.bind(this, function (se, prop) {
let text = this._searchEntry.getText();
text = text.replace(/^\s+/g, "").replace(/\s+$/g, "")
this._searchActive = text != '';
this._updateDashActors();
if (!this._searchActive) {
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._searchTimeoutId = 0;
}
return;
}
if (this._searchTimeoutId > 0)
return;
this._searchTimeoutId = Mainloop.timeout_add(150, Lang.bind(this, function() {
this._searchTimeoutId = 0;
let text = this._searchEntry.getText();
text = text.replace(/^\s+/g, "").replace(/\s+$/g, "");
let selectionSet = false;
for (var i = 0; i < this._searchSections.length; i++) {
let section = this._searchSections[i];
section.resultArea.display.setSearch(text);
let itemCount = section.resultArea.display.getMatchedItemsCount();
let itemCountText = itemCount + "";
section.header.countText.text = itemCountText;
if (this._searchResultsSingleShownSection == section.type) {
this._searchResultsSection.header.setCountText(itemCountText);
if (itemCount == 0) {
section.resultArea.actor.hide();
} else {
section.resultArea.actor.show();
}
} else if (this._searchResultsSingleShownSection == null) {
// Don't show the section if it has no results
if (itemCount == 0) {
section.header.actor.hide();
section.resultArea.actor.hide();
} else {
section.header.actor.show();
section.resultArea.actor.show();
}
}
// Refresh the selection when a new search is applied.
section.resultArea.display.unsetSelected();
if (!selectionSet && section.resultArea.display.hasItems() &&
(this._searchResultsSingleShownSection == null || this._searchResultsSingleShownSection == section.type)) {
section.resultArea.display.selectFirstItem();
selectionSet = true;
}
}
return false;
}));
}));
this._searchEntry.entry.connect('activate', Lang.bind(this, function (se) {
// Only one of the displays will have an item selected, so it's ok to
// call activateSelected() on all of them.
for (var i = 0; i < this._searchSections.length; i++) {
let section = this._searchSections[i];
section.resultArea.display.activateSelected();
}
return true;
}));
this._searchEntry.entry.connect('key-press-event', Lang.bind(this, function (se, e) {
let text = this._searchEntry.getText();
let symbol = e.get_key_symbol();
if (symbol == Clutter.Escape) {
// Escape will keep clearing things back to the desktop.
// If we are showing a particular section of search, go back to all sections.
if (this._searchResultsSingleShownSection != null)
this._showAllSearchSections();
// If we have an active search, we remove it.
else if (this._searchActive)
this._searchEntry.reset();
// Next, if we're in one of the "more" modes or showing the details pane, close them
else if (this._activePane != null)
this._activePane.close();
// Finally, just close the Overview entirely
else
Main.overview.hide();
return true;
} else if (symbol == Clutter.Up) {
if (!this._searchActive)
return true;
// selectUp and selectDown wrap around in their respective displays
// too, but there doesn't seem to be any flickering if we first select
// something in one display, but then unset the selection, and move
// it to the other display, so it's ok to do that.
for (var i = 0; i < this._searchSections.length; i++) {
let section = this._searchSections[i];
if (section.resultArea.display.hasSelected() && !section.resultArea.display.selectUp()) {
if (this._searchResultsSingleShownSection != section.type) {
// We need to move the selection to the next section above this section that has items,
// wrapping around at the bottom, if necessary.
let newSectionIndex = this._findAnotherSectionWithItems(i, -1);
if (newSectionIndex >= 0) {
this._searchSections[newSectionIndex].resultArea.display.selectLastItem();
section.resultArea.display.unsetSelected();
}
}
break;
}
}
return true;
} else if (symbol == Clutter.Down) {
if (!this._searchActive)
return true;
for (var i = 0; i < this._searchSections.length; i++) {
let section = this._searchSections[i];
if (section.resultArea.display.hasSelected() && !section.resultArea.display.selectDown()) {
if (this._searchResultsSingleShownSection != section.type) {
// We need to move the selection to the next section below this section that has items,
// wrapping around at the top, if necessary.
let newSectionIndex = this._findAnotherSectionWithItems(i, 1);
if (newSectionIndex >= 0) {
this._searchSections[newSectionIndex].resultArea.display.selectFirstItem();
section.resultArea.display.unsetSelected();
}
}
break;
}
}
return true;
}
return false;
}));
/***** Applications *****/
this._appsSection = new Section(_("APPLICATIONS"));
let appWell = new AppDisplay.AppWell();
this._appsSection.content.append(appWell.actor, Big.BoxPackFlags.EXPAND);
this._moreAppsPane = null;
this._appsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
if (this._moreAppsPane == null) {
this._moreAppsPane = new ResultPane(this);
this._moreAppsPane.packResults(APPS, true);
this._addPane(this._moreAppsPane);
link.setPane(this._moreAppsPane);
}
}));
this.sectionArea.append(this._appsSection.actor, Big.BoxPackFlags.NONE);
/***** Places *****/
/* Translators: This is in the sense of locations for documents,
network locations, etc. */
this._placesSection = new Section(_("PLACES"), true);
let placesDisplay = new Places.Places();
this._placesSection.content.append(placesDisplay.actor, Big.BoxPackFlags.EXPAND);
this.sectionArea.append(this._placesSection.actor, Big.BoxPackFlags.NONE);
/***** Documents *****/
this._docsSection = new Section(_("RECENT DOCUMENTS"));
let docDisplay = new DocDisplay.DashDocDisplay();
this._docsSection.content.append(docDisplay.actor, Big.BoxPackFlags.EXPAND);
this._moreDocsPane = null;
this._docsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
if (this._moreDocsPane == null) {
this._moreDocsPane = new ResultPane(this);
this._moreDocsPane.packResults(DOCS, true);
this._addPane(this._moreDocsPane);
link.setPane(this._moreDocsPane);
}
}));
this.sectionArea.append(this._docsSection.actor, Big.BoxPackFlags.EXPAND);
/***** Search Results *****/
this._searchResultsSection = new Section(_("SEARCH RESULTS"), true);
this._searchResultsSingleShownSection = null;
this._searchResultsSection.header.connect('back-link-activated', Lang.bind(this, function () {
this._showAllSearchSections();
}));
this._searchSections = [
{ type: APPS,
title: _("APPLICATIONS"),
header: null,
resultArea: null
},
{ type: PREFS,
title: _("PREFERENCES"),
header: null,
resultArea: null
},
{ type: DOCS,
title: _("RECENT DOCUMENTS"),
header: null,
resultArea: null
}
];
for (var i = 0; i < this._searchSections.length; i++) {
let section = this._searchSections[i];
section.header = new SearchSectionHeader(section.title,
Lang.bind(this,
function () {
this._showSingleSearchSection(section.type);
}));
this._searchResultsSection.content.append(section.header.actor, Big.BoxPackFlags.NONE);
section.resultArea = new ResultArea(section.type, false);
section.resultArea.controlBox.hide();
this._searchResultsSection.content.append(section.resultArea.actor, Big.BoxPackFlags.EXPAND);
createPaneForDetails(this, section.resultArea.display);
}
this.sectionArea.append(this._searchResultsSection.actor, Big.BoxPackFlags.EXPAND);
this._searchResultsSection.actor.hide();
},
show: function() {
global.stage.set_key_focus(this._searchEntry.entry);
},
hide: function() {
this._firstSelectAfterOverlayShow = true;
this._searchEntry.reset();
if (this._activePane != null)
this._activePane.close();
},
closePanes: function () {
if (this._activePane != null)
this._activePane.close();
},
_addPane: function(pane) {
pane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) {
if (isOpen) {
if (pane != this._activePane && this._activePane != null) {
this._activePane.close();
}
this._activePane = pane;
} else if (pane == this._activePane) {
this._activePane = null;
}
}));
Main.overview.addPane(pane);
},
_updateDashActors: function() {
if (!this._searchActive && this._searchResultsSection.actor.visible) {
this._showAllSearchSections();
this._searchResultsSection.actor.hide();
this._appsSection.actor.show();
this._placesSection.actor.show();
this._docsSection.actor.show();
} else if (this._searchActive && !this._searchResultsSection.actor.visible) {
this._searchResultsSection.actor.show();
this._appsSection.actor.hide();
this._placesSection.actor.hide();
this._docsSection.actor.hide();
}
},
_showSingleSearchSection: function(type) {
// We currently don't allow going from showing one section to showing another section.
if (this._searchResultsSingleShownSection != null) {
throw new Error("We were already showing a single search section: '" + this._searchResultsSingleShownSection
+ "' when _showSingleSearchSection() was called for '" + type + "'");
}
for (var i = 0; i < this._searchSections.length; i++) {
let section = this._searchSections[i];
if (section.type == type) {
// This will be the only section shown.
section.resultArea.display.selectFirstItem();
section.resultArea.controlBox.show();
let itemCount = section.resultArea.display.getMatchedItemsCount();
let itemCountText = itemCount + "";
section.header.actor.hide();
this._searchResultsSection.header.setTitle(section.title);
this._searchResultsSection.header.setBackLinkVisible(true);
this._searchResultsSection.header.setCountText(itemCountText);
} else {
// We need to hide this section.
section.header.actor.hide();
section.resultArea.actor.hide();
section.resultArea.display.unsetSelected();
}
}
this._searchResultsSingleShownSection = type;
},
_showAllSearchSections: function() {
if (this._searchResultsSingleShownSection != null) {
let selectionSet = false;
for (var i = 0; i < this._searchSections.length; i++) {
let section = this._searchSections[i];
if (section.type == this._searchResultsSingleShownSection) {
// This will no longer be the only section shown.
section.resultArea.display.displayPage(0);
section.resultArea.controlBox.hide();
let itemCount = section.resultArea.display.getMatchedItemsCount();
if (itemCount != 0) {
section.header.actor.show();
section.resultArea.display.selectFirstItem();
selectionSet = true;
}
this._searchResultsSection.header.setTitle(_("SEARCH RESULTS"));
this._searchResultsSection.header.setBackLinkVisible(false);
this._searchResultsSection.header.setCountText("");
} else {
// We need to restore this section.
let itemCount = section.resultArea.display.getMatchedItemsCount();
if (itemCount != 0) {
section.header.actor.show();
section.resultArea.actor.show();
// This ensures that some other section will have the selection if the
// single section that was being displayed did not have any items.
if (!selectionSet) {
section.resultArea.display.selectFirstItem();
selectionSet = true;
}
}
}
}
this._searchResultsSingleShownSection = null;
}
},
_findAnotherSectionWithItems: function(index, increment) {
let pos = _getIndexWrapped(index, increment, this._searchSections.length);
while (pos != index) {
if (this._searchSections[pos].resultArea.display.hasItems())
return pos;
pos = _getIndexWrapped(pos, increment, this._searchSections.length);
}
return -1;
}
};
Signals.addSignalMethods(Dash.prototype);

View File

@ -8,15 +8,17 @@ const Tweener = imports.ui.tweener;
const SNAP_BACK_ANIMATION_TIME = 0.25;
function _Draggable(actor) {
this._init(actor);
function _Draggable(actor, manualMode) {
this._init(actor, manualMode);
}
_Draggable.prototype = {
_init : function(actor) {
_init : function(actor, manualMode) {
this.actor = actor;
this.actor.connect('button-press-event',
Lang.bind(this, this._onButtonPress));
if (!manualMode)
this.actor.connect('button-press-event',
Lang.bind(this, this._onButtonPress));
this._haveSourceGrab = false;
},
_onButtonPress : function (actor, event) {
@ -25,6 +27,7 @@ _Draggable.prototype = {
if (Tweener.getTweenCount(actor))
return false;
this._haveSourceGrab = true;
this._grabActor(actor);
let [stageX, stageY] = event.get_coords();
@ -66,6 +69,80 @@ _Draggable.prototype = {
return false;
},
/**
* startDrag:
* @actor: Origin actor for drag and drop
* @stageX: X coordinate of event
* @stageY: Y coordinate of event
* @time: Event timestamp
*
* Directly initiate a drag and drop operation from the given actor.
* This function is useful to call if you've specified manualMode
* for the draggable.
*/
startDrag: function (actor, stageX, stageY, time) {
this.emit('drag-begin', time);
this._dragStartX = stageX;
this._dragStartY = stageY;
if (this.actor._delegate && this.actor._delegate.getDragActor) {
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
// Drag actor does not always have to be the same as actor. For example drag actor
// can be an image that's part of the actor. So to perform "snap back" correctly we need
// to know what was the drag actor source.
if (this.actor._delegate.getDragActorSource) {
this._dragActorSource = this.actor._delegate.getDragActorSource();
// If the user dragged from the source, then position
// the dragActor over it. Otherwise, center it
// around the pointer
let [sourceX, sourceY] = this._dragActorSource.get_transformed_position();
let [sourceWidth, sourceHeight] = this._dragActorSource.get_transformed_size();
let x, y;
if (stageX > sourceX && stageX <= sourceX + sourceWidth &&
stageY > sourceY && stageY <= sourceY + sourceHeight) {
x = sourceX;
y = sourceY;
} else {
x = stageX - this._dragActor.width / 2;
y = stageY - this._dragActor.height / 2;
}
this._dragActor.set_position(x, y);
} else {
this._dragActorSource = this.actor;
}
this._dragOrigParent = undefined;
if (this._haveSourceGrab) {
this._haveSourceGrab = false;
this._ungrabActor(actor);
}
this._grabActor(this._dragActor);
this._dragOffsetX = this._dragActor.x - this._dragStartX;
this._dragOffsetY = this._dragActor.y - this._dragStartY;
} else {
this._dragActor = actor;
this._dragActorSource = undefined;
this._dragOrigParent = actor.get_parent();
this._dragOrigX = this._dragActor.x;
this._dragOrigY = this._dragActor.y;
this._dragOrigScale = this._dragActor.scale_x;
let [actorStageX, actorStageY] = actor.get_transformed_position();
this._dragOffsetX = actorStageX - this._dragStartX;
this._dragOffsetY = actorStageY - this._dragStartY;
// Set the actor's scale such that it will keep the same
// transformed size when it's reparented to the stage
let [scaledWidth, scaledHeight] = actor.get_transformed_size();
actor.set_scale(scaledWidth / actor.width,
scaledHeight / actor.height);
}
this._dragActor.reparent(actor.get_stage());
this._dragActor.raise_top();
},
_onMotion : function (actor, event) {
let [stageX, stageY] = event.get_coords();
@ -75,44 +152,7 @@ _Draggable.prototype = {
if (!this._dragActor &&
(Math.abs(stageX - this._dragStartX) > threshold ||
Math.abs(stageY - this._dragStartY) > threshold)) {
this.emit('drag-begin', event.get_time());
if (this.actor._delegate && this.actor._delegate.getDragActor) {
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
// Drag actor does not always have to be the same as actor. For example drag actor
// can be an image that's part of the actor. So to perform "snap back" correctly we need
// to know what was the drag actor source.
if (this.actor._delegate.getDragActorSource)
this._dragActorSource = this.actor._delegate.getDragActorSource();
else
this._dragActorSource = this.actor;
this._dragOrigParent = undefined;
this._ungrabActor(actor);
this._grabActor(this._dragActor);
this._dragOffsetX = this._dragActor.x - this._dragStartX;
this._dragOffsetY = this._dragActor.y - this._dragStartY;
} else {
this._dragActor = actor;
this._dragActorSource = undefined;
this._dragOrigParent = actor.get_parent();
this._dragOrigX = this._dragActor.x;
this._dragOrigY = this._dragActor.y;
this._dragOrigScale = this._dragActor.scale_x;
let [actorStageX, actorStageY] = actor.get_transformed_position();
this._dragOffsetX = actorStageX - this._dragStartX;
this._dragOffsetY = actorStageY - this._dragStartY;
// Set the actor's scale such that it will keep the same
// transformed size when it's reparented to the stage
let [scaledWidth, scaledHeight] = actor.get_transformed_size();
actor.set_scale(scaledWidth / actor.width,
scaledHeight / actor.height);
}
this._dragActor.reparent(actor.get_stage());
this._dragActor.raise_top();
this.startDrag(actor, stageX, stageY, event.get_time());
}
// If we are dragging, update the position
@ -133,8 +173,8 @@ _Draggable.prototype = {
// We can check the return value of the function and break the loop if it's true if we don't want
// to continue checking the parents.
target._delegate.handleDragOver(this.actor._delegate, actor,
(stageX + this._dragOffsetX + this._xOffset - targX) / target.scale_x,
(stageY + this._dragOffsetY + this._yOffset - targY) / target.scale_y,
(stageX + this._dragOffsetX - targX) / target.scale_x,
(stageY + this._dragOffsetY - targY) / target.scale_y,
event.get_time());
}
target = target.get_parent();
@ -153,8 +193,6 @@ _Draggable.prototype = {
if (!dragging)
return false;
this.emit('drag-end', event.get_time());
// Find a drop target
actor.hide();
let [dropX, dropY] = event.get_coords();
@ -165,14 +203,15 @@ _Draggable.prototype = {
if (target._delegate && target._delegate.acceptDrop) {
let [targX, targY] = target.get_transformed_position();
if (target._delegate.acceptDrop(this.actor._delegate, actor,
(dropX + this._xOffset - targX) / target.scale_x,
(dropY + this._yOffset - targY) / target.scale_y,
(dropX - targX) / target.scale_x,
(dropY - targY) / target.scale_y,
event.get_time())) {
// If it accepted the drop without taking the actor,
// destroy it.
if (actor.get_parent() == actor.get_stage())
actor.destroy();
this.emit('drag-end', event.get_time(), true);
return true;
}
}
@ -196,23 +235,32 @@ _Draggable.prototype = {
transition: "easeOutQuad",
onComplete: this._onSnapBackComplete,
onCompleteScope: this,
onCompleteParams: [actor]
onCompleteParams: [actor, event.get_time()]
});
return true;
},
_onSnapBackComplete : function (dragActor) {
_onSnapBackComplete : function (dragActor, eventTime) {
if (this._dragOrigParent) {
dragActor.reparent(this._dragOrigParent);
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
dragActor.set_position(this._dragOrigX, this._dragOrigY);
} else
} else {
dragActor.destroy();
}
this.emit('drag-end', eventTime, false);
}
};
Signals.addSignalMethods(_Draggable.prototype);
function makeDraggable(actor) {
return new _Draggable(actor);
/**
* makeDraggable:
* @actor: Source actor
* @manualMode: If given, do not automatically start drag and drop on click
*
* Create an object which controls drag and drop for the given actor.
*/
function makeDraggable(actor, manualMode) {
return new _Draggable(actor, manualMode);
}

View File

@ -1,38 +1,59 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Mainloop = imports.mainloop;
const DocInfo = imports.misc.docInfo;
const DND = imports.ui.dnd;
const GenericDisplay = imports.ui.genericDisplay;
const Main = imports.ui.main;
const DASH_DOCS_ICON_SIZE = 16;
const DEFAULT_SPACING = 4;
/* This class represents a single display item containing information about a document.
* We take the current number of seconds in the constructor to avoid looking up the current
* time for every item when they are created in a batch.
*
* docInfo - DocInfo object containing information about the document
* availableWidth - total width available for the item
* currentSeconds - current number of seconds since the epoch
*/
function DocDisplayItem(docInfo, availableWidth) {
this._init(docInfo, availableWidth);
function DocDisplayItem(docInfo, currentSecs) {
this._init(docInfo, currentSecs);
}
DocDisplayItem.prototype = {
__proto__: GenericDisplay.GenericDisplayItem.prototype,
_init : function(docInfo, availableWidth) {
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
_init : function(docInfo, currentSecs) {
GenericDisplay.GenericDisplayItem.prototype._init.call(this);
this._docInfo = docInfo;
this._setItemInfo(docInfo.name, "",
docInfo.getIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE));
this._setItemInfo(docInfo.name, "");
this._timeoutTime = -1;
this._resetTimeDisplay(currentSecs);
},
//// Public methods ////
getUpdateTimeoutTime: function() {
return this._timeoutTime;
},
// Update any relative-time based displays for this item.
redisplay: function(currentSecs) {
this._resetTimeDisplay(currentSecs);
},
//// Public method overrides ////
// Opens a document represented by this display item.
@ -42,66 +63,95 @@ DocDisplayItem.prototype = {
//// Protected method overrides ////
// Ensures the preview icon is created.
_ensurePreviewIconCreated : function() {
if (!this._previewIcon)
this._previewIcon = this._docInfo.getIcon(GenericDisplay.PREVIEW_ICON_SIZE);
// Returns an icon for the item.
_createIcon : function() {
return this._docInfo.createIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
},
// Returns a preview icon for the item.
_createPreviewIcon : function() {
return this._docInfo.createIcon(GenericDisplay.PREVIEW_ICON_SIZE);
},
// Creates and returns a large preview icon, but only if this._docInfo is an image file
// and we were able to generate a pixbuf from it successfully.
_createLargePreviewIcon : function(availableWidth, availableHeight) {
_createLargePreviewIcon : function() {
if (this._docInfo.mimeType == null || this._docInfo.mimeType.indexOf("image/") != 0)
return null;
return Shell.TextureCache.get_default().load_uri_sync(this._docInfo.uri, availableWidth, availableHeight);
try {
return Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.NONE,
this._docInfo.uri, -1, -1);
} catch (e) {
// An exception will be raised when the image format isn't know
/* FIXME: http://bugzilla.gnome.org/show_bug.cgi?id=591480: should
* only ignore GDK_PIXBUF_ERROR_UNKNOWN_TYPE. */
return null;
}
},
//// Drag and Drop ////
shellWorkspaceLaunch: function() {
this.launch();
},
//// Private Methods ////
// Updates the last visited time displayed in the description text for the item.
_resetTimeDisplay: function(currentSecs) {
let lastSecs = this._docInfo.timestamp;
let timeDelta = currentSecs - lastSecs;
let [text, nextUpdate] = global.format_time_relative_pretty(timeDelta);
this._timeoutTime = currentSecs + nextUpdate;
this._setDescriptionText(text);
}
};
/* This class represents a display containing a collection of document items.
* The documents are sorted by how recently they were last visited.
*
* width - width available for the display
* height - height available for the display
*/
function DocDisplay(width, height, numberOfColumns, columnGap) {
this._init(width, height, numberOfColumns, columnGap);
function DocDisplay() {
this._init();
}
DocDisplay.prototype = {
__proto__: GenericDisplay.GenericDisplay.prototype,
_init : function(width, height, numberOfColumns, columnGap) {
GenericDisplay.GenericDisplay.prototype._init.call(this, width, height, numberOfColumns, columnGap);
let me = this;
this._recentManager = Gtk.RecentManager.get_default();
_init : function() {
GenericDisplay.GenericDisplay.prototype._init.call(this);
// We keep a single timeout callback for updating last visited times
// for all the items in the display. This avoids creating individual
// callbacks for each item in the display. So proper time updates
// for individual items and item details depend on the item being
// associated with one of the displays.
this._updateTimeoutTargetTime = -1;
this._updateTimeoutId = 0;
this._docManager = DocInfo.getDocManager();
this._docsStale = true;
this._recentManager.connect('changed', function(recentManager, userData) {
me._docsStale = true;
// Changes in local recent files should not happen when we are in the overlay mode,
this._docManager.connect('changed', Lang.bind(this, function(mgr, userData) {
this._docsStale = true;
// Changes in local recent files should not happen when we are in the Overview mode,
// but redisplaying right away is cool when we use Zephyr.
// Also, we might be displaying remote documents, like Google Docs, in the future
// which might be edited by someone else.
me._redisplay(false);
});
this._redisplay(false);
}));
this.connect('destroy', Lang.bind(this, function (o) {
if (this._updateTimeoutId > 0)
Mainloop.source_remove(this._updateTimeoutId);
}));
},
//// Protected method overrides ////
// Gets the list of recent items from the recent items manager.
_refreshCache : function() {
let me = this;
if (!this._docsStale)
return;
this._allItems = {};
let docs = this._recentManager.get_items();
for (let i = 0; i < docs.length; i++) {
let recentInfo = docs[i];
let docInfo = new DocInfo.DocInfo(recentInfo);
// we use GtkRecentInfo URI as an item Id
this._allItems[docInfo.uri] = docInfo;
}
this._allItems = this._docManager.getItems();
this._docsStale = false;
},
@ -116,7 +166,7 @@ DocDisplay.prototype = {
// we should do the sorting manually because we want the order to be based on last visited.
//
// This function is called each time the search string is set back to '' or we display
// the overlay, so we are doing the sorting over the same items multiple times if the list
// the Overview, so we are doing the sorting over the same items multiple times if the list
// of recent items didn't change. We could store an additional array of doc ids and sort
// them once when they are returned by this._recentManager.get_items() to avoid having to do
// this sorting each time, but the sorting seems to be very fast anyway, so there is no need
@ -145,7 +195,7 @@ DocDisplay.prototype = {
let docA = this._allItems[itemIdA];
let docB = this._allItems[itemIdB];
return docB.lastVisited() - docA.lastVisited();
return docB.timestamp - docA.timestamp;
},
// Checks if the item info can be a match for the search string by checking
@ -168,8 +218,219 @@ DocDisplay.prototype = {
// Creates a DocDisplayItem based on itemInfo, which is expected to be a DocInfo object.
_createDisplayItem: function(itemInfo) {
return new DocDisplayItem(itemInfo, this._columnWidth);
let currentSecs = new Date().getTime() / 1000;
let docDisplayItem = new DocDisplayItem(itemInfo, currentSecs);
this._updateTimeoutCallback(docDisplayItem, currentSecs);
return docDisplayItem;
},
//// Private Methods ////
// A callback function that redisplays the items, updating their descriptions,
// and sets up a new timeout callback.
_docTimeout: function () {
let currentSecs = new Date().getTime() / 1000;
this._updateTimeoutId = 0;
this._updateTimeoutTargetTime = -1;
for (let docId in this._displayedItems) {
let docDisplayItem = this._displayedItems[docId];
docDisplayItem.redisplay(currentSecs);
this._updateTimeoutCallback(docDisplayItem, currentSecs);
}
return false;
},
// Updates the timeout callback if the timeout time for the docDisplayItem
// is earlier than the target time for the current timeout callback.
_updateTimeoutCallback: function (docDisplayItem, currentSecs) {
let timeoutTime = docDisplayItem.getUpdateTimeoutTime();
if (this._updateTimeoutTargetTime < 0 || timeoutTime < this._updateTimeoutTargetTime) {
if (this._updateTimeoutId > 0)
Mainloop.source_remove(this._updateTimeoutId);
this._updateTimeoutId = Mainloop.timeout_add_seconds(timeoutTime - currentSecs, Lang.bind(this, this._docTimeout));
this._updateTimeoutTargetTime = timeoutTime;
}
}
};
Signals.addSignalMethods(DocDisplay.prototype);
function DashDocDisplayItem(docInfo) {
this._init(docInfo);
}
DashDocDisplayItem.prototype = {
_init: function(docInfo) {
this._info = docInfo;
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: DEFAULT_SPACING,
reactive: true });
this.actor.connect('button-release-event', Lang.bind(this, function () {
docInfo.launch();
Main.overview.hide();
}));
this._icon = docInfo.createIcon(DASH_DOCS_ICON_SIZE);
let iconBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
iconBox.append(this._icon, Big.BoxPackFlags.NONE);
this.actor.append(iconBox, Big.BoxPackFlags.NONE);
let name = new Clutter.Text({ font_name: "Sans 14px",
color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
ellipsize: Pango.EllipsizeMode.END,
text: docInfo.name });
this.actor.append(name, Big.BoxPackFlags.EXPAND);
let draggable = DND.makeDraggable(this.actor);
this.actor._delegate = this;
},
getDragActorSource: function() {
return this._icon;
},
getDragActor: function(stageX, stageY) {
this.dragActor = this._info.createIcon(DASH_DOCS_ICON_SIZE);
return this.dragActor;
},
//// Drag and drop functions ////
shellWorkspaceLaunch: function () {
this._info.launch();
}
}
/**
* Class used to display two column recent documents in the dash
*/
function DashDocDisplay() {
this._init();
}
DashDocDisplay.prototype = {
_init: function() {
this.actor = new Shell.GenericContainer();
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate', Lang.bind(this, this._allocate));
this._docManager = DocInfo.getDocManager();
this._docManager.connect('changed', Lang.bind(this, function(mgr) {
this._redisplay();
}));
this._redisplay();
},
_getPreferredWidth: function(actor, forHeight, alloc) {
let children = actor.get_children();
// We use two columns maximum. Just take the min and natural size of the
// first two items, even though strictly speaking it's not correct; we'd
// need to calculate how many items we could fit for the height, then
// take the biggest preferred width for each column.
// In practice the dash gets a fixed width anyways.
// If we have one child, add its minimum and natural size
if (children.length > 0) {
let [minSize, naturalSize] = children[0].get_preferred_width(forHeight);
alloc.min_size += minSize;
alloc.natural_size += naturalSize;
}
// If we have two, add its size, plus DEFAULT_SPACING
if (children.length > 1) {
let [minSize, naturalSize] = children[1].get_preferred_width(forHeight);
alloc.min_size += DEFAULT_SPACING + minSize;
alloc.natural_size += DEFAULT_SPACING + naturalSize;
}
},
_getPreferredHeight: function(actor, forWidth, alloc) {
let children = actor.get_children();
// Two columns, where we go vertically down first. So just take
// the height of half of the children as our preferred height.
let firstColumnChildren = children.length / 2;
alloc.min_size = 0;
for (let i = 0; i < firstColumnChildren; i++) {
let child = children[i];
let [minSize, naturalSize] = child.get_preferred_height(forWidth);
alloc.natural_size += naturalSize;
if (i > 0 && i < children.length - 1) {
alloc.min_size += DEFAULT_SPACING;
alloc.natural_size += DEFAULT_SPACING;
}
}
},
_allocate: function(actor, box, flags) {
let width = box.x2 - box.x1;
let height = box.y2 - box.y1;
let children = actor.get_children();
// The width of an item is our allocated width, minus spacing, divided in half.
let itemWidth = Math.floor((width - DEFAULT_SPACING) / 2);
let x = box.x1;
let y = box.y1;
let columnIndex = 0;
let i = 0;
// Loop over the children, going vertically down first. When we run
// out of vertical space (our y variable is bigger than box.y2), switch
// to the second column.
for (; i < children.length; i++) {
let child = children[i];
let [minSize, naturalSize] = child.get_preferred_height(-1);
if (y + naturalSize > box.y2) {
// Is this the second column? Ok, break.
if (columnIndex == 1) {
break;
}
// Set x to the halfway point.
columnIndex += 1;
x = x + itemWidth + DEFAULT_SPACING;
// And y is back to the top.
y = box.y1;
}
let childBox = new Clutter.ActorBox();
childBox.x1 = x;
childBox.y1 = y;
childBox.x2 = childBox.x1 + itemWidth;
childBox.y2 = y + naturalSize;
y = childBox.y2 + DEFAULT_SPACING;
child.show();
child.allocate(childBox, flags);
}
// Everything else didn't fit, just hide it.
for (; i < children.length; i++) {
children[i].hide();
}
},
_redisplay: function() {
this.actor.remove_all();
let docs = this._docManager.getItems();
let docUrls = [];
for (let url in docs) {
docUrls.push(url);
}
docUrls.sort(function (urlA, urlB) { return docs[urlB].timestamp - docs[urlA].timestamp; });
let textureCache = Shell.TextureCache.get_default();
for (let i = 0; i < docUrls.length; i++) {
let url = docUrls[i];
let docInfo = docs[url];
let display = new DashDocDisplayItem(docInfo);
this.actor.add_actor(display.actor);
}
}
}

File diff suppressed because it is too large Load Diff

579
js/ui/lookingGlass.js Normal file
View File

@ -0,0 +1,579 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
const LG_BORDER_COLOR = new Clutter.Color();
LG_BORDER_COLOR.from_pixel(0x0000aca0);
const LG_BACKGROUND_COLOR = new Clutter.Color();
LG_BACKGROUND_COLOR.from_pixel(0x000000d5);
const GREY = new Clutter.Color();
GREY.from_pixel(0xAFAFAFFF);
const MATRIX_GREEN = new Clutter.Color();
MATRIX_GREEN.from_pixel(0x88ff66ff);
// FIXME pull from GConf
const MATRIX_FONT = 'Monospace 10';
/* Imports...feel free to add here as needed */
var commandHeader = "const Clutter = imports.gi.Clutter; " +
"const GLib = imports.gi.GLib; " +
"const Gtk = imports.gi.Gtk; " +
"const Mainloop = imports.mainloop; " +
"const Meta = imports.gi.Meta; " +
"const Shell = imports.gi.Shell; " +
"const Main = imports.ui.main; " +
"const Lang = imports.lang; " +
"const Tweener = imports.ui.tweener; " +
/* Utility functions...we should probably be able to use these
* in the shell core code too. */
"const stage = global.stage; " +
"const color = function(pixel) { let c= new Clutter.Color(); c.from_pixel(pixel); return c; }; " +
/* Special lookingGlass functions */
"const it = Main.lookingGlass.getIt(); " +
"const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ";
function Notebook() {
this._init();
}
Notebook.prototype = {
_init: function() {
this.actor = new Big.Box();
this.tabControls = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: 4, padding: 2 });
this._selectedIndex = -1;
this._tabs = [];
},
appendPage: function(name, child) {
let labelOuterBox = new Big.Box({ padding: 2 });
let labelBox = new Big.Box({ padding: 2, border_color: MATRIX_GREEN,
reactive: true });
labelOuterBox.append(labelBox, Big.BoxPackFlags.NONE);
let label = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
text: name });
labelBox.connect('button-press-event', Lang.bind(this, function () {
this.selectChild(child);
return true;
}));
labelBox.append(label, Big.BoxPackFlags.EXPAND);
this._tabs.push([child, labelBox]);
child.hide();
this.actor.append(child, Big.BoxPackFlags.EXPAND);
this.tabControls.append(labelOuterBox, Big.BoxPackFlags.NONE);
if (this._selectedIndex == -1)
this.selectIndex(0);
},
_unselect: function() {
if (this._selectedIndex < 0)
return;
let [child, labelBox] = this._tabs[this._selectedIndex];
labelBox.padding = 2;
labelBox.border = 0;
child.hide();
this._selectedIndex = -1;
},
selectIndex: function(index) {
if (index == this._selectedIndex)
return;
this._unselect();
if (index < 0) {
this.emit('selection', null);
return;
}
let [child, labelBox] = this._tabs[index];
labelBox.padding = 1;
labelBox.border = 1;
child.show();
this._selectedIndex = index;
this.emit('selection', child);
},
selectChild: function(child) {
if (child == null)
this.selectIndex(-1);
else {
for (let i = 0; i < this._tabs.length; i++) {
let [tabChild, labelBox] = this._tabs[i];
if (tabChild == child) {
this.selectIndex(i);
return;
}
}
}
}
}
Signals.addSignalMethods(Notebook.prototype);
function Result(command, o, index) {
this._init(command, o, index);
}
Result.prototype = {
_init : function(command, o, index) {
this.index = index;
this.o = o;
this.actor = new Big.Box();
let cmdTxt = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
ellipsize: Pango.EllipsizeMode.END,
text: command });
this.actor.append(cmdTxt, Big.BoxPackFlags.NONE);
let resultTxt = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
ellipsize: Pango.EllipsizeMode.END,
text: "r(" + index + ") = " + o });
this.actor.append(resultTxt, Big.BoxPackFlags.NONE);
let line = new Big.Box({ border_color: GREY,
border_bottom: 1,
height: 8 });
this.actor.append(line, Big.BoxPackFlags.NONE);
}
}
function ActorHierarchy() {
this._init();
}
ActorHierarchy.prototype = {
_init : function () {
this._previousTarget = null;
this._target = null;
this._parentList = [];
this.actor = new Big.Box({ spacing: 4,
border: 1,
padding: 4,
border_color: GREY });
},
setTarget: function(actor) {
this._previousTarget = this._target;
this.target = actor;
this.actor.remove_all();
if (!(actor instanceof Clutter.Actor))
return;
if (this.target == null)
return;
this._parentList = [];
let parent = actor;
while ((parent = parent.get_parent()) != null) {
this._parentList.push(parent);
let link = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
reactive: true,
text: "" + parent });
this.actor.append(link, Big.BoxPackFlags.IF_FITS);
let parentTarget = parent;
link.connect('button-press-event', Lang.bind(this, function () {
this._selectByActor(parentTarget);
return true;
}));
}
this.emit('selection', actor);
},
_selectByActor: function(actor) {
let idx = this._parentList.indexOf(actor);
let children = this.actor.get_children();
let link = children[idx];
this.emit('selection', actor);
}
}
Signals.addSignalMethods(ActorHierarchy.prototype);
function PropertyInspector() {
this._init();
}
PropertyInspector.prototype = {
_init : function () {
this._target = null;
this._parentList = [];
this.actor = new Big.Box({ spacing: 4,
border: 1,
padding: 4,
border_color: GREY });
},
setTarget: function(actor) {
this.target = actor;
this.actor.remove_all();
for (let propName in actor) {
let valueStr;
try {
valueStr = "" + actor[propName];
} catch (e) {
valueStr = '<error>';
}
let propText = propName + ": " + valueStr;
let propDisplay = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
reactive: true,
text: propText });
this.actor.append(propDisplay, Big.BoxPackFlags.IF_FITS);
}
}
}
function Inspector() {
this._init();
}
Inspector.prototype = {
_init: function() {
let width = 150;
let eventHandler = new Big.Box({ background_color: LG_BACKGROUND_COLOR,
border: 1,
border_color: LG_BORDER_COLOR,
corner_radius: 4,
y: global.stage.height/2,
reactive: true
});
eventHandler.connect('notify::allocation', Lang.bind(this, function () {
eventHandler.x = Math.floor((global.stage.width)/2 - (eventHandler.width)/2);
}));
global.stage.add_actor(eventHandler);
let displayText = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT, text: '' });
eventHandler.append(displayText, Big.BoxPackFlags.EXPAND);
let borderPaintTarget = null;
let borderPaintId = null;
eventHandler.connect('destroy', Lang.bind(this, function() {
if (borderPaintTarget != null)
borderPaintTarget.disconnect(borderPaintId);
}));
eventHandler.connect('button-press-event', Lang.bind(this, function (actor, event) {
Clutter.ungrab_pointer(eventHandler);
let [stageX, stageY] = event.get_coords();
let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
stageX,
stageY);
this.emit('target', target, stageX, stageY);
eventHandler.destroy();
this.emit('closed');
return true;
}));
eventHandler.connect('motion-event', Lang.bind(this, function (actor, event) {
let [stageX, stageY] = event.get_coords();
let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
stageX,
stageY);
displayText.text = '<inspect x: ' + stageX + ' y: ' + stageY + '> ' + target;
if (borderPaintTarget != null)
borderPaintTarget.disconnect(borderPaintId);
borderPaintTarget = target;
borderPaintId = Shell.add_hook_paint_red_border(target);
return true;
}));
Clutter.grab_pointer(eventHandler);
}
}
Signals.addSignalMethods(Inspector.prototype);
function LookingGlass() {
this._init();
}
LookingGlass.prototype = {
_init : function() {
this._idleHistorySaveId = 0;
let historyPath = global.configdir + "/lookingglass-history.txt";
this._historyFile = Gio.file_new_for_path(historyPath);
this._savedText = null;
this._historyNavIndex = -1;
this._history = [];
this._readHistory();
this._open = false;
this._offset = 0;
this._results = [];
// TODO replace with scrolling or something better
this._maxItems = 10;
this.actor = new Big.Box({ background_color: LG_BACKGROUND_COLOR,
border: 1,
border_color: LG_BORDER_COLOR,
corner_radius: 4,
padding_top: 8,
padding_left: 4,
padding_right: 4,
padding_bottom: 4,
spacing: 4,
visible: false
});
global.stage.add_actor(this.actor);
let toolbar = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
border: 1, border_color: GREY,
corner_radius: 4 });
this.actor.append(toolbar, Big.BoxPackFlags.NONE);
let inspectIcon = Shell.TextureCache.get_default().load_gicon(new Gio.ThemedIcon({ name: 'gtk-color-picker' }),
24);
toolbar.append(inspectIcon, Big.BoxPackFlags.NONE);
inspectIcon.reactive = true;
inspectIcon.connect('button-press-event', Lang.bind(this, function () {
let inspector = new Inspector();
inspector.connect('target', Lang.bind(this, function(i, target, stageX, stageY) {
this._pushResult('<inspect x:' + stageX + ' y:' + stageY + '>',
target);
this._hierarchy.setTarget(target);
}));
inspector.connect('closed', Lang.bind(this, function() {
this.actor.show();
global.stage.set_key_focus(this._entry);
}));
this.actor.hide();
return true;
}));
let notebook = new Notebook();
this.actor.append(notebook.actor, Big.BoxPackFlags.EXPAND);
toolbar.append(notebook.tabControls, Big.BoxPackFlags.END);
this._evalBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: 4 });
notebook.appendPage('Evaluator', this._evalBox);
this._resultsArea = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: 4 });
this._evalBox.append(this._resultsArea, Big.BoxPackFlags.EXPAND);
let entryArea = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
this._evalBox.append(entryArea, Big.BoxPackFlags.NONE);
let label = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
text: 'js>>> ' });
entryArea.append(label, Big.BoxPackFlags.NONE);
this._entry = new Clutter.Text({ color: MATRIX_GREEN,
font_name: MATRIX_FONT,
editable: true,
activatable: true,
singleLineMode: true,
text: ''});
/* unmapping the edit box will un-focus it, undo that */
notebook.connect('selection', Lang.bind(this, function (nb, child) {
if (child == this._evalBox)
global.stage.set_key_focus(this._entry);
}));
entryArea.append(this._entry, Big.BoxPackFlags.EXPAND);
this._hierarchy = new ActorHierarchy();
notebook.appendPage('Hierarchy', this._hierarchy.actor);
this._propInspector = new PropertyInspector();
notebook.appendPage('Properties', this._propInspector.actor);
this._hierarchy.connect('selection', Lang.bind(this, function (h, actor) {
this._pushResult('<parent selection>', actor);
notebook.selectIndex(0);
}));
this._entry.connect('activate', Lang.bind(this, function (o, e) {
let text = o.get_text();
// Ensure we don't get newlines in the command; the history file is
// newline-separated.
text.replace('\n', ' ');
// Strip leading and trailing whitespace
text = text.replace(/^\s+/g, "").replace(/\s+$/g, "");
if (text == '')
return true;
this._evaluate(text);
this._historyNavIndex = -1;
return true;
}));
this._entry.connect('key-press-event', Lang.bind(this, function(o, e) {
let symbol = e.get_key_symbol();
if (symbol == Clutter.Escape) {
this.close();
return true;
} else if (symbol == Clutter.Up) {
if (this._historyNavIndex >= this._history.length - 1)
return true;
this._historyNavIndex++;
if (this._historyNavIndex == 0)
this._savedText = this._entry.text;
this._entry.text = this._history[this._history.length - this._historyNavIndex - 1];
return true;
} else if (symbol == Clutter.Down) {
if (this._historyNavIndex <= 0)
return true;
this._historyNavIndex--;
if (this._historyNavIndex < 0)
this._entry.text = this._savedText;
else
this._entry.text = this._history[this._history.length - this._historyNavIndex - 1];
return true;
} else {
this._historyNavIndex = -1;
this._savedText = null;
return false;
}
}));
},
_readHistory: function () {
if (!this._historyFile.query_exists(null))
return;
let [result, contents, length, etag] = this._historyFile.load_contents(null);
this._history = contents.split('\n').filter(function (e) { return e != ''; });
},
_queueHistorySave: function() {
if (this._idleHistorySaveId > 0)
return;
this._idleHistorySaveId = Mainloop.timeout_add_seconds(5, Lang.bind(this, this._doSaveHistory));
},
_doSaveHistory: function () {
this._idleHistorySaveId = false;
let output = this._historyFile.replace(null, true, Gio.FileCreateFlags.NONE, null);
let dataOut = new Gio.DataOutputStream({ base_stream: output });
dataOut.put_string(this._history.join('\n'), null);
dataOut.put_string('\n', null);
dataOut.close(null);
return false;
},
_pushResult: function(command, obj) {
let index = this._results.length + this._offset;
let result = new Result('>>> ' + command, obj, index);
this._results.push(result);
this._resultsArea.append(result.actor, Big.BoxPackFlags.NONE);
this._propInspector.setTarget(obj);
let children = this._resultsArea.get_children();
if (children.length > this._maxItems) {
this._results.shift();
children[0].destroy();
this._offset++;
}
this._it = obj;
},
_evaluate : function(command) {
this._history.push(command);
this._queueHistorySave();
let fullCmd = commandHeader + command;
let resultObj;
try {
resultObj = eval(fullCmd);
} catch (e) {
resultObj = "<exception " + e + ">";
}
this._pushResult(command, resultObj);
this._hierarchy.setTarget(null);
this._entry.text = '';
},
getIt: function () {
return this._it;
},
getResult: function(idx) {
return this._results[idx - this._offset].o;
},
toggle: function() {
if (this._open)
this.close();
else
this.open();
},
_resizeTo: function(actor) {
let stage = global.stage;
let myWidth = stage.width * 0.7;
let myHeight = stage.height * 0.7;
let [srcX, srcY] = actor.get_transformed_position();
this.actor.x = srcX + (stage.width-myWidth)/2;
this._hiddenY = srcY + actor.height - myHeight - 4; // -4 to hide the top corners
this._targetY = this._hiddenY + myHeight;
this.actor.y = this._hiddenY;
this.actor.width = myWidth;
this.actor.height = myHeight;
},
slaveTo: function(actor) {
this._slaveTo = actor;
actor.connect('notify::allocation', Lang.bind(this, function () {
this._resizeTo(actor);
}));
this._resizeTo(actor);
},
open : function() {
if (this._open)
return;
this.actor.show();
this.actor.lower(Main.chrome.actor);
this._open = true;
Tweener.removeTweens(this.actor);
Main.pushModal(this.actor);
global.stage.set_key_focus(this._entry);
Tweener.addTween(this.actor, { time: 0.5,
transition: "easeOutQuad",
y: this._targetY
});
},
close : function() {
if (!this._open)
return;
this._historyNavIndex = -1;
this._open = false;
Tweener.removeTweens(this.actor);
Main.popModal(this.actor);
Tweener.addTween(this.actor, { time: 0.5,
transition: "easeOutQuad",
y: this._hiddenY,
onComplete: Lang.bind(this, function () {
this.actor.hide();
})
});
}
};
Signals.addSignalMethods(LookingGlass.prototype);

View File

@ -3,6 +3,7 @@
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
@ -10,9 +11,10 @@ const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Chrome = imports.ui.chrome;
const Overlay = imports.ui.overlay;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
const RunDialog = imports.ui.runDialog;
const LookingGlass = imports.ui.lookingGlass;
const Sidebar = imports.ui.sidebar;
const Tweener = imports.ui.tweener;
const WindowManager = imports.ui.windowManager;
@ -23,49 +25,53 @@ DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
let chrome = null;
let panel = null;
let sidebar = null;
let overlay = null;
let overview = null;
let runDialog = null;
let lookingGlass = null;
let wm = null;
let recorder = null;
let inModal = false;
let modalCount = 0;
let modalActorFocusStack = [];
function start() {
let global = Shell.Global.get();
// Add a binding for "global" in the global JS namespace; (gjs
// keeps the web browser convention of having that namespace be
// called "window".)
window.global = Shell.Global.get();
Gio.DesktopAppInfo.set_desktop_env("GNOME");
global.grab_dbus_service();
global.start_task_panel();
Tweener.init();
// Ensure ShellAppMonitor is initialized; this will
// also initialize ShellAppSystem first. ShellAppSystem
// needs to load all the .desktop files, and ShellAppMonitor
// will use those to associate with windows. Right now
// the Monitor doesn't listen for installed app changes
// and recalculate application associations, so to avoid
// races for now we initialize it here. It's better to
// be predictable anyways.
Shell.AppMonitor.get_default();
// The background color really only matters if there is no desktop
// window (say, nautilus) running. We set it mostly so things look good
// when we are running inside Xephyr.
global.stage.color = DEFAULT_BACKGROUND_COLOR;
// Mutter currently hardcodes putting "Yessir. The compositor is running""
// in the overlay. Clear that out.
// in the Overview. Clear that out.
let children = global.overlay_group.get_children();
for (let i = 0; i < children.length; i++)
children[i].destroy();
global.connect('panel-run-dialog', function(panel) {
// Make sure not more than one run dialog is shown.
if (!runDialog) {
runDialog = new RunDialog.RunDialog();
let endHandler = function() {
runDialog.destroy();
runDialog = null;
};
runDialog.connect('run', endHandler);
runDialog.connect('cancel', endHandler);
if (!runDialog.show())
endHandler();
}
getRunDialog().open();
});
overlay = new Overlay.Overlay();
overview = new Overview.Overview();
chrome = new Chrome.Chrome();
panel = new Panel.Panel();
sidebar = new Sidebar.Sidebar();
@ -73,11 +79,6 @@ function start() {
global.screen.connect('toggle-recording', function() {
if (recorder == null) {
// We have to initialize GStreamer first. This isn't done
// inside ShellRecorder to make it usable inside projects
// with other usage of GStreamer.
let Gst = imports.gi.Gst;
Gst.init(null, null);
recorder = new Shell.Recorder({ stage: global.stage });
}
@ -88,13 +89,24 @@ function start() {
}
});
_relayout();
panel.startupAnimation();
let display = global.screen.get_display();
display.connect('overlay-key', Lang.bind(overlay, overlay.toggle));
global.connect('panel-main-menu', Lang.bind(overlay, overlay.toggle));
display.connect('overlay-key', Lang.bind(overview, overview.toggle));
global.connect('panel-main-menu', Lang.bind(overview, overview.toggle));
global.stage.connect('captured-event', _globalKeyPressHandler);
Mainloop.idle_add(_removeUnusedWorkspaces);
}
function _relayout() {
panel.actor.set_size(global.screen_width, Panel.PANEL_HEIGHT);
overview.relayout();
}
// metacity-clutter currently uses the same prefs as plain metacity,
// which probably means we'll be starting out with multiple workspaces;
// remove any unused ones. (We do this from an idle handler, because
@ -102,8 +114,6 @@ function start() {
// is called.)
function _removeUnusedWorkspaces() {
let global = Shell.Global.get();
let windows = global.get_windows();
let maxWorkspace = 0;
for (let i = 0; i < windows.length; i++) {
@ -125,31 +135,154 @@ function _removeUnusedWorkspaces() {
return false;
}
// Used to go into a mode where all keyboard and mouse input goes to
// the stage. Returns true if we successfully grabbed the keyboard and
// went modal, false otherwise
function startModal() {
let global = Shell.Global.get();
if (!global.grab_keyboard())
// This function encapsulates hacks to make certain global keybindings
// work even when we are in one of our modes where global keybindings
// are disabled with a global grab. (When there is a global grab, then
// all key events will be delivered to the stage, so ::captured-event
// on the stage can be used for global keybindings.)
//
// We expect to need to conditionally enable just a few keybindings
// depending on circumstance; the main hackiness here is that we are
// assuming that keybindings have their default values; really we
// should be asking Mutter to resolve the key into an action and then
// base our handling based on the action.
function _globalKeyPressHandler(actor, event) {
if (modalCount == 0)
return false;
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
inModal = true;
let type = event.type();
return true;
if (type == Clutter.EventType.KEY_PRESS) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.Print) {
// We want to be able to take screenshots of the shell at all times
let gconf = Shell.GConf.get_default();
let command = gconf.get_string("/apps/metacity/keybinding_commands/command_screenshot");
if (command != null && command != "") {
let [ok, len, args] = GLib.shell_parse_argv(command);
let p = new Shell.Process({'args' : args});
p.run();
}
return true;
}
} else if (type == Clutter.EventType.KEY_RELEASE) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
// The super key is the default for triggering the overview, and should
// get us out of the overview when we are already in it.
if (overview.visible)
overview.hide();
return true;
} else if (symbol == Clutter.F2 && (event.get_state() & Clutter.ModifierType.MOD1_MASK)) {
getRunDialog().open();
}
}
return false;
}
function endModal() {
let global = Shell.Global.get();
function _findModal(actor) {
for (let i = 0; i < modalActorFocusStack.length; i++) {
let [stackActor, stackFocus] = modalActorFocusStack[i];
if (stackActor == actor) {
return i;
}
}
return -1;
}
global.ungrab_keyboard();
/**
* pushModal:
* @actor: #ClutterActor which will be given keyboard focus
*
* Ensure we are in a mode where all keyboard and mouse input goes to
* the stage. Multiple calls to this function act in a stacking fashion;
* the effect will be undone when an equal number of popModal() invocations
* have been made.
*
* Next, record the current Clutter keyboard focus on a stack. If the modal stack
* returns to this actor, reset the focus to the actor which was focused
* at the time pushModal() was invoked.
*/
function pushModal(actor) {
let timestamp = global.screen.get_display().get_current_time();
modalCount += 1;
actor.connect('destroy', function() {
let index = _findModal(actor);
if (index >= 0)
modalActorFocusStack.splice(index, 1);
});
let curFocus = global.stage.get_key_focus();
if (curFocus != null) {
curFocus.connect('destroy', function() {
let index = _findModal(actor);
if (index >= 0)
modalActorFocusStack[index][1] = null;
});
}
modalActorFocusStack.push([actor, curFocus]);
if (modalCount > 1)
return;
if (!global.begin_modal(timestamp)) {
log("pushModal: invocation of begin_modal failed");
return;
}
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
}
/**
* popModal:
* @actor: #ClutterActor passed to original invocation of pushModal().
*
* Reverse the effect of pushModal(). If this invocation is undoing
* the topmost invocation, then the focus will be restored to the
* previous focus at the time when pushModal() was invoked.
*/
function popModal(actor) {
let timestamp = global.screen.get_display().get_current_time();
modalCount -= 1;
let focusIndex = _findModal(actor);
if (focusIndex >= 0) {
if (focusIndex == modalActorFocusStack.length - 1) {
let [stackActor, stackFocus] = modalActorFocusStack[focusIndex];
global.stage.set_key_focus(stackFocus);
} else {
// Remove from the middle, shift the focus chain up
for (let i = focusIndex; i < modalActorFocusStack.length - 1; i++) {
modalActorFocusStack[i + 1][1] = modalActorFocusStack[i][1];
}
}
modalActorFocusStack.splice(focusIndex, 1);
}
if (modalCount > 0)
return;
global.end_modal(timestamp);
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
inModal = false;
}
function createLookingGlass() {
if (lookingGlass == null) {
lookingGlass = new LookingGlass.LookingGlass();
lookingGlass.slaveTo(panel.actor);
}
return lookingGlass;
}
function getRunDialog() {
if (runDialog == null) {
runDialog = new RunDialog.RunDialog();
}
return runDialog;
}
function createAppLaunchContext() {
let global = Shell.Global.get();
let screen = global.screen;
let display = screen.get_display();

View File

@ -1,975 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Lang = imports.lang;
const AppDisplay = imports.ui.appDisplay;
const DocDisplay = imports.ui.docDisplay;
const GenericDisplay = imports.ui.genericDisplay;
const Link = imports.ui.link;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const Tweener = imports.ui.tweener;
const Workspaces = imports.ui.workspaces;
const ROOT_OVERLAY_COLOR = new Clutter.Color();
ROOT_OVERLAY_COLOR.from_pixel(0x000000bb);
// The factor to scale the overlay wallpaper with. This should not be less
// than 3/2, because the rule of thirds is used for positioning (see below).
const BACKGROUND_SCALE = 2;
const LABEL_HEIGHT = 16;
// We use SIDESHOW_PAD for the padding on the left side of the sideshow and as a gap
// between sideshow columns.
const SIDESHOW_PAD = 6;
const SIDESHOW_MIN_WIDTH = 250;
const SIDESHOW_SECTION_PADDING_TOP = 6;
const SIDESHOW_SECTION_SPACING = 6;
const SIDESHOW_COLUMNS = 1;
const DETAILS_CORNER_RADIUS = 5;
const DETAILS_BORDER_WIDTH = 1;
const DETAILS_PADDING = 6;
// This is the height of section components other than the item display.
const SIDESHOW_SECTION_MISC_HEIGHT = (LABEL_HEIGHT + SIDESHOW_SECTION_SPACING) * 2 + SIDESHOW_SECTION_PADDING_TOP;
const SIDESHOW_SEARCH_BG_COLOR = new Clutter.Color();
SIDESHOW_SEARCH_BG_COLOR.from_pixel(0xffffffff);
const SIDESHOW_TEXT_COLOR = new Clutter.Color();
SIDESHOW_TEXT_COLOR.from_pixel(0xffffffff);
const DETAILS_BORDER_COLOR = new Clutter.Color();
DETAILS_BORDER_COLOR.from_pixel(0xffffffff);
// Time for initial animation going into overlay mode
const ANIMATION_TIME = 0.25;
// We divide the screen into a grid of rows and columns, which we use
// to help us position the overlay components, such as the side panel
// that lists applications and documents, the workspaces display, and
// the button for adding additional workspaces.
// In the regular mode, the side panel takes up one column on the left,
// and the workspaces display takes up the remaining columns.
// In the expanded side panel display mode, the side panel takes up two
// columns, and the workspaces display slides all the way to the right,
// being visible only in the last quarter of the right-most column.
// In the future, this mode will have more components, such as a display
// of documents which were recently opened with a given application, which
// will take up the remaining sections of the display.
const WIDE_SCREEN_CUT_OFF_RATIO = 1.4;
const COLUMNS_REGULAR_SCREEN = 4;
const ROWS_REGULAR_SCREEN = 8;
const COLUMNS_WIDE_SCREEN = 5;
const ROWS_WIDE_SCREEN = 10;
// Padding around workspace grid / Spacing between Sideshow and Workspaces
const WORKSPACE_GRID_PADDING = 12;
const COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN = 3;
const ROWS_FOR_WORKSPACES_REGULAR_SCREEN = 6;
const WORKSPACES_X_FACTOR_ASIDE_MODE_REGULAR_SCREEN = 4 - 0.25;
const EXPANDED_SIDESHOW_COLUMNS_REGULAR_SCREEN = 2;
const COLUMNS_FOR_WORKSPACES_WIDE_SCREEN = 4;
const ROWS_FOR_WORKSPACES_WIDE_SCREEN = 8;
const WORKSPACES_X_FACTOR_ASIDE_MODE_WIDE_SCREEN = 5 - 0.25;
const EXPANDED_SIDESHOW_COLUMNS_WIDE_SCREEN = 3;
// A multi-state; PENDING is used during animations
const STATE_ACTIVE = true;
const STATE_PENDING_INACTIVE = false;
const STATE_INACTIVE = false;
let wideScreen = false;
let displayGridColumnWidth = null;
let displayGridRowHeight = null;
function SearchEntry(width) {
this._init(width);
}
SearchEntry.prototype = {
_init : function(width) {
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
y_align: Big.BoxAlignment.CENTER,
background_color: SIDESHOW_SEARCH_BG_COLOR,
corner_radius: 4,
spacing: 4,
padding_left: 4,
padding_right: 4,
width: width,
height: 24
});
let icontheme = Gtk.IconTheme.get_default();
let searchIconTexture = new Clutter.Texture({});
let searchIconPath = icontheme.lookup_icon('gtk-find', 16, 0).get_filename();
searchIconTexture.set_from_file(searchIconPath);
this.actor.append(searchIconTexture, 0);
// We need to initialize the text for the entry to have the cursor displayed
// in it. See http://bugzilla.openedhand.com/show_bug.cgi?id=1365
this.entry = new Clutter.Text({ font_name: "Sans 14px",
editable: true,
activatable: true,
singleLineMode: true,
text: ""
});
this.entry.connect('text-changed', Lang.bind(this, function (e) {
let text = this.entry.text;
}));
this.actor.append(this.entry, Big.BoxPackFlags.EXPAND);
}
};
function Sideshow() {
this._init();
}
Sideshow.prototype = {
_init : function() {
let me = this;
this._moreAppsMode = STATE_INACTIVE;
this._moreDocsMode = STATE_INACTIVE;
let asideXFactor = wideScreen ? WORKSPACES_X_FACTOR_ASIDE_MODE_WIDE_SCREEN : WORKSPACES_X_FACTOR_ASIDE_MODE_REGULAR_SCREEN;
this._expandedSideshowColumns = wideScreen ? EXPANDED_SIDESHOW_COLUMNS_WIDE_SCREEN : EXPANDED_SIDESHOW_COLUMNS_REGULAR_SCREEN;
this._width = displayGridColumnWidth;
this._displayWidth = this._width - SIDESHOW_PAD;
this._expandedWidth = displayGridColumnWidth * asideXFactor;
// this figures out the additional width we can give to the display in the 'More' mode,
// assuming that we want to keep the columns the same width in both modes
this._additionalWidth = (this._width / SIDESHOW_COLUMNS) *
(this._expandedSideshowColumns - SIDESHOW_COLUMNS);
let bottomHeight = displayGridRowHeight / 2;
let global = Shell.Global.get();
let previewWidth = this._expandedWidth - this._width -
this._additionalWidth - SIDESHOW_SECTION_SPACING;
let previewHeight = global.screen_height - Panel.PANEL_HEIGHT - SIDESHOW_PAD - bottomHeight;
this.actor = new Clutter.Group();
this.actor.height = global.screen_height;
this._searchEntry = new SearchEntry(this._displayWidth);
this.actor.add_actor(this._searchEntry.actor);
this._searchEntry.actor.set_position(SIDESHOW_PAD, Panel.PANEL_HEIGHT + SIDESHOW_PAD);
this._searchQueued = false;
this._searchEntry.entry.connect('text-changed', function (se, prop) {
if (me._searchQueued)
return;
me._searchQueued = true;
Mainloop.timeout_add(250, function() {
// Strip leading and trailing whitespace
let text = me._searchEntry.entry.text.replace(/^\s+/g, "").replace(/\s+$/g, "");
me._searchQueued = false;
me._appDisplay.setSearch(text);
me._docDisplay.setSearch(text);
return false;
});
});
this._searchEntry.entry.connect('activate', function (se) {
// only one of the displays will have an item selected, so it's ok to
// call activateSelected() on both of them
me._appDisplay.activateSelected();
me._docDisplay.activateSelected();
return true;
});
this._searchEntry.entry.connect('key-press-event', function (se, e) {
let symbol = Shell.get_event_key_symbol(e);
if (symbol == Clutter.Escape) {
// We always want to hide the previews when the user hits Escape.
// If something that should have a preview gets displayed under
// the mouse pointer afterwards the preview will get redisplayed.
me._appDisplay.hidePreview();
me._docDisplay.hidePreview();
// Escape will keep clearing things back to the desktop. First, if
// we have active text, we remove it.
if (me._searchEntry.text != '')
me._searchEntry.text = '';
// Next, if we're in one of the "more" modes, close it
else if (me._moreAppsMode)
me._unsetMoreAppsMode();
else if (me._moreDocsMode)
me._unsetMoreDocsMode();
else
// Finally, just close the overlay entirely
me.emit('activated');
return true;
} else if (symbol == Clutter.Up) {
// selectUp and selectDown wrap around in their respective displays
// too, but there doesn't seem to be any flickering if we first select
// something in one display, but then unset the selection, and move
// it to the other display, so it's ok to do that.
if (me._moreAppsMode)
me._appDisplay.selectUp();
else if (me._moreDocsMode)
me._docDisplay.selectUp();
else if (me._appDisplay.hasSelected() && !me._appDisplay.selectUp() && me._docDisplay.hasItems()) {
me._appDisplay.unsetSelected();
me._docDisplay.selectLastItem();
} else if (me._docDisplay.hasSelected() && !me._docDisplay.selectUp() && me._appDisplay.hasItems()) {
me._docDisplay.unsetSelected();
me._appDisplay.selectLastItem();
}
return true;
} else if (symbol == Clutter.Down) {
if (me._moreAppsMode)
me._appDisplay.selectDown();
else if (me._moreDocsMode)
me._docDisplay.selectDown();
else if (me._appDisplay.hasSelected() && !me._appDisplay.selectDown() && me._docDisplay.hasItems()) {
me._appDisplay.unsetSelected();
me._docDisplay.selectFirstItem();
} else if (me._docDisplay.hasSelected() && !me._docDisplay.selectDown() && me._appDisplay.hasItems()) {
me._docDisplay.unsetSelected();
me._appDisplay.selectFirstItem();
}
return true;
} else if (me._moreAppsMode && me._searchEntry.text == '') {
if (symbol == Clutter.Right) {
me._appDisplay.moveRight();
return true;
} else if (symbol == Clutter.Left) {
me._appDisplay.moveLeft();
return true;
}
return false;
} else if (symbol == Clutter.Right && me._searchEntry.text == '') {
if (me._appDisplay.hasSelected())
me._setMoreAppsMode();
else
me._setMoreDocsMode();
return true;
}
return false;
});
this._appsSection = new Big.Box({ x: SIDESHOW_PAD,
y: this._searchEntry.actor.y + this._searchEntry.actor.height,
padding_top: SIDESHOW_SECTION_PADDING_TOP,
spacing: SIDESHOW_SECTION_SPACING});
this._appsText = new Clutter.Text({ color: SIDESHOW_TEXT_COLOR,
font_name: "Sans Bold 14px",
text: "Applications",
height: LABEL_HEIGHT});
this._appsSection.append(this._appsText, Big.BoxPackFlags.EXPAND);
this._itemDisplayHeight = global.screen_height - this._appsSection.y - SIDESHOW_SECTION_MISC_HEIGHT * 2 - bottomHeight;
this._appsContent = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
this._appsSection.append(this._appsContent, Big.BoxPackFlags.EXPAND);
this._appDisplay = new AppDisplay.AppDisplay(this._displayWidth, this._itemDisplayHeight / 2, SIDESHOW_COLUMNS, SIDESHOW_PAD);
let sideArea = this._appDisplay.getSideArea();
sideArea.hide();
this._appsContent.append(sideArea, Big.BoxPackFlags.NONE);
this._appsContent.append(this._appDisplay.actor, Big.BoxPackFlags.EXPAND);
let moreAppsBox = new Big.Box({x_align: Big.BoxAlignment.END});
this._moreAppsLink = new Link.Link({ color: SIDESHOW_TEXT_COLOR,
font_name: "Sans Bold 14px",
text: "More...",
height: LABEL_HEIGHT });
moreAppsBox.append(this._moreAppsLink.actor, Big.BoxPackFlags.EXPAND);
this._appsSection.append(moreAppsBox, Big.BoxPackFlags.EXPAND);
this.actor.add_actor(this._appsSection);
this._appsSectionDefaultHeight = this._appsSection.height;
this._appsDisplayControlBox = new Big.Box({x_align: Big.BoxAlignment.CENTER});
this._appsDisplayControlBox.append(this._appDisplay.displayControl, Big.BoxPackFlags.NONE);
this._docsSection = new Big.Box({ x: SIDESHOW_PAD,
y: this._appsSection.y + this._appsSection.height,
padding_top: SIDESHOW_SECTION_PADDING_TOP,
spacing: SIDESHOW_SECTION_SPACING});
this._docsText = new Clutter.Text({ color: SIDESHOW_TEXT_COLOR,
font_name: "Sans Bold 14px",
text: "Recent Documents",
height: LABEL_HEIGHT});
this._docsSection.append(this._docsText, Big.BoxPackFlags.EXPAND);
this._docDisplay = new DocDisplay.DocDisplay(this._displayWidth, this._itemDisplayHeight - this._appsContent.height, SIDESHOW_COLUMNS, SIDESHOW_PAD);
this._docsSection.append(this._docDisplay.actor, Big.BoxPackFlags.EXPAND);
let moreDocsBox = new Big.Box({x_align: Big.BoxAlignment.END});
this._moreDocsLink = new Link.Link({ color: SIDESHOW_TEXT_COLOR,
font_name: "Sans Bold 14px",
text: "More...",
height: LABEL_HEIGHT });
moreDocsBox.append(this._moreDocsLink.actor, Big.BoxPackFlags.EXPAND);
this._docsSection.append(moreDocsBox, Big.BoxPackFlags.EXPAND);
this.actor.add_actor(this._docsSection);
this._docsSectionDefaultHeight = this._docsSection.height;
this._docsDisplayControlBox = new Big.Box({x_align: Big.BoxAlignment.CENTER});
this._docsDisplayControlBox.append(this._docDisplay.displayControl, Big.BoxPackFlags.NONE);
this._details = new Big.Box({ x: this._width + this._additionalWidth + SIDESHOW_SECTION_SPACING,
y: Panel.PANEL_HEIGHT + SIDESHOW_PAD,
width: previewWidth,
height: previewHeight,
corner_radius: DETAILS_CORNER_RADIUS,
border: DETAILS_BORDER_WIDTH,
border_color: DETAILS_BORDER_COLOR,
padding: DETAILS_PADDING});
this._appDisplay.setAvailableDimensionsForItemDetails(previewWidth - DETAILS_PADDING * 2 - DETAILS_BORDER_WIDTH * 2,
previewHeight - DETAILS_PADDING * 2 - DETAILS_BORDER_WIDTH * 2);
this._docDisplay.setAvailableDimensionsForItemDetails(previewWidth - DETAILS_PADDING * 2 - DETAILS_BORDER_WIDTH * 2,
previewHeight - DETAILS_PADDING * 2 - DETAILS_BORDER_WIDTH * 2);
/* Proxy the activated signals */
this._appDisplay.connect('activated', function(appDisplay) {
me.emit('activated');
});
this._docDisplay.connect('activated', function(docDisplay) {
me.emit('activated');
});
this._appDisplay.connect('selected', function(appDisplay) {
// We allow clicking on any item to select it, so if an
// item in the app display is selected, we need to make sure that
// no item in the doc display has the selection.
me._docDisplay.unsetSelected();
me._docDisplay.hidePreview();
});
this._docDisplay.connect('selected', function(docDisplay) {
// We allow clicking on any item to select it, so if an
// item in the doc display is selected, we need to make sure that
// no item in the app display has the selection.
me._appDisplay.unsetSelected();
me._appDisplay.hidePreview();
});
this._appDisplay.connect('redisplayed', function(appDisplay) {
me._ensureItemSelected();
});
this._docDisplay.connect('redisplayed', function(docDisplay) {
me._ensureItemSelected();
});
this._moreAppsLink.connect('clicked',
function(o, event) {
if (me._moreAppsMode) {
me._unsetMoreAppsMode();
} else {
me._setMoreAppsMode();
}
});
this._moreDocsLink.connect('clicked',
function(o, event) {
if (me._moreDocsMode) {
me._unsetMoreDocsMode();
} else {
me._setMoreDocsMode();
}
});
},
show: function() {
let global = Shell.Global.get();
this._appDisplay.show();
this._appsContent.show();
this._docDisplay.show();
this._appDisplay.selectFirstItem();
if (!this._appDisplay.hasSelected())
this._docDisplay.selectFirstItem();
else
this._docDisplay.unsetSelected();
global.stage.set_key_focus(this._searchEntry.entry);
},
hide: function() {
this._appsContent.hide();
this._docDisplay.hide();
this._searchEntry.entry.text = '';
this._unsetMoreAppsMode();
this._unsetMoreDocsMode();
},
// Ensures that one of the displays has the selection if neither owns it after the
// latest redisplay. This can be applicable if the display that earlier had the
// selection no longer has any items, or if their is a single section being shown
// in the expanded view and it went from having no matching items to having some.
// We first try to place the selection in the applications section, because it is
// displayed above the documents section.
_ensureItemSelected: function() {
if (!this._appDisplay.hasSelected() && !this._docDisplay.hasSelected()) {
if (this._appDisplay.hasItems()) {
this._appDisplay.selectFirstItem();
} else if (this._docDisplay.hasItems()) {
this._docDisplay.selectFirstItem();
}
}
},
// Sets the 'More' mode for browsing applications. Updates the applications section to have more items.
// Slides down the documents section to reveal the additional applications.
_setMoreAppsMode: function() {
if (this._moreAppsMode)
return;
// No corresponding STATE_PENDING_ACTIVE, because we call updateAppsSection
// immediately below.
this._moreAppsMode = STATE_ACTIVE;
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
this._moreAppsLink.actor.hide();
this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height);
// Move the selection to the applications section if it was in the docs section.
this._docDisplay.unsetSelected();
// Because we have menus in applications, we want to reset the selection for applications
// as well. The default is no menu.
this._appDisplay.unsetSelected();
this._updateAppsSection();
Tweener.addTween(this._docsSection,
{ y: this._docsSection.y + this._docsSection.height,
clipHeightBottom: 0,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
// We need to expand the clip on the applications section so that the first additional
// application to be displayed does not appear abruptly.
Tweener.addTween(this._appsSection,
{ clipHeightBottom: this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT * 2 - LABEL_HEIGHT - SIDESHOW_SECTION_SPACING,
time: ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._onAppsSectionExpanded,
onCompleteScope: this
});
this.actor.set_clip(0, 0, this.actor.width, this.actor.height);
Tweener.addTween(this.actor,
{ clipWidthRight: this._expandedWidth,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
this.emit('more-activated');
},
// Unsets the 'More' mode for browsing applications. Slides in the documents section.
_unsetMoreAppsMode: function() {
if (!this._moreAppsMode)
return;
this._moreAppsMode = STATE_PENDING_INACTIVE;
this._moreAppsLink.actor.hide();
this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height);
this.actor.set_clip(0, 0, this.actor.width, this.actor.height);
this._docDisplay.show();
// We need to be reducing the clip on the applications section so that the last application to
// be removed does not disappear abruptly.
Tweener.addTween(this._appsSection,
{ clipHeightBottom: this._appsSectionDefaultHeight - LABEL_HEIGHT - SIDESHOW_SECTION_SPACING,
time: ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._onAppsSectionReduced,
onCompleteScope: this
});
Tweener.addTween(this._docsSection,
{ y: this._docsSection.y - this._docsSection.height,
clipHeightBottom: this._docsSection.height,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
Tweener.addTween(this.actor,
{ clipWidthRight: this._width,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
this.emit('less-activated');
},
// Removes the clip from the applications section to reveal the 'Less...' text.
// Hides the documents section so that it doesn't get updated on new searches.
_onAppsSectionExpanded: function() {
this._appsSection.remove_clip();
this._docDisplay.hide();
this.actor.remove_clip();
},
// Updates the applications section to contain fewer items. Selects the first item in the
// documents section if applications section has no items.
// Removes the clip from the applications section to reveal the 'More...' text.
// Removes the clip from the documents section, so that the clip does not limit the size of
// the section if it is expanded later.
_onAppsSectionReduced: function() {
this.actor.remove_clip();
if (this._moreAppsMode != STATE_PENDING_INACTIVE)
return;
this._moreAppsMode = STATE_INACTIVE;
this._updateAppsSection();
if (!this._appDisplay.hasItems())
this._docDisplay.selectFirstItem();
this._appsSection.remove_clip();
this._docsSection.remove_clip();
},
// Updates the applications section display and the 'More...' or 'Less...' control associated with it
// depending on the current mode. This function must only be called once after the 'More' mode has been
// changed, which is ensured by _setMoreAppsMode() and _unsetMoreAppsMode() functions.
_updateAppsSection: function() {
if (this._moreAppsMode) {
// Subtract one from columns since we are displaying menus
this._appDisplay.setExpanded(true, this._displayWidth, this._additionalWidth,
this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT,
this._expandedSideshowColumns - 1);
this._moreAppsLink.setText("Less...");
this._appsSection.insert_after(this._appsDisplayControlBox, this._appsContent, Big.BoxPackFlags.NONE);
this.actor.add_actor(this._details);
this._details.append(this._appDisplay.selectedItemDetails, Big.BoxPackFlags.NONE);
} else {
this._appDisplay.setExpanded(false, this._displayWidth, 0,
this._appsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT,
SIDESHOW_COLUMNS);
this._moreAppsLink.setText("More...");
this._appsSection.remove_actor(this._appsDisplayControlBox);
this.actor.remove_actor(this._details);
this._details.remove_all();
}
this._moreAppsLink.actor.show();
},
// Sets the 'More' mode for browsing documents. Updates the documents section to have more items.
// Slides up the applications section and the documents section at the same time to reveal the additional
// documents.
_setMoreDocsMode: function() {
if (this._moreDocsMode)
return;
this._moreDocsMode = true;
if (!this._appsSection.has_clip)
this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height);
this._moreDocsLink.actor.hide();
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
this.actor.set_clip(0, 0, this.actor.width, this.actor.height);
// Move the selection to the docs section if it was in the apps section.
this._appDisplay.unsetSelected();
if (!this._docDisplay.hasSelected())
this._docDisplay.selectFirstItem();
this._updateDocsSection();
Tweener.addTween(this._appsSection,
{ y: this._appsSection.y - this._appsSection.height,
clipHeightTop: 0,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
// We do not slide in the 'Less...' text along with the documents so that the documents appear from the same
// edge where the last document was displayed, and not have that edge gradually move over to where the 'Less'
// text is displayed.
Tweener.addTween(this._docsSection,
{ y: this._searchEntry.actor.y + this._searchEntry.actor.height,
clipHeightBottom: this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT * 2 - LABEL_HEIGHT - SIDESHOW_SECTION_SPACING,
time: ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._onDocsSectionExpanded,
onCompleteScope: this
});
Tweener.addTween(this.actor,
{ clipWidthRight: this._expandedWidth,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
this.emit('more-activated');
},
// Unsets the 'More' mode for browsing documents. Slides in the applications section
// and slides down the documents section.
_unsetMoreDocsMode: function() {
if (!this._moreDocsMode)
return;
this._moreDocsMode = false;
this._moreDocsLink.actor.hide();
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
this.actor.set_clip(0, 0, this.actor.width, this.actor.height);
this._appsContent.show();
Tweener.addTween(this._docsSection,
{ y: this._docsSection.y + this._appsSectionDefaultHeight,
clipHeightBottom: this._docsSectionDefaultHeight - LABEL_HEIGHT - SIDESHOW_SECTION_SPACING,
time: ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._onDocsSectionReduced,
onCompleteScope: this
});
Tweener.addTween(this._appsSection,
{ y: this._appsSection.y + this._appsSection.height,
clipHeightTop: this._appsSection.height,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
Tweener.addTween(this.actor,
{ clipWidthRight: this._width,
time: ANIMATION_TIME,
transition: "easeOutQuad"
});
this.emit('less-activated');
},
// Removes the clip from the documents section to reveal the 'Less...' text.
// Hides the applications section so that it doesn't get updated on new searches.
_onDocsSectionExpanded: function() {
this._docsSection.remove_clip();
this._appsContent.hide();
this.actor.remove_clip();
},
// Updates the documents section to contain fewer items. Selects the first item in the
// applications section if applications section has no items.
// Removes the clip from the documents section to reveal the 'More...' text.
// Removes the clip from the applications section, so that the clip does not limit the size of
// the section if it is expanded later.
_onDocsSectionReduced: function() {
this.actor.remove_clip();
this._updateDocsSection();
if (!this._docDisplay.hasItems())
this._appDisplay.selectFirstItem();
this._docsSection.remove_clip();
this._appsSection.remove_clip();
},
// Updates the documents section display and the 'More...' or 'Less...' control associated with it
// depending on the current mode. This function must only be called once after the 'More' mode has been
// changed, which is ensured by _setMoreDocsMode() and _unsetMoreDocsMode() functions.
_updateDocsSection: function() {
if (this._moreDocsMode) {
this._docDisplay.setExpanded(true, this._displayWidth, this._additionalWidth,
this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT,
this._expandedSideshowColumns);
this._moreDocsLink.setText("Less...");
this._docsSection.insert_after(this._docsDisplayControlBox, this._docDisplay.actor, Big.BoxPackFlags.NONE);
this.actor.add_actor(this._details);
this._details.append(this._docDisplay.selectedItemDetails, Big.BoxPackFlags.NONE);
} else {
this._docDisplay.setExpanded(false, this._displayWidth, 0,
this._docsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT,
SIDESHOW_COLUMNS);
this._moreDocsLink.setText("More...");
this._docsSection.remove_actor(this._docsDisplayControlBox);
this.actor.remove_actor(this._details);
this._details.remove_all();
}
this._moreDocsLink.actor.show();
}
};
Signals.addSignalMethods(Sideshow.prototype);
function Overlay() {
this._init();
}
Overlay.prototype = {
_init : function() {
let me = this;
let global = Shell.Global.get();
wideScreen = (global.screen_width/global.screen_height > WIDE_SCREEN_CUT_OFF_RATIO);
// We divide the screen into an imaginary grid which helps us determine the layout of
// different visual components.
if (wideScreen) {
displayGridColumnWidth = global.screen_width / COLUMNS_WIDE_SCREEN;
displayGridRowHeight = global.screen_height / ROWS_WIDE_SCREEN;
} else {
displayGridColumnWidth = global.screen_width / COLUMNS_REGULAR_SCREEN;
displayGridRowHeight = global.screen_height / ROWS_REGULAR_SCREEN;
}
this._group = new Clutter.Group();
this._group._delegate = this;
this.visible = false;
this._hideInProgress = false;
// A scaled root pixmap actor is used as a background. It is zoomed in
// to the lower right intersection of the lines that divide the image
// evenly in a 3x3 grid. This is based on the rule of thirds, a
// compositional rule of thumb in visual arts. The choice for the
// lower right point is based on a quick survey of GNOME wallpapers.
let background = global.create_root_pixmap_actor();
background.width = global.screen_width * BACKGROUND_SCALE;
background.height = global.screen_height * BACKGROUND_SCALE;
background.x = -global.screen_width * (4 * BACKGROUND_SCALE - 3) / 6;
background.y = -global.screen_height * (4 * BACKGROUND_SCALE - 3) / 6;
this._group.add_actor(background);
// Draw a semitransparent rectangle over the background for readability.
let backOver = new Clutter.Rectangle({ color: ROOT_OVERLAY_COLOR,
width: global.screen_width,
height: global.screen_height - Panel.PANEL_HEIGHT,
y: Panel.PANEL_HEIGHT });
this._group.add_actor(backOver);
this._group.hide();
global.overlay_group.add_actor(this._group);
// TODO - recalculate everything when desktop size changes
this._sideshow = new Sideshow();
this._group.add_actor(this._sideshow.actor);
this._workspaces = null;
this._sideshow.connect('activated', function(sideshow) {
// TODO - have some sort of animation/effect while
// transitioning to the new app. We definitely need
// startup-notification integration at least.
me.hide();
});
this._sideshow.connect('more-activated', function(sideshow) {
if (me._workspaces != null) {
let asideXFactor = wideScreen ? WORKSPACES_X_FACTOR_ASIDE_MODE_WIDE_SCREEN : WORKSPACES_X_FACTOR_ASIDE_MODE_REGULAR_SCREEN;
let workspacesX = displayGridColumnWidth * asideXFactor + WORKSPACE_GRID_PADDING;
me._workspaces.addButton.hide();
me._workspaces.updatePosition(workspacesX, null);
}
});
this._sideshow.connect('less-activated', function(sideshow) {
if (me._workspaces != null) {
let workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
me._workspaces.addButton.show();
me._workspaces.updatePosition(workspacesX, null);
}
});
},
//// Draggable target interface ////
// Unsets the expanded display mode if a GenericDisplayItem is being
// dragged over the overlay, i.e. as soon as it starts being dragged.
// This slides the workspaces back in and allows the user to place
// the item on any workspace.
handleDragOver : function(source, actor, x, y, time) {
if (source instanceof GenericDisplay.GenericDisplayItem) {
this._sideshow._unsetMoreAppsMode();
this._sideshow._unsetMoreDocsMode();
return true;
}
return false;
},
//// Public methods ////
show : function() {
if (this.visible)
return;
if (!Main.startModal())
return;
this.visible = true;
let global = Shell.Global.get();
let screenWidth = global.screen_width;
let screenHeight = global.screen_height;
this._sideshow.show();
let columnsUsed = wideScreen ? COLUMNS_FOR_WORKSPACES_WIDE_SCREEN : COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN;
let rowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN;
let workspacesWidth = displayGridColumnWidth * columnsUsed - WORKSPACE_GRID_PADDING * 2;
// We scale the vertical padding by (screenHeight / screenWidth) so that the workspace preserves its aspect ratio.
let workspacesHeight = displayGridRowHeight * rowsUsed - WORKSPACE_GRID_PADDING * (screenHeight / screenWidth) * 2;
let workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
let workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (screenHeight / screenWidth);
// place the 'Add Workspace' button in the bottom row of the grid
let addButtonSize = Math.floor(displayGridRowHeight * 3/5);
let addButtonX = workspacesX + workspacesWidth - addButtonSize;
let addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5);
this._workspaces = new Workspaces.Workspaces(workspacesWidth, workspacesHeight, workspacesX, workspacesY,
addButtonSize, addButtonX, addButtonY);
this._group.add_actor(this._workspaces.actor);
// All the the actors in the window group are completely obscured,
// hiding the group holding them while the overlay is displayed greatly
// increases performance of the overlay especially when there are many
// windows visible.
//
// If we switched to displaying the actors in the overlay rather than
// clones of them, this would obviously no longer be necessary.
global.window_group.hide();
this._group.show();
// Try to make the menu not too visible behind the empty space between
// the workspace previews by sliding in its clipping rectangle.
// We want to finish drawing the sideshow just before the top workspace fully
// slides in on the top. Which means that we have more time to wait before
// drawing the sideshow if the active workspace is displayed on the bottom of
// the workspaces grid, and almost no time to wait if it is displayed in the top
// row of the workspaces grid. The calculations used below try to roughly
// capture the animation ratio for when workspaces are covering the top of the overlay
// vs. when workspaces are already below the top of the overlay, and apply it
// to clipping the sideshow. The clipping is removed in this._showDone().
this._sideshow.actor.set_clip(0, 0,
this._workspaces.getFullSizeX(),
this._sideshow.actor.height);
Tweener.addTween(this._sideshow.actor,
{ clipWidthRight: this._sideshow._width + WORKSPACE_GRID_PADDING + this._workspaces.getWidthToTopActiveWorkspace(),
time: ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._showDone,
onCompleteScope: this
});
this.emit('showing');
},
hide : function() {
if (!this.visible || this._hideInProgress)
return;
let global = Shell.Global.get();
this._hideInProgress = true;
// lower the sideshow, so that workspaces display is on top and covers the sideshow while it is sliding out
this._sideshow.actor.lower(this._workspaces.actor);
this._workspaces.hide();
// Try to make the menu not too visible behind the empty space between
// the workspace previews by sliding in its clipping rectangle.
// The logic used is the same as described in this.show(). If the active workspace
// is displayed in the top row, than almost full animation time is needed for it
// to reach the top of the overlay and cover the sideshow fully, while if the
// active workspace is in the lower row, than the top left workspace reaches the
// top of the overlay sooner as it is moving out of the way.
// The clipping is removed in this._hideDone().
this._sideshow.actor.set_clip(0, 0,
this._sideshow.actor.width + WORKSPACE_GRID_PADDING + this._workspaces.getWidthToTopActiveWorkspace(),
this._sideshow.actor.height);
Tweener.addTween(this._sideshow.actor,
{ clipWidthRight: this._workspaces.getFullSizeX() + this._workspaces.getWidthToTopActiveWorkspace() - global.screen_width,
time: ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._hideDone,
onCompleteScope: this
});
this.emit('hiding');
},
toggle: function() {
if (this.visible)
this.hide();
else
this.show();
},
//// Private methods ////
// Raises the sideshow to the top, so that we can tell if the pointer is above one of its items.
// We need to do this once the workspaces are shown because the workspaces actor currently covers
// the whole screen, regardless of where the workspaces are actually displayed.
//
// Once we rework the workspaces actor to only cover the area it actually needs, we can
// remove this workaround. Also http://bugzilla.openedhand.com/show_bug.cgi?id=1513 requests being
// able to pick only a reactive actor at a certain position, rather than any actor. Being able
// to do that would allow us to not have to raise the sideshow.
_showDone: function() {
if (this._hideInProgress)
return;
this._sideshow.actor.raise_top();
this._sideshow.actor.remove_clip();
this.emit('shown');
},
_hideDone: function() {
let global = Shell.Global.get();
global.window_group.show();
this._workspaces.destroy();
this._workspaces = null;
this._sideshow.actor.remove_clip();
this._sideshow.hide();
this._group.hide();
this.visible = false;
this._hideInProgress = false;
Main.endModal();
this.emit('hidden');
}
};
Signals.addSignalMethods(Overlay.prototype);
Tweener.registerSpecialProperty("clipHeightBottom", _clipHeightBottomGet, _clipHeightBottomSet);
function _clipHeightBottomGet(actor) {
let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
return clipHeight;
}
function _clipHeightBottomSet(actor, clipHeight) {
actor.set_clip(0, 0, actor.width, clipHeight);
}
Tweener.registerSpecialProperty("clipHeightTop", _clipHeightTopGet, _clipHeightTopSet);
function _clipHeightTopGet(actor) {
let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
return clipHeight;
}
function _clipHeightTopSet(actor, clipHeight) {
actor.set_clip(0, actor.height - clipHeight, actor.width, clipHeight);
}
Tweener.registerSpecialProperty("clipWidthRight", _clipWidthRightGet, _clipWidthRightSet);
function _clipWidthRightGet(actor) {
let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
return clipWidth;
}
function _clipWidthRightSet(actor, clipWidth) {
actor.set_clip(0, 0, clipWidth, actor.height);
}

480
js/ui/overview.js Normal file
View File

@ -0,0 +1,480 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Lang = imports.lang;
const AppDisplay = imports.ui.appDisplay;
const DocDisplay = imports.ui.docDisplay;
const GenericDisplay = imports.ui.genericDisplay;
const Link = imports.ui.link;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const Dash = imports.ui.dash;
const Tweener = imports.ui.tweener;
const Workspaces = imports.ui.workspaces;
const ROOT_OVERVIEW_COLOR = new Clutter.Color();
ROOT_OVERVIEW_COLOR.from_pixel(0x000000ff);
// Time for initial animation going into Overview mode
const ANIMATION_TIME = 0.25;
// We divide the screen into a grid of rows and columns, which we use
// to help us position the Overview components, such as the side panel
// that lists applications and documents, the workspaces display, and
// the button for adding additional workspaces.
// In the regular mode, the side panel takes up one column on the left,
// and the workspaces display takes up the remaining columns.
// In the expanded side panel display mode, the side panel takes up two
// columns, and the workspaces display slides all the way to the right,
// being visible only in the last quarter of the right-most column.
// In the future, this mode will have more components, such as a display
// of documents which were recently opened with a given application, which
// will take up the remaining sections of the display.
const WIDE_SCREEN_CUT_OFF_RATIO = 1.4;
const COLUMNS_REGULAR_SCREEN = 4;
const ROWS_REGULAR_SCREEN = 8;
const COLUMNS_WIDE_SCREEN = 5;
const ROWS_WIDE_SCREEN = 10;
const DEFAULT_PADDING = 4;
// Padding around workspace grid / Spacing between Dash and Workspaces
const WORKSPACE_GRID_PADDING = 12;
const COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN = 3;
const ROWS_FOR_WORKSPACES_REGULAR_SCREEN = 6;
const COLUMNS_FOR_WORKSPACES_WIDE_SCREEN = 4;
const ROWS_FOR_WORKSPACES_WIDE_SCREEN = 8;
// A multi-state; PENDING is used during animations
const STATE_ACTIVE = true;
const STATE_PENDING_INACTIVE = false;
const STATE_INACTIVE = false;
const SHADOW_COLOR = new Clutter.Color();
SHADOW_COLOR.from_pixel(0x00000033);
const TRANSPARENT_COLOR = new Clutter.Color();
TRANSPARENT_COLOR.from_pixel(0x00000000);
const SHADOW_WIDTH = 6;
const NUMBER_OF_SECTIONS_IN_SEARCH = 2;
let wideScreen = false;
let displayGridColumnWidth = null;
let displayGridRowHeight = null;
let addRemoveButtonSize = null;
function Overview() {
this._init();
}
Overview.prototype = {
_init : function() {
this._group = new Clutter.Group();
this._group._delegate = this;
this.visible = false;
this.animationInProgress = false;
this._hideInProgress = false;
this._recalculateGridSizes();
this._activeDisplayPane = null;
// During transitions, we raise this to the top to avoid having the overview
// area be reactive; it causes too many issues such as double clicks on
// Dash elements, or mouseover handlers in the workspaces.
this._coverPane = new Clutter.Rectangle({ opacity: 0,
reactive: true });
this._group.add_actor(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
// Similar to the cover pane but used for dialogs ("panes"); see the comments
// in addPane below.
this._transparentBackground = new Clutter.Rectangle({ opacity: 0,
reactive: true });
this._group.add_actor(this._transparentBackground);
// Background color for the Overview
this._backOver = new Clutter.Rectangle({ color: ROOT_OVERVIEW_COLOR });
this._group.add_actor(this._backOver);
this._group.hide();
global.overlay_group.add_actor(this._group);
// TODO - recalculate everything when desktop size changes
this._dash = new Dash.Dash();
this._group.add_actor(this._dash.actor);
// Container to hold popup pane chrome.
this._paneContainer = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: 6
});
// Note here we explicitly don't set the paneContainer to be reactive yet; that's done
// inside the notify::visible handler on panes.
this._paneContainer.connect('button-release-event', Lang.bind(this, function(background) {
this._activeDisplayPane.close();
return true;
}));
this._group.add_actor(this._paneContainer);
this._transparentBackground.lower_bottom();
this._paneContainer.lower_bottom();
this._coverPane.lower_bottom();
this._workspaces = null;
},
_recalculateGridSizes: function () {
wideScreen = (global.screen_width/global.screen_height > WIDE_SCREEN_CUT_OFF_RATIO);
// We divide the screen into an imaginary grid which helps us determine the layout of
// different visual components.
if (wideScreen) {
displayGridColumnWidth = global.screen_width / COLUMNS_WIDE_SCREEN;
displayGridRowHeight = global.screen_height / ROWS_WIDE_SCREEN;
} else {
displayGridColumnWidth = global.screen_width / COLUMNS_REGULAR_SCREEN;
displayGridRowHeight = global.screen_height / ROWS_REGULAR_SCREEN;
}
},
relayout: function () {
let screenHeight = global.screen_height;
let screenWidth = global.screen_width;
let contentY = Panel.PANEL_HEIGHT;
let contentHeight = screenHeight - contentY;
this._coverPane.set_position(0, contentY);
this._coverPane.set_size(screenWidth, contentHeight);
let workspaceColumnsUsed = wideScreen ? COLUMNS_FOR_WORKSPACES_WIDE_SCREEN : COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN;
let workspaceRowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN;
this._workspacesWidth = displayGridColumnWidth * workspaceColumnsUsed
- WORKSPACE_GRID_PADDING * 2;
// We scale the vertical padding by (screenHeight / screenWidth)
// so that the workspace preserves its aspect ratio.
this._workspacesHeight = displayGridRowHeight * workspaceRowsUsed
- WORKSPACE_GRID_PADDING * (screenHeight / screenWidth) * 2;
this._workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
this._workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (screenHeight / screenWidth);
this._dash.actor.set_position(0, contentY);
this._dash.actor.set_size(displayGridColumnWidth, contentHeight);
this._dash.searchArea.height = this._workspacesY - contentY;
this._dash.sectionArea.height = this._workspacesHeight;
// place the 'Add Workspace' button in the bottom row of the grid
addRemoveButtonSize = Math.floor(displayGridRowHeight * 3/5);
this._addButtonX = this._workspacesX + this._workspacesWidth - addRemoveButtonSize;
this._addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5);
this._backOver.set_position(0, contentY);
this._backOver.set_size(global.screen_width, contentHeight);
this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING,
contentY);
// Dynamic width
this._paneContainer.height = contentHeight;
this._transparentBackground.set_position(this._paneContainer.x, this._paneContainer.y);
this._transparentBackground.set_size(global.screen_width - this._paneContainer.x,
this._paneContainer.height);
if (this._activeDisplayPane != null)
this._activeDisplayPane.actor.width = displayGridColumnWidth * 2;
},
addPane: function (pane) {
this._paneContainer.append(pane.actor, Big.BoxPackFlags.NONE);
// When a pane is displayed, we raise the transparent background to the top
// and connect to button-release-event on it, then raise the pane above that.
// The idea here is that clicking anywhere outside the pane should close it.
// When the active pane is closed, undo the effect.
let backgroundEventId = null;
pane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) {
if (isOpen) {
pane.actor.width = displayGridColumnWidth * 2;
this._activeDisplayPane = pane;
this._transparentBackground.raise_top();
this._paneContainer.raise_top();
if (backgroundEventId != null)
this._transparentBackground.disconnect(backgroundEventId);
backgroundEventId = this._transparentBackground.connect('button-release-event', Lang.bind(this, function () {
this._activeDisplayPane.close();
return true;
}));
} else if (pane == this._activeDisplayPane) {
this._activeDisplayPane = null;
if (backgroundEventId != null) {
this._transparentBackground.disconnect(backgroundEventId);
backgroundEventId = null;
}
this._transparentBackground.lower_bottom();
this._paneContainer.lower_bottom();
}
}));
},
//// Draggable target interface ////
// Closes any active panes if a GenericDisplayItem is being
// dragged over the Overview, i.e. as soon as it starts being dragged.
// This allows the user to place the item on any workspace.
handleDragOver : function(source, actor, x, y, time) {
if (source instanceof GenericDisplay.GenericDisplayItem
|| source instanceof AppDisplay.BaseWellItem) {
if (this._activeDisplayPane != null)
this._activeDisplayPane.close();
return true;
}
return false;
},
//// Public methods ////
// Returns the scale the Overview has when we just start zooming out
// to overview mode. That is, when just the active workspace is showing.
getZoomedInScale : function() {
return 1 / this._workspaces.getScale();
},
// Returns the position the Overview has when we just start zooming out
// to overview mode. That is, when just the active workspace is showing.
getZoomedInPosition : function() {
let [posX, posY] = this._workspaces.getActiveWorkspacePosition();
let scale = this.getZoomedInScale();
return [- posX * scale, - posY * scale];
},
// Returns the current scale of the Overview.
getScale : function() {
return this._group.scaleX;
},
// Returns the current position of the Overview.
getPosition : function() {
return [this._group.x, this._group.y];
},
show : function() {
if (this.visible)
return;
Main.pushModal(this._dash.actor);
this.visible = true;
this.animationInProgress = true;
this._dash.show();
/* TODO: make this stuff dynamic */
this._workspaces = new Workspaces.Workspaces(this._workspacesWidth, this._workspacesHeight,
this._workspacesX, this._workspacesY);
this._group.add_actor(this._workspaces.actor);
// The workspaces actor is as big as the screen, so we have to raise the dash above it
// for drag and drop to work. In the future we should fix the workspaces to not
// be as big as the screen.
this._dash.actor.raise(this._workspaces.actor);
// Create (+) button
this._addButton = new AddWorkspaceButton(addRemoveButtonSize, this._addButtonX, this._addButtonY, Lang.bind(this, this._acceptNewWorkspaceDrop));
this._addButton.actor.connect('button-release-event', Lang.bind(this, this._addNewWorkspace));
this._group.add_actor(this._addButton.actor);
this._addButton.actor.raise(this._workspaces.actor);
// All the the actors in the window group are completely obscured,
// hiding the group holding them while the Overview is displayed greatly
// increases performance of the Overview especially when there are many
// windows visible.
//
// If we switched to displaying the actors in the Overview rather than
// clones of them, this would obviously no longer be necessary.
global.window_group.hide();
this._group.show();
// Create a zoom out effect. First scale the Overview group up and
// position it so that the active workspace fills up the whole screen,
// then transform the group to its normal dimensions and position.
// The opposite transition is used in hide().
this._group.scaleX = this._group.scaleY = this.getZoomedInScale();
[this._group.x, this._group.y] = this.getZoomedInPosition();
Tweener.addTween(this._group,
{ x: 0,
y: 0,
scaleX: 1,
scaleY: 1,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
onComplete: this._showDone,
onCompleteScope: this
});
// Make Dash fade in so that it doesn't appear to big.
this._dash.actor.opacity = 0;
Tweener.addTween(this._dash.actor,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME
});
this._coverPane.raise_top();
this.emit('showing');
},
hide: function() {
if (!this.visible || this._hideInProgress)
return;
this.animationInProgress = true;
this._hideInProgress = true;
if (this._activeDisplayPane != null)
this._activeDisplayPane.close();
this._workspaces.hide();
// Create a zoom in effect by transforming the Overview group so that
// the active workspace fills up the whole screen. The opposite
// transition is used in show().
let scale = this.getZoomedInScale();
let [posX, posY] = this.getZoomedInPosition();
Tweener.addTween(this._group,
{ x: posX,
y: posY,
scaleX: scale,
scaleY: scale,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
onComplete: this._hideDone,
onCompleteScope: this
});
// Make Dash fade out so that it doesn't appear to big.
Tweener.addTween(this._dash.actor,
{ opacity: 0,
transition: 'easeOutQuad',
time: ANIMATION_TIME
});
this._coverPane.raise_top();
this.emit('hiding');
},
toggle: function() {
if (this.visible)
this.hide();
else
this.show();
},
/**
* getWorkspacesForWindow:
* @metaWindow: A #MetaWindow
*
* Returns the Workspaces object associated with the given window.
* This method is not be accessible if the overview is not open
* and will return %null.
*/
getWorkspacesForWindow: function(metaWindow) {
return this._workspaces;
},
/**
* activateWindow:
* @metaWindow: A #MetaWindow
* @time: Event timestamp integer
*
* Make the given MetaWindow be the focus window, switching
* to the workspace it's on if necessary. This function
* should only be used when the Overview is currently active;
* outside of that, use the relevant methods on MetaDisplay.
*/
activateWindow: function (metaWindow, time) {
this._workspaces.activateWindowFromOverview(metaWindow, time);
},
//// Private methods ////
_showDone: function() {
if (this._hideInProgress)
return;
this.animationInProgress = false;
this._coverPane.lower_bottom();
this.emit('shown');
},
_hideDone: function() {
global.window_group.show();
this._workspaces.destroy();
this._workspaces = null;
this._dash.hide();
this._group.hide();
this.visible = false;
this.animationInProgress = false;
this._hideInProgress = false;
this._coverPane.lower_bottom();
Main.popModal(this._dash.actor);
this.emit('hidden');
},
_addNewWorkspace: function() {
global.screen.append_new_workspace(false, global.screen.get_display().get_current_time());
},
_acceptNewWorkspaceDrop: function(source, dropActor, x, y, time) {
this._addNewWorkspace();
return this._workspaces.acceptNewWorkspaceDrop(source, dropActor, x, y, time);
}
};
Signals.addSignalMethods(Overview.prototype);
function AddWorkspaceButton(buttonSize, buttonX, buttonY, acceptDropCallback) {
this._init(buttonSize, buttonX, buttonY, acceptDropCallback);
}
AddWorkspaceButton.prototype = {
_init: function(buttonSize, buttonX, buttonY, acceptDropCallback) {
this.actor = new Clutter.Group({ x: buttonX,
y: buttonY,
width: global.screen_width - buttonX,
height: global.screen_height - buttonY,
reactive: true });
this.actor._delegate = this;
this._acceptDropCallback = acceptDropCallback;
let plus = new Clutter.Texture({ x: 0,
y: 0,
width: buttonSize,
height: buttonSize });
plus.set_from_file(global.imagedir + 'add-workspace.svg');
this.actor.add_actor(plus);
},
// Draggable target interface
acceptDrop: function(source, actor, x, y, time) {
return this._acceptDropCallback(source, actor, x, y, time);
}
};

View File

@ -7,35 +7,48 @@ const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Tweener = imports.ui.tweener;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Button = imports.ui.button;
const Main = imports.ui.main;
const PANEL_HEIGHT = 32;
const PANEL_HEIGHT = 26;
const TRAY_HEIGHT = PANEL_HEIGHT - 1;
const SHADOW_HEIGHT = 6;
// The panel has a transparent white background with a gradient.
const PANEL_TOP_COLOR = new Clutter.Color();
PANEL_TOP_COLOR.from_pixel(0xffffff99);
const PANEL_MIDDLE_COLOR = new Clutter.Color();
PANEL_MIDDLE_COLOR.from_pixel(0xffffff88);
const PANEL_BOTTOM_COLOR = new Clutter.Color();
PANEL_BOTTOM_COLOR.from_pixel(0xffffffaa);
const DEFAULT_PADDING = 4;
const PANEL_ICON_SIZE = 24;
const BACKGROUND_TOP = new Clutter.Color();
BACKGROUND_TOP.from_pixel(0x161616ff);
const BACKGROUND_BOTTOM = new Clutter.Color();
BACKGROUND_BOTTOM.from_pixel(0x000000ff);
const PANEL_FOREGROUND_COLOR = new Clutter.Color();
PANEL_FOREGROUND_COLOR.from_pixel(0xffffffff);
const SN_BACKGROUND_COLOR = new Clutter.Color();
SN_BACKGROUND_COLOR.from_pixel(0xffff00a0);
const SHADOW_COLOR = new Clutter.Color();
SHADOW_COLOR.from_pixel(0x00000033);
const TRANSPARENT_COLOR = new Clutter.Color();
TRANSPARENT_COLOR.from_pixel(0x00000000);
// Darken (pressed) buttons; lightening has no effect on white backgrounds.
// Don't make the mouse hover effect visible to the user for a menu feel.
const PANEL_BUTTON_COLOR = new Clutter.Color();
PANEL_BUTTON_COLOR.from_pixel(0x00000015);
PANEL_BUTTON_COLOR.from_pixel(0x00000000);
// Lighten pressed buttons; darkening has no effect on a black background.
const PRESSED_BUTTON_BACKGROUND_COLOR = new Clutter.Color();
PRESSED_BUTTON_BACKGROUND_COLOR.from_pixel(0x00000030);
PRESSED_BUTTON_BACKGROUND_COLOR.from_pixel(0x324c6ffa);
const DEFAULT_FONT = 'Sans 16px';
const TRAY_PADDING = 0;
const TRAY_SPACING = 2;
// See comments around _recomputeTraySize
const TRAY_SPACING = 14;
const TRAY_SPACING_MIN = 8;
// Used for the tray icon container with gtk pre-2.16, which doesn't
// fully support tray icon transparency
@ -46,84 +59,277 @@ TRAY_BORDER_COLOR.from_pixel(0x00000033);
const TRAY_CORNER_RADIUS = 5;
const TRAY_BORDER_WIDTH = 0;
function AppPanelMenu() {
this._init();
}
AppPanelMenu.prototype = {
_init: function() {
this._metaDisplay = global.screen.get_display();
this._focusedApp = null;
this._activeSequence = null;
this._startupSequences = {};
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: DEFAULT_PADDING,
y_align: Big.BoxAlignment.CENTER });
this._iconBox = new Big.Box({ width: PANEL_ICON_SIZE, height: PANEL_ICON_SIZE,
x_align: Big.BoxAlignment.CENTER,
y_align: Big.BoxAlignment.CENTER });
this.actor.append(this._iconBox, Big.BoxPackFlags.NONE);
let labelBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
y_align: Big.BoxAlignment.CENTER });
this._label = new Clutter.Text({ font_name: DEFAULT_FONT,
color: PANEL_FOREGROUND_COLOR,
text: "" });
labelBox.append(this._label, Big.BoxPackFlags.EXPAND);
this.actor.append(labelBox, Big.BoxPackFlags.NONE);
this._startupBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
y_align: Big.BoxAlignment.CENTER });
this.actor.append(this._startupBox, Big.BoxPackFlags.NONE);
Main.overview.connect('hiding', Lang.bind(this, function () {
this.actor.opacity = 255;
}));
Main.overview.connect('showing', Lang.bind(this, function () {
this.actor.opacity = 192;
}));
this._metaDisplay.connect('notify::focus-window', Lang.bind(this, this._sync));
let appMonitor = Shell.AppMonitor.get_default();
appMonitor.connect('startup-sequence-changed', Lang.bind(this, this._sync));
// For now just resync on application add/remove; this is mainly to handle
// cases where the focused window's application changes without the focus
// changing. An example case is how we map Firefox based on the window
// title which is a dynamic property.
appMonitor.connect('app-added', Lang.bind(this, this._sync));
appMonitor.connect('app-removed', Lang.bind(this, this._sync));
this._sync();
},
_sync: function() {
let appMonitor = Shell.AppMonitor.get_default();
let focusWindow = this._metaDisplay.get_focus_window();
let focusedApp;
if (focusWindow == null) {
focusedApp = null;
} else {
focusedApp = appMonitor.get_window_app(focusWindow);
}
let lastSequence = null;
if (focusedApp == null) {
let sequences = appMonitor.get_startup_sequences();
if (sequences.length > 0)
lastSequence = sequences[sequences.length - 1];
}
// If the currently focused app hasn't changed and the current
// startup sequence hasn't changed, we have nothing to do
if (focusedApp == this._focusedApp
&& ((lastSequence == null && this._activeSequence == null)
|| (lastSequence != null && this._activeSequence != null
&& lastSequence.get_id() == this._activeSequence.get_id())))
return;
this._focusedApp = focusedApp;
this._activeSequence = lastSequence;
this._iconBox.remove_all();
this._iconBox.hide();
this._label.text = '';
if (this._focusedApp != null) {
let icon = focusedApp.create_icon_texture(PANEL_ICON_SIZE);
this._iconBox.append(icon, Big.BoxPackFlags.NONE);
this._iconBox.show();
this._label.text = focusedApp.get_name();
} else if (this._activeSequence != null) {
let icon = this._activeSequence.create_icon(PANEL_ICON_SIZE);
this._iconBox.append(icon, Big.BoxPackFlags.NONE);
this._iconBox.show();
this._label.text = this._activeSequence.get_name();
}
this.emit('changed');
}
}
Signals.addSignalMethods(AppPanelMenu.prototype);
function Panel() {
this._init();
}
Panel.prototype = {
_init : function() {
let global = Shell.Global.get();
// Put the background under the panel within a group.
this.actor = new Clutter.Group();
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL
});
let backgroundGradient = Shell.create_vertical_gradient(BACKGROUND_TOP,
BACKGROUND_BOTTOM);
this.actor.connect('notify::allocation', Lang.bind(this, function () {
let [width, height] = this.actor.get_size();
backgroundGradient.set_size(width, height);
}));
this.actor.add_actor(backgroundGradient);
// Create backBox, which contains two boxes, backUpper and backLower,
// for the background gradients and one for the shadow. The shadow at
// the bottom has a fixed height (packing flag NONE), and the rest of
// the height above is divided evenly between backUpper and backLower
// (with packing flag EXPAND).
let backBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
x: 0,
y: 0,
width: global.screen_width,
height: PANEL_HEIGHT + SHADOW_HEIGHT });
let backUpper = global.create_vertical_gradient(PANEL_TOP_COLOR,
PANEL_MIDDLE_COLOR);
let backLower = global.create_vertical_gradient(PANEL_MIDDLE_COLOR,
PANEL_BOTTOM_COLOR);
let shadow = global.create_vertical_gradient(SHADOW_COLOR,
TRANSPARENT_COLOR);
shadow.set_height(SHADOW_HEIGHT + 1);
backBox.append(backUpper, Big.BoxPackFlags.EXPAND);
backBox.append(backLower, Big.BoxPackFlags.EXPAND);
backBox.append(shadow, Big.BoxPackFlags.NONE);
this.actor.add_actor(backBox);
this._leftBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
y_align: Big.BoxAlignment.CENTER,
spacing: DEFAULT_PADDING,
padding_right: DEFAULT_PADDING });
this._centerBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
y_align: Big.BoxAlignment.CENTER });
this._rightBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
y_align: Big.BoxAlignment.CENTER,
padding_left: DEFAULT_PADDING });
let box = new Big.Box({ x: 0,
y: 0,
height: PANEL_HEIGHT,
width: global.screen_width,
orientation: Big.BoxOrientation.HORIZONTAL,
spacing: 4 });
/* This box container ensures that the centerBox is positioned in the *absolute*
* center, but can be pushed aside if necessary. */
this._boxContainer = new Shell.GenericContainer();
this.actor.append(this._boxContainer, Big.BoxPackFlags.EXPAND);
this._boxContainer.add_actor(this._leftBox);
this._boxContainer.add_actor(this._centerBox);
this._boxContainer.add_actor(this._rightBox);
this._boxContainer.connect('get-preferred-width', Lang.bind(this, function(box, forHeight, alloc) {
let children = box.get_children();
for (let i = 0; i < children.length; i++) {
let [childMin, childNatural] = children[i].get_preferred_width(forHeight);
alloc.min_size += childMin;
alloc.natural_size += childNatural;
}
}));
this._boxContainer.connect('get-preferred-height', Lang.bind(this, function(box, forWidth, alloc) {
let children = box.get_children();
for (let i = 0; i < children.length; i++) {
let [childMin, childNatural] = children[i].get_preferred_height(forWidth);
if (childMin > alloc.min_size)
alloc.min_size = childMin;
if (childNatural > alloc.natural_size)
alloc.natural_size = childNatural;
}
}));
this._boxContainer.connect('allocate', Lang.bind(this, function(container, 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 leftWidth, centerWidth, rightWidth;
if (allocWidth < (leftNaturalWidth + centerNaturalWidth + rightNaturalWidth)) {
leftWidth = leftMinWidth;
centerWidth = centerMinWidth;
rightWidth = rightMinWidth;
} else {
leftWidth = leftNaturalWidth;
centerWidth = centerNaturalWidth;
rightWidth = rightNaturalWidth;
}
this.button = new Button.Button("Activities", PANEL_BUTTON_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR, true, null, PANEL_HEIGHT);
let x;
let childBox = new Clutter.ActorBox();
childBox.x1 = box.x1;
childBox.y1 = box.y1;
childBox.x2 = x = childBox.x1 + leftWidth;
childBox.y2 = box.y2;
this._leftBox.allocate(childBox, flags);
box.append(this.button.button, Big.BoxPackFlags.NONE);
let centerNaturalX = Math.floor((box.x2 - box.x1) / 2 - (centerWidth / 2));
/* Check left side */
if (x < centerNaturalX) {
/* We didn't overflow the left, use the natural. */
x = centerNaturalX;
}
/* Check right side */
if (x + centerWidth > (box.x2 - rightWidth)) {
x = box.x2 - rightWidth - centerWidth;
}
childBox = new Clutter.ActorBox();
childBox.x1 = x;
childBox.y1 = box.y1;
childBox.x2 = x = childBox.x1 + centerWidth;
childBox.y2 = box.y2;
this._centerBox.allocate(childBox, flags);
let statusbox = new Big.Box();
let statusmenu = this._statusmenu = new Shell.StatusMenu();
statusbox.append(this._statusmenu, Big.BoxPackFlags.NONE);
let statusbutton = new Button.Button(statusbox, PANEL_BUTTON_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR,
true, null, PANEL_HEIGHT);
statusbutton.button.connect('button-press-event', function (b, e) {
statusmenu.toggle(e);
return false;
});
box.append(statusbutton.button, Big.BoxPackFlags.END);
// We get a deactivated event when the popup disappears
this._statusmenu.connect('deactivated', function (sm) {
statusbutton.release();
});
childBox = new Clutter.ActorBox();
childBox.x1 = box.x2 - rightWidth;
childBox.y1 = box.y1;
childBox.x2 = box.x2;
childBox.y2 = box.y2;
this._rightBox.allocate(childBox, flags);
}));
this._clock = new Clutter.Text({ font_name: "Sans Bold 16px",
/* left side */
this.button = new Button.Button(_("Activities"), PANEL_BUTTON_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR,
PANEL_FOREGROUND_COLOR, DEFAULT_FONT);
this.button.actor.height = PANEL_HEIGHT;
this._leftBox.append(this.button.actor, Big.BoxPackFlags.NONE);
// We use this flag to mark the case where the user has entered the
// hot corner and has not left both the hot corner and a surrounding
// guard area (the "environs"). This avoids triggering the hot corner
// multiple times due to an accidental jitter.
this._hotCornerEntered = false;
this._hotCornerEnvirons = new Clutter.Rectangle({ width: 3,
height: 3,
opacity: 0,
reactive: true });
this._hotCorner = new Clutter.Rectangle({ width: 1,
height: 1,
opacity: 0,
reactive: true });
this._hotCornerEnvirons.connect('leave-event',
Lang.bind(this, this._onHotCornerEnvironsLeft));
// Clicking on the hot corner environs should result in the same bahavior
// as clicking on the hot corner.
this._hotCornerEnvirons.connect('button-release-event',
Lang.bind(this, this._onHotCornerClicked));
// In addition to being triggered by the mouse enter event, the hot corner
// can be triggered by clicking on it. This is useful if the user wants to
// undo the effect of triggering the hot corner once in the hot corner.
this._hotCorner.connect('enter-event',
Lang.bind(this, this._onHotCornerEntered));
this._hotCorner.connect('button-release-event',
Lang.bind(this, this._onHotCornerClicked));
this._hotCorner.connect('leave-event',
Lang.bind(this, this._onHotCornerLeft));
this._leftBox.append(this._hotCornerEnvirons, Big.BoxPackFlags.FIXED);
this._leftBox.append(this._hotCorner, Big.BoxPackFlags.FIXED);
let appMenu = new AppPanelMenu();
this._leftBox.append(appMenu.actor, Big.BoxPackFlags.NONE);
/* center */
this._clock = new Clutter.Text({ font_name: DEFAULT_FONT,
color: PANEL_FOREGROUND_COLOR,
text: "" });
let pad = (PANEL_HEIGHT - this._clock.height) / 2;
let clockbox = new Big.Box({ padding_top: pad,
padding_bottom: pad,
padding_left: 4,
padding_right: 4 });
clockbox.append(this._clock, Big.BoxPackFlags.NONE);
box.append(clockbox, Big.BoxPackFlags.END);
this._centerBox.append(this._clock, Big.BoxPackFlags.NONE);
/* right */
// The tray icons live in trayBox within trayContainer.
// The trayBox is hidden when there are no tray icons.
let trayContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
y_align: Big.BoxAlignment.START });
box.append(trayContainer, Big.BoxPackFlags.END);
this._rightBox.append(trayContainer, Big.BoxPackFlags.NONE);
let trayBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
height: TRAY_HEIGHT,
padding: TRAY_PADDING,
spacing: TRAY_SPACING });
this._trayBox = trayBox;
// gtk+ < 2.16 doesn't have fully-working icon transparency,
// so we want trayBox to be opaque in that case (the icons
@ -140,42 +346,100 @@ Panel.prototype = {
this._traymanager = new Shell.TrayManager({ bg_color: TRAY_BACKGROUND_COLOR });
this._traymanager.connect('tray-icon-added',
function(o, icon) {
Lang.bind(this, function(o, icon) {
trayBox.append(icon, Big.BoxPackFlags.NONE);
// Make sure the trayBox is shown.
trayBox.show();
});
this._recomputeTraySize();
}));
this._traymanager.connect('tray-icon-removed',
function(o, icon) {
Lang.bind(this, function(o, icon) {
trayBox.remove_actor(icon);
if (trayBox.get_children().length == 0)
trayBox.hide();
});
this._recomputeTraySize();
}));
this._traymanager.manage_stage(global.stage);
// TODO: decide what to do with the rest of the panel in the overlay mode (make it fade-out, become non-reactive, etc.)
// We get into the overlay mode on button-press-event as opposed to button-release-event because eventually we'll probably
// have the overlay act like a menu that allows the user to release the mouse on the activity the user wants
let statusbox = new Big.Box();
let statusmenu = this._statusmenu = new Shell.StatusMenu();
statusmenu.get_icon().hide();
statusmenu.get_name().fontName = DEFAULT_FONT;
statusmenu.get_name().color = PANEL_FOREGROUND_COLOR;
statusbox.append(this._statusmenu, Big.BoxPackFlags.NONE);
let statusbutton = new Button.Button(statusbox,
PANEL_BUTTON_COLOR,
PRESSED_BUTTON_BACKGROUND_COLOR,
PANEL_FOREGROUND_COLOR);
statusbutton.actor.height = PANEL_HEIGHT;
statusbutton.actor.connect('button-press-event', function (b, e) {
if (e.get_button() == 1 && e.get_click_count() == 1) {
statusmenu.toggle(e);
// The statusmenu might not pop up if it couldn't get a pointer grab
if (statusmenu.is_active())
statusbutton.actor.active = true;
return true;
} else {
return false;
}
});
this._rightBox.append(statusbutton.actor, Big.BoxPackFlags.NONE);
// We get a deactivated event when the popup disappears
this._statusmenu.connect('deactivated', function (sm) {
statusbutton.actor.active = false;
});
// TODO: decide what to do with the rest of the panel in the Overview mode (make it fade-out, become non-reactive, etc.)
// We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
// have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
// to switch to.
this.button.button.connect('button-press-event',
Lang.bind(Main.overlay, Main.overlay.toggle));
// In addition to pressing the button, the overlay can be entered and exited by other means, such as
// pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the overlay is entered
this.button.actor.connect('button-press-event', function(b, e) {
if (e.get_button() == 1 && e.get_click_count() == 1) {
Main.overview.toggle();
return true;
} else {
return false;
}
});
// In addition to pressing the button, the Overview can be entered and exited by other means, such as
// pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the Overview is entered
// and to be released when it is exited regardless of how it was triggered.
Main.overlay.connect('showing', Lang.bind(this.button, this.button.pressIn));
Main.overlay.connect('hiding', Lang.bind(this.button, this.button.release));
Main.overview.connect('showing', Lang.bind(this, function() {
this.button.actor.active = true;
}));
Main.overview.connect('hiding', Lang.bind(this, function() {
this.button.actor.active = false;
}));
this.actor.add_actor(box);
Main.chrome.addActor(this.actor, box);
Main.chrome.setVisibleInOverlay(this.actor, true);
Main.chrome.addActor(this.actor);
Main.chrome.setVisibleInOverview(this.actor, true);
// Start the clock
this._updateClock();
},
startupAnimation: function() {
this.actor.y = -this.actor.height;
Tweener.addTween(this.actor,
{ y: 0,
time: 0.2,
transition: "easeOutQuad"
});
},
// By default, tray icons have a spacing of TRAY_SPACING. However this
// starts to fail if we have too many as can sadly happen; just jump down
// to a spacing of 8 if we're over 6.
// http://bugzilla.gnome.org/show_bug.cgi?id=590495
_recomputeTraySize: function () {
if (this._trayBox.get_children().length > 6)
this._trayBox.spacing = TRAY_SPACING_MIN;
else
this._trayBox.spacing = TRAY_SPACING;
},
_updateClock: function() {
let displayDate = new Date();
let msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
@ -184,8 +448,40 @@ Panel.prototype = {
displayDate.setMinutes(displayDate.getMinutes() + 1);
msecRemaining += 60000;
}
this._clock.set_text(displayDate.toLocaleFormat("%a %b %e, %l:%M %p"));
/* Translators: This is a time format. */
this._clock.set_text(displayDate.toLocaleFormat(_("%a %l:%M %p")));
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClock));
return false;
},
_onHotCornerEntered : function() {
if (!this._hotCornerEntered) {
this._hotCornerEntered = true;
if (!Main.overview.animationInProgress) {
Main.overview.toggle();
}
}
return false;
},
_onHotCornerClicked : function() {
if (!Main.overview.animationInProgress) {
Main.overview.toggle();
}
return false;
},
_onHotCornerLeft : function(actor, event) {
if (event.get_related() != this._hotCornerEnvirons) {
this._hotCornerEntered = false;
}
return false;
},
_onHotCornerEnvironsLeft : function(actor, event) {
if (event.get_related() != this._hotCorner) {
this._hotCornerEntered = false;
}
return false;
}
};

278
js/ui/places.js Normal file
View File

@ -0,0 +1,278 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Pango = imports.gi.Pango;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const GenericDisplay = imports.ui.genericDisplay;
const PLACES_VSPACING = 8;
const PLACES_ICON_SIZE = 16;
/**
* An entry in the places menu.
* @name: String title
* @iconFactory: A JavaScript callback which will create an icon texture
* @onActivate: A JavaScript callback to launch the entry
*/
function PlaceDisplay(name, iconFactory, onActivate) {
this._init(name, iconFactory, onActivate);
}
PlaceDisplay.prototype = {
_init : function(name, iconFactory, onActivate) {
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
reactive: true,
spacing: 4 });
this.actor.connect('button-release-event', Lang.bind(this, function (b, e) {
onActivate(this);
Main.overview.hide();
}));
let text = new Clutter.Text({ font_name: "Sans 14px",
ellipsize: Pango.EllipsizeMode.END,
color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
text: name });
let iconBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
this._icon = iconFactory();
iconBox.append(this._icon, Big.BoxPackFlags.NONE);
this.actor.append(iconBox, Big.BoxPackFlags.NONE);
this.actor.append(text, Big.BoxPackFlags.EXPAND);
this._iconFactory = iconFactory;
this._onActivate = onActivate;
this.actor._delegate = this;
let draggable = DND.makeDraggable(this.actor);
},
getDragActorSource: function() {
return this._icon;
},
getDragActor: function(stageX, stageY) {
return this._iconFactory();
},
//// Drag and drop methods ////
shellWorkspaceLaunch : function() {
this._onActivate();
}
};
Signals.addSignalMethods(PlaceDisplay.prototype);
function Places() {
this._init();
}
Places.prototype = {
_init : function() {
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: 4 });
this._menuBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: PLACES_VSPACING });
this.actor.append(this._menuBox, Big.BoxPackFlags.EXPAND);
this._devBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: PLACES_VSPACING });
this._dirsBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: PLACES_VSPACING });
this.actor.append(this._dirsBox, Big.BoxPackFlags.EXPAND);
let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
let homeUri = homeFile.get_uri();
let homeLabel = Shell.util_get_label_for_uri (homeUri);
let homeIcon = Shell.util_get_icon_for_uri (homeUri);
let home = new PlaceDisplay(homeLabel,
function() {
return Shell.TextureCache.get_default().load_gicon(homeIcon, PLACES_ICON_SIZE);
},
function() {
Gio.app_info_launch_default_for_uri(homeUri, Main.createAppLaunchContext());
});
this._menuBox.append(home.actor, Big.BoxPackFlags.NONE);
/*
* Show devices, code more or less ported from nautilus-places-sidebar.c
*/
this._menuBox.append(this._devBox, Big.BoxPackFlags.NONE);
this._volumeMonitor = Gio.VolumeMonitor.get();
this._volumeMonitor.connect('volume-added', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('volume-removed',Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('volume-changed', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('mount-added', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('mount-changed', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
this._updateDevices();
let networkApp = null;
try {
networkApp = Shell.AppSystem.get_default().load_from_desktop_file('gnome-network-scheme.desktop');
} catch(e) {
try {
networkApp = Shell.AppSystem.get_default().load_from_desktop_file('network-scheme.desktop');
} catch(e) {
log("Cannot create \"Network\" item, .desktop file not found or corrupt.");
}
}
if (networkApp != null) {
let network = new PlaceDisplay(networkApp.get_name(),
function() {
return networkApp.create_icon_texture(PLACES_ICON_SIZE);
},
function () {
networkApp.launch();
});
this._menuBox.append(network.actor, Big.BoxPackFlags.NONE);
}
let connect = new PlaceDisplay('Connect to...',
function () {
return Shell.TextureCache.get_default().load_icon_name("applications-internet", PLACES_ICON_SIZE);
},
function () {
new Shell.Process({ args: ['nautilus-connect-server'] }).run();
});
this._menuBox.append(connect.actor, Big.BoxPackFlags.NONE);
this._bookmarksPath = GLib.build_filenamev([GLib.get_home_dir(), ".gtk-bookmarks"]);
this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
let monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
this._bookmarkTimeoutId = 0;
monitor.connect('changed', Lang.bind(this, function () {
if (this._bookmarkTimeoutId > 0)
return;
/* Defensive event compression */
this._bookmarkTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function () {
this._bookmarkTimeoutId = 0;
this._reloadBookmarks();
return false;
}));
}));
this._reloadBookmarks();
},
_reloadBookmarks: function() {
this._dirsBox.remove_all();
if (!GLib.file_test(this._bookmarksPath, GLib.FileTest.EXISTS))
return;
let [success, bookmarksContent, len] = GLib.file_get_contents(this._bookmarksPath);
if (!success)
return;
let bookmarks = bookmarksContent.split('\n');
let bookmarksToLabel = {};
let bookmarksOrder = [];
for (let i = 0; i < bookmarks.length; i++) {
let bookmarkLine = bookmarks[i];
let components = bookmarkLine.split(' ');
let bookmark = components[0];
if (bookmark in bookmarksToLabel)
continue;
let label = null;
if (components.length > 1)
label = components.slice(1).join(' ');
bookmarksToLabel[bookmark] = label;
bookmarksOrder.push(bookmark);
}
for (let i = 0; i < bookmarksOrder.length; i++) {
let bookmark = bookmarksOrder[i];
let label = bookmarksToLabel[bookmark];
let file = Gio.file_new_for_uri(bookmark);
if (!file.query_exists(null))
continue;
if (label == null)
label = Shell.util_get_label_for_uri(bookmark);
if (label == null)
continue;
let icon = Shell.util_get_icon_for_uri(bookmark);
let item = new PlaceDisplay(label,
function() {
return Shell.TextureCache.get_default().load_gicon(icon, PLACES_ICON_SIZE);
},
function() {
Gio.app_info_launch_default_for_uri(bookmark, Main.createAppLaunchContext());
});
this._dirsBox.append(item.actor, Big.BoxPackFlags.NONE);
}
},
_updateDevices: function() {
this._devBox.remove_all();
/* first go through all connected drives */
let drives = this._volumeMonitor.get_connected_drives();
for (let i = 0; i < drives.length; i++) {
let volumes = drives[i].get_volumes();
for(let j = 0; j < volumes.length; j++) {
let mount = volumes[j].get_mount();
if(mount != null) {
this._addMount(mount);
}
}
}
/* add all volumes that is not associated with a drive */
let volumes = this._volumeMonitor.get_volumes();
for(let i = 0; i < volumes.length; i++) {
if(volumes[i].get_drive() != null)
continue;
let mount = volumes[i].get_mount();
if(mount != null) {
this._addMount(mount);
}
}
/* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */
let mounts = this._volumeMonitor.get_mounts();
for(let i = 0; i < mounts.length; i++) {
if(mounts[i].is_shadowed())
continue;
if(mounts[i].get_volume())
continue;
this._addMount(mounts[i]);
}
},
_addMount: function(mount) {
let mountLabel = mount.get_name();
let mountIcon = mount.get_icon();
let root = mount.get_root();
let mountUri = root.get_uri();
let devItem = new PlaceDisplay(mountLabel,
function() {
return Shell.TextureCache.get_default().load_gicon(mountIcon, PLACES_ICON_SIZE);
},
function() {
Gio.app_info_launch_default_for_uri(mountUri, Main.createAppLaunchContext());
});
this._devBox.append(devItem.actor, Big.BoxPackFlags.NONE);
}
};
Signals.addSignalMethods(Places.prototype);

View File

@ -1,8 +1,15 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Main = imports.ui.main;
@ -15,8 +22,10 @@ BOX_BACKGROUND_COLOR.from_pixel(0x000000cc);
const BOX_TEXT_COLOR = new Clutter.Color();
BOX_TEXT_COLOR.from_pixel(0xffffffff);
const BOX_WIDTH = 320;
const BOX_HEIGHT = 56;
const DIALOG_WIDTH = 320;
const DIALOG_PADDING = 6;
const ICON_SIZE = 24;
const ICON_BOX_SIZE = 36;
function RunDialog() {
this._init();
@ -24,7 +33,33 @@ function RunDialog() {
RunDialog.prototype = {
_init : function() {
let global = Shell.Global.get();
this._isOpen = false;
let gconf = Shell.GConf.get_default();
gconf.connect('changed', Lang.bind(this, function (gconf, key) {
if (key == 'development_tools')
this._enableInternalCommands = gconf.get_bool('development_tools');
}));
this._enableInternalCommands = gconf.get_boolean('development_tools');
this._internalCommands = { 'lg':
Lang.bind(this, function() {
Main.createLookingGlass().open();
}),
'r': Lang.bind(this, function() {
global.reexec_self();
}),
// Developer brain backwards compatibility
'restart': Lang.bind(this, function() {
global.reexec_self();
}),
'debugexit': Lang.bind(this, function() {
Meta.exit(Meta.ExitCode.ERROR);
})
};
// All actors are inside _group. We create it initially
// hidden then show it in show()
@ -38,100 +73,139 @@ RunDialog.prototype = {
reactive: true });
this._group.add_actor(this._overlay);
let boxGroup = new Clutter.Group();
boxGroup.set_position((global.screen_width - BOX_WIDTH) / 2,
(global.screen_height - BOX_HEIGHT) / 2);
this._group.add_actor(boxGroup);
let boxH = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
x_align: Big.BoxAlignment.CENTER,
y_align: Big.BoxAlignment.CENTER,
width: global.screen_width,
height: global.screen_height });
let box = new Clutter.Rectangle({ color: BOX_BACKGROUND_COLOR,
reactive: false,
width: BOX_WIDTH,
height: BOX_HEIGHT,
border_width: 0 });
boxGroup.add_actor(box);
this._group.add_actor(boxH);
let boxV = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
y_align: Big.BoxAlignment.CENTER });
boxH.append(boxV, Big.BoxPackFlags.NONE);
let dialogBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
background_color: BOX_BACKGROUND_COLOR,
corner_radius: 4,
reactive: false,
padding: DIALOG_PADDING,
width: DIALOG_WIDTH });
boxH.append(dialogBox, Big.BoxPackFlags.NONE);
let label = new Clutter.Text({ color: BOX_TEXT_COLOR,
font_name: '18px Sans',
text: 'Please enter a command:' });
label.set_position(6, 6);
boxGroup.add_actor(label);
text: _("Please enter a command:") });
dialogBox.append(label, Big.BoxPackFlags.EXPAND);
this._entry = new Clutter.Text({ color: BOX_TEXT_COLOR,
font_name: '20px Sans Bold',
editable: true,
activatable: true,
singleLineMode: true,
text: '',
width: BOX_WIDTH - 12,
height: BOX_HEIGHT - 12 });
// TODO: Implement relative positioning using Tidy.
this._entry.set_position(6, 30);
boxGroup.add_actor(this._entry);
singleLineMode: true });
let me = this;
dialogBox.append(this._entry, Big.BoxPackFlags.EXPAND);
this._entry.connect('activate', function (o, e) {
me.hide();
me._run(o.get_text());
this._errorBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
padding_top: DIALOG_PADDING });
dialogBox.append(this._errorBox, Big.BoxPackFlags.EXPAND);
let iconBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
y_align: Big.BoxAlignment.CENTER,
x_align: Big.BoxAlignment.CENTER,
width: ICON_BOX_SIZE,
height: ICON_BOX_SIZE });
this._errorBox.append(iconBox, Big.BoxPackFlags.NONE);
this._commandError = false;
let errorIcon = Shell.TextureCache.get_default().load_icon_name("gtk-dialog-error", ICON_SIZE);
iconBox.append(errorIcon, Big.BoxPackFlags.EXPAND);
this._errorMessage = new Clutter.Text({ color: BOX_TEXT_COLOR,
font_name: '18px Sans Bold',
line_wrap: true });
this._errorBox.append(this._errorMessage, Big.BoxPackFlags.EXPAND);
this._errorBox.hide();
this._entry.connect('activate', Lang.bind(this, function (o, e) {
this._run(o.get_text());
if (!this._commandError)
this.close();
}));
this._entry.connect('key-press-event', Lang.bind(this, function(o, e) {
let symbol = e.get_key_symbol();
if (symbol == Clutter.Escape) {
this.close();
return true;
}
return false;
});
}));
},
_run : function(command) {
if (command == 'restart') {
let global = Shell.Global.get();
global.reexec_self();
let f;
if (this._enableInternalCommands)
f = this._internalCommands[command];
else
f = null;
if (f) {
f();
} else if (command) {
var p = new Shell.Process({'args' : [command]});
try {
this._commandError = false;
let [ok, len, args] = GLib.shell_parse_argv(command);
let p = new Shell.Process({'args' : args});
p.run();
} catch (e) {
// TODO: Give the user direct feedback.
log('Could not run command ' + command + '.');
this._commandError = true;
/*
* The exception contains an error string like:
* Error invoking Shell.run: Failed to execute child process "foo"
* (No such file or directory)
* We are only interested in the actual error, so parse that out.
*/
let m = /.+\((.+)\)/.exec(e);
let errorStr = "Execution of '" + command + "' failed:\n" + m[1];
this._errorMessage.set_text(errorStr);
this._errorBox.show();
}
}
this.emit('run');
},
show : function() {
let me = this;
if (this._group.visible) // Already shown
return false;
if (!Main.startModal())
return false;
this._group.show_all();
this._entry.connect('key-press-event', function(o, e) {
if (Shell.get_event_key_symbol(e) == Clutter.Escape) {
me.hide();
me.emit('cancel');
return true;
} else
return false;
});
let global = Shell.Global.get();
global.stage.set_key_focus(this._entry);
return true;
},
hide : function() {
if (!this._group.visible)
open : function() {
if (this._isOpen) // Already shown
return;
this._group.hide();
Main.endModal();
this._isOpen = true;
this._group.show();
Main.pushModal(this._group);
global.stage.set_key_focus(this._entry);
},
destroy : function(){
this.hide();
this._group.destroy();
close : function() {
if (!this._isOpen)
return;
this._isOpen = false;
this._errorBox.hide();
this._commandError = false;
this._group.hide();
this._entry.text = '';
Main.popModal(this._group);
}
};
Signals.addSignalMethods(RunDialog.prototype);

View File

@ -14,24 +14,12 @@ const WidgetBox = imports.ui.widgetBox;
const SIDEBAR_SPACING = 4;
const SIDEBAR_PADDING = 4;
// The total sidebar width is the widget width plus the widget
// padding, plus the sidebar padding
const SIDEBAR_COLLAPSED_WIDTH = Widget.COLLAPSED_WIDTH + 2 * WidgetBox.WIDGETBOX_PADDING + 2 * SIDEBAR_PADDING;
const SIDEBAR_EXPANDED_WIDTH = Widget.EXPANDED_WIDTH + 2 * WidgetBox.WIDGETBOX_PADDING + 2 * SIDEBAR_PADDING;
// The maximum height of the sidebar would be extending from just
// below the panel to just above the taskbar. Since the taskbar is
// just a temporary hack and it would be too hard to do this the right
// way, we just hardcode its size.
const HARDCODED_TASKBAR_HEIGHT = 24;
const MAXIMUM_SIDEBAR_HEIGHT = Shell.Global.get().screen_height - Panel.PANEL_HEIGHT - HARDCODED_TASKBAR_HEIGHT;
// FIXME, needs to be configurable, obviously
const default_widgets = [
"imports.ui.widget.ClockWidget",
"imports.ui.widget.AppsWidget",
"imports.ui.widget.DocsWidget"
];
// The total sidebar width is the widget width plus the widget padding
// (counted twice for the widget box, and once again for the
// out-of-screen padding), plus the empty space between the border of
// the bar and of the windows
const SIDEBAR_COLLAPSED_WIDTH = Widget.COLLAPSED_WIDTH + 3 * WidgetBox.WIDGETBOX_PADDING + SIDEBAR_PADDING;
const SIDEBAR_EXPANDED_WIDTH = Widget.EXPANDED_WIDTH + 3 * WidgetBox.WIDGETBOX_PADDING + SIDEBAR_PADDING;
function Sidebar() {
this._init();
@ -39,8 +27,6 @@ function Sidebar() {
Sidebar.prototype = {
_init : function() {
let global = Shell.Global.get();
// The top-left corner of the sidebar is fixed at:
// x = -WidgetBox.WIDGETBOX_PADDING, y = Panel.PANEL_HEIGHT.
// (The negative X is so that we don't see the rounded
@ -48,7 +34,6 @@ Sidebar.prototype = {
this.actor = new Clutter.Group({ x: -WidgetBox.WIDGETBOX_PADDING,
y: Panel.PANEL_HEIGHT,
width: SIDEBAR_EXPANDED_WIDTH });
Main.chrome.addActor(this.actor);
// The actual widgets go into a Big.Box inside this.actor. The
// box's width will vary during the expand/collapse animations,
@ -58,23 +43,38 @@ Sidebar.prototype = {
// during the animation.
this.box = new Big.Box ({ padding_top: SIDEBAR_PADDING,
padding_bottom: SIDEBAR_PADDING,
padding_right: SIDEBAR_PADDING,
padding_right: 0,
padding_left: 0,
spacing: SIDEBAR_SPACING });
this.actor.add_actor(this.box);
this._visible = this.expanded = true;
this._gconf = Shell.GConf.get_default();
this._expanded = this._gconf.get_boolean ("sidebar/expanded");
if (!this._expanded)
this.actor.width = SIDEBAR_COLLAPSED_WIDTH;
this._visible = this._gconf.get_boolean ("sidebar/visible");
if (this._visible)
Main.chrome.addActor(this.actor);
this._widgets = [];
this.addWidget(new ToggleWidget(this));
this.addWidget(new ToggleWidget());
let default_widgets = this._gconf.get_string_list("sidebar/widgets");
for (let i = 0; i < default_widgets.length; i++)
this.addWidget(default_widgets[i]);
this._gconf.connect('changed::sidebar/expanded',
Lang.bind(this, this._expandedChanged));
this._gconf.connect('changed::sidebar/visible',
Lang.bind(this, this._visibleChanged));
},
addWidget: function(widget) {
let widgetBox;
try {
widgetBox = new WidgetBox.WidgetBox(widget);
widgetBox = new WidgetBox.WidgetBox(widget, this._expanded);
} catch(e) {
logError(e, "Failed to add widget '" + widget + "'");
return;
@ -84,18 +84,32 @@ Sidebar.prototype = {
this._widgets.push(widgetBox);
},
show: function() {
this._visible = true;
this.actor.show();
_visibleChanged: function() {
let visible = this._gconf.get_boolean("sidebar/visible");
if (visible == this._visible)
return;
this._visible = visible;
if (visible)
Main.chrome.addActor(this.actor);
else
Main.chrome.removeActor(this.actor);
},
hide: function() {
this._visible = false;
this.actor.hide();
_expandedChanged: function() {
let expanded = this._gconf.get_boolean("sidebar/expanded");
if (expanded == this._expanded)
return;
this._expanded = expanded;
if (expanded)
this._expand();
else
this._collapse();
},
expand: function() {
this.expanded = true;
_expand: function() {
this._expanded = true;
for (let i = 0; i < this._widgets.length; i++)
this._widgets[i].expand();
@ -106,8 +120,8 @@ Sidebar.prototype = {
} });
},
collapse: function() {
this.expanded = false;
_collapse: function() {
this._expanded = false;
for (let i = 0; i < this._widgets.length; i++)
this._widgets[i].collapse();
@ -130,24 +144,33 @@ Sidebar.prototype = {
const LEFT_DOUBLE_ARROW = "\u00AB";
const RIGHT_DOUBLE_ARROW = "\u00BB";
function ToggleWidget(sidebar) {
this._init(sidebar);
function ToggleWidget() {
this._init();
}
ToggleWidget.prototype = {
__proto__ : Widget.Widget.prototype,
_init : function(sidebar) {
this._sidebar = sidebar;
_init : function() {
this._gconf = Shell.GConf.get_default();
this.actor = new Clutter.Text({ font_name: "Sans Bold 16px",
text: LEFT_DOUBLE_ARROW,
reactive: true });
this.actor.connect('button-release-event',
Lang.bind(this._sidebar, this._sidebar.collapse));
Lang.bind(this, this._collapse));
this.collapsedActor = new Clutter.Text({ font_name: "Sans Bold 16px",
text: RIGHT_DOUBLE_ARROW,
reactive: true });
this.collapsedActor.connect('button-release-event',
Lang.bind(this._sidebar, this._sidebar.expand));
Lang.bind(this, this._expand));
},
_collapse : function () {
this._gconf.set_boolean ("sidebar/expanded", false);
},
_expand : function () {
this._gconf.set_boolean ("sidebar/expanded", true);
}
};

View File

@ -1,6 +1,7 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
@ -41,9 +42,17 @@ const Tweener = imports.tweener.tweener;
// calls any of these is almost certainly wrong anyway, because they
// affect the entire application.)
let slowDownFactor = 1.0;
// Called from Main.start
function init() {
let slowdownEnv = GLib.getenv("GNOME_SHELL_SLOWDOWN_FACTOR");
if (slowdownEnv) {
let factor = parseFloat(slowdownEnv);
if (!isNaN(factor) && factor > 0.0)
slowDownFactor = factor;
}
Tweener.setFrameTicker(new ClutterFrameTicker());
}
@ -208,11 +217,10 @@ ClutterFrameTicker.prototype = {
this._startTime = -1;
this._currentTime = -1;
let me = this;
this._timeline.connect('new-frame',
this._timeline.connect('new-frame', Lang.bind(this,
function(timeline, frame) {
me._onNewFrame(frame);
});
this._onNewFrame(frame);
}));
},
_onNewFrame : function(frame) {
@ -225,7 +233,7 @@ ClutterFrameTicker.prototype = {
this._startTime = this._timeline.get_elapsed_time();
// currentTime is in milliseconds
this._currentTime = this._timeline.get_elapsed_time() - this._startTime;
this._currentTime = (this._timeline.get_elapsed_time() - this._startTime) / slowDownFactor;
this.emit('prepare-frame');
},

View File

@ -9,9 +9,9 @@ const Lang = imports.lang;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const AppInfo = imports.misc.appInfo;
const DocDisplay = imports.ui.docDisplay;
const DocInfo = imports.misc.docInfo;
const COLLAPSED_WIDTH = 24;
@ -31,12 +31,22 @@ function Widget() {
Widget.prototype = {
// _init():
//
// Your widget constructor. Receives no arguments. Must define a
// field named "actor" containing the Clutter.Actor to show in
// expanded mode. This actor will be clipped to
// Widget.EXPANDED_WIDTH. Most widgets will also define a field
// named "title" containing the title string to show above the
// widget in the sidebar.
// Your widget constructor. Your constructor function should look
// like:
//
// function MyWidgetType() {
// this._init.apply(this, arguments);
// }
//
// and your _init method should start by doing:
//
// Widget.Widget.prototype._init.apply(this, arguments);
//
// The _init method must define a field named "actor" containing
// the Clutter.Actor to show in expanded mode. This actor will be
// clipped to Widget.EXPANDED_WIDTH. Most widgets will also define
// a field named "title" containing the title string to show above
// the widget in the sidebar.
//
// If you want to have a separate collapsed view, you can define a
// field "collapsedActor" containing the Clutter.Actor to show in
@ -51,6 +61,9 @@ Widget.prototype = {
// the sidebar is collapsed, the widget's expanded view will pop
// out of the sidebar until either the cursor moves out of it,
// or else the widget calls this.activated() on itself.
_init: function (initialState) {
this.state = initialState;
},
// destroy():
//
@ -81,23 +94,22 @@ Widget.prototype = {
// state:
//
// A field set on your widget by the sidebar. Will contain one of
// the Widget.STATE_* values. (Eg, Widget.STATE_EXPANDED). Note
// that this will not be set until *after* _init() is called, so
// you cannot rely on it being set at that point. The widget will
// always initially be in STATE_EXPANDED.
// the Widget.STATE_* values. (Eg, Widget.STATE_EXPANDED).
};
Signals.addSignalMethods(Widget.prototype);
function ClockWidget() {
this._init();
this._init.apply(this, arguments);
}
ClockWidget.prototype = {
__proto__ : Widget.prototype,
_init: function() {
Widget.prototype._init.apply(this, arguments);
this.actor = new Clutter.Text({ font_name: "Sans Bold 16px",
text: "",
// Give an explicit height to ensure
@ -146,14 +158,14 @@ ClockWidget.prototype = {
},
_updateText: function(time) {
this.actor.set_text(time.toLocaleFormat("%H:%M"));
// Translators: This is a time format.
this.actor.set_text(time.toLocaleFormat(_("%H:%M")));
},
_updateCairo: function(time) {
let global = Shell.Global.get();
global.clutter_cairo_texture_draw_clock(this.collapsedActor,
time.getHours() % 12,
time.getMinutes());
Shell.draw_clock(this.collapsedActor,
time.getHours() % 12,
time.getMinutes());
}
};
@ -168,7 +180,7 @@ const ITEM_NAME_COLOR = new Clutter.Color();
ITEM_NAME_COLOR.from_pixel(0x000000ff);
function LauncherWidget() {
this._init();
this._init.apply(this, arguments);
}
LauncherWidget.prototype = {
@ -182,7 +194,7 @@ LauncherWidget.prototype = {
spacing: ITEM_SPACING,
reactive: true });
item._info = info;
item.append(info.getIcon(ITEM_ICON_SIZE), Big.BoxPackFlags.NONE);
item.append(info.createIcon(ITEM_ICON_SIZE), Big.BoxPackFlags.NONE);
item.append(new Clutter.Text({ color: ITEM_NAME_COLOR,
font_name: "Sans 14px",
ellipsize: Pango.EllipsizeMode.END,
@ -203,7 +215,7 @@ LauncherWidget.prototype = {
padding: ITEM_PADDING,
reactive: true });
item._info = info;
item.append(info.getIcon(COLLAPSED_WIDTH - 2 * ITEM_PADDING),
item.append(info.createIcon(COLLAPSED_WIDTH - 2 * ITEM_PADDING),
Big.BoxPackFlags.NONE);
this.collapsedActor.append(item, Big.BoxPackFlags.NONE);
@ -272,33 +284,61 @@ LauncherWidget.prototype = {
}
};
function AppsWidgetInfo(appInfo) {
this._init(appInfo);
}
AppsWidgetInfo.prototype = {
_init : function(appInfo) {
this._info = appInfo;
this.name = appInfo.get_name();
},
createIcon : function(size) {
return this._info.create_icon_texture(size);
},
launch : function() {
this._info.launch();
}
}
function AppsWidget() {
this._init();
this._init.apply(this, arguments);
}
AppsWidget.prototype = {
__proto__ : LauncherWidget.prototype,
_init : function() {
this.title = "Applications";
Widget.prototype._init.apply(this, arguments);
this.title = _("Applications");
this.actor = new Big.Box({ spacing: 2 });
this.collapsedActor = new Big.Box({ spacing: 2});
let apps = AppInfo.getMostUsedApps(5);
for (let i = 0; i < apps.length; i++)
this.addItem(apps[i]);
let appSystem = Shell.AppSystem.get_default();
let apps = appSystem.get_favorites();
for (let i = 0; i < apps.length; i++) {
let app = appSystem.lookup_cached_app(apps[i]);
if (!app)
continue;
this.addItem(new AppsWidgetInfo(app));
}
}
};
function DocsWidget() {
this._init();
function RecentDocsWidget() {
this._init.apply(this, arguments);
}
DocsWidget.prototype = {
RecentDocsWidget.prototype = {
__proto__ : LauncherWidget.prototype,
_init : function() {
this.title = "Recent Docs";
Widget.prototype._init.apply(this, arguments);
this.title = _("Recent Documents");
this.actor = new Big.Box({ spacing: 2 });
this._recentManager = Gtk.RecentManager.get_default();
@ -320,7 +360,7 @@ DocsWidget.prototype = {
items.push(docInfo);
}
items.sort(function (a,b) { return b.lastVisited() - a.lastVisited(); });
items.sort(function (a,b) { return b.timestamp - a.timestamp; });
for (i = 0; i < Math.min(items.length, 5); i++)
this.addItem(items[i]);
}

View File

@ -15,21 +15,24 @@ WIDGETBOX_BG_COLOR.from_pixel(0xf0f0f0ff);
const BLACK = new Clutter.Color();
BLACK.from_pixel(0x000000ff);
const WIDGETBOX_PADDING = 4;
const WIDGETBOX_PADDING = 2;
const ANIMATION_TIME = 0.5;
const POP_IN_LAG = 250; /* milliseconds */
function WidgetBox(widget) {
this._init(widget);
function WidgetBox(widget, expanded) {
this._init(widget, expanded);
}
WidgetBox.prototype = {
_init: function(widget) {
if (widget instanceof Widget.Widget)
_init: function(widget, expanded) {
this.state = expanded ? Widget.STATE_EXPANDED : Widget.STATE_COLLAPSED;
if (widget instanceof Widget.Widget) {
this._widget = widget;
else {
this._widget.state = this.state;
} else {
let ctor = this._ctorFromName(widget);
this._widget = new ctor();
this._widget = new ctor(this.state);
}
if (!this._widget.actor)
@ -37,7 +40,7 @@ WidgetBox.prototype = {
else if (!this._widget.title && !this._widget.collapsedActor)
throw new Error("widget has neither title nor collapsedActor");
this.state = this._widget.state = Widget.STATE_EXPANDED;
this.state = expanded ? Widget.STATE_EXPANDED : Widget.STATE_COLLAPSED;
// The structure of a WidgetBox:
//
@ -77,9 +80,15 @@ WidgetBox.prototype = {
this.actor = new Clutter.Group();
this._hbox = new Big.Box({ background_color: WIDGETBOX_BG_COLOR,
padding: WIDGETBOX_PADDING,
padding_top: WIDGETBOX_PADDING,
padding_bottom: WIDGETBOX_PADDING,
padding_right: WIDGETBOX_PADDING,
// Left padding is here to make up for
// the X offset used for the sidebar
// to hide its rounded corners
padding_left: 2 * WIDGETBOX_PADDING,
spacing: WIDGETBOX_PADDING,
corner_radius: WIDGETBOX_PADDING / 2,
corner_radius: WIDGETBOX_PADDING,
orientation: Big.BoxOrientation.HORIZONTAL,
reactive: true });
this.actor.add_actor(this._hbox);
@ -122,7 +131,6 @@ WidgetBox.prototype = {
this._activationHandler = this._widget.connect('activated',
Lang.bind(this, this._activationHandler));
}
this._cgroup.hide();
this._egroup = new Clutter.Group({ clip_to_allocation: true });
this._hbox.append(this._egroup, Big.BoxPackFlags.NONE);
@ -142,6 +150,11 @@ WidgetBox.prototype = {
}
this._ebox.append(this._widget.actor, Big.BoxPackFlags.NONE);
if (expanded)
this._setWidgetExpanded();
else
this._setWidgetCollapsed();
},
// Given a name like "imports.ui.widget.ClockWidget", turn that
@ -178,16 +191,25 @@ WidgetBox.prototype = {
this.state = this._widget.state = Widget.STATE_EXPANDING;
},
_expandPart1Complete: function() {
_setWidgetExpanded: function() {
this._cgroup.hide();
this._cbox.x = 0;
this._egroup.show();
if (this._singleActor) {
log(this._widget.actor);
this._widget.actor.unparent();
this._ebox.append(this._widget.actor, Big.BoxPackFlags.NONE);
}
if (this._htitle) {
this._htitle.show();
this._hline.show();
}
},
_expandPart1Complete: function() {
this._cbox.x = 0;
this._setWidgetExpanded();
if (this._widget.expand) {
try {
this._widget.expand();
@ -196,11 +218,6 @@ WidgetBox.prototype = {
}
}
this._egroup.show();
if (this._htitle) {
this._htitle.show();
this._hline.show();
}
this._ebox.x = -Widget.EXPANDED_WIDTH;
Tweener.addTween(this._ebox, { x: 0,
time: ANIMATION_TIME / 2,
@ -222,19 +239,27 @@ WidgetBox.prototype = {
this.state = this._widget.state = Widget.STATE_COLLAPSING;
},
_collapsePart1Complete: function() {
_setWidgetCollapsed: function() {
this._egroup.hide();
this._ebox.x = 0;
this._cgroup.show();
if (this._singleActor) {
this._widget.actor.unparent();
this._cbox.append(this._widget.actor, Big.BoxPackFlags.NONE);
}
if (this._htitle) {
this._htitle.hide();
this._hline.hide();
}
if (this._singleActor) {
log(this._widget.actor);
this._widget.actor.unparent();
this._cbox.append(this._widget.actor, Big.BoxPackFlags.NONE);
}
if (this._vtitle)
this._cbox.height = this._ebox.height;
},
_collapsePart1Complete: function() {
this._ebox.x = 0;
this._setWidgetCollapsed();
if (this._widget.collapse) {
try {
@ -244,10 +269,7 @@ WidgetBox.prototype = {
}
}
this._cgroup.show();
this._cbox.x = -Widget.COLLAPSED_WIDTH;
if (this._vtitle)
this._cbox.height = this._ebox.height;
Tweener.addTween(this._cbox, { x: 0,
time: ANIMATION_TIME / 2,
transition: "easeOutQuad",
@ -274,7 +296,7 @@ WidgetBox.prototype = {
this.state == Widget.STATE_POPPING_OUT)) {
// If moving into another actor within this._hbox, let the
// event be propagated
let into = Shell.get_event_related(event);
let into = event.get_related();
while (into) {
if (into == this._hbox)
return false;

View File

@ -1,9 +1,9 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const AltTab = imports.ui.altTab;
const Main = imports.ui.main;
@ -17,10 +17,8 @@ function WindowManager() {
WindowManager.prototype = {
_init : function() {
let me = this;
let shellwm = global.window_manager;
this._global = Shell.Global.get();
this._shellwm = this._global.window_manager;
this._minimizing = [];
this._maximizing = [];
this._unmaximizing = [];
@ -28,64 +26,24 @@ WindowManager.prototype = {
this._destroying = [];
this._switchData = null;
this._shellwm.connect('switch-workspace',
function(o, from, to, direction) {
let actors = me._shellwm.get_switch_workspace_actors();
me._switchWorkspace(actors, from, to, direction);
});
this._shellwm.connect('kill-switch-workspace',
function(o) {
me._switchWorkspaceDone();
});
this._shellwm.connect('minimize',
function(o, actor) {
me._minimizeWindow(actor);
});
this._shellwm.connect('kill-minimize',
function(o, actor) {
me._minimizeWindowDone(actor);
});
this._shellwm.connect('maximize',
function(o, actor, tx, ty, tw, th) {
me._maximizeWindow(actor, tx, ty, tw, th);
});
this._shellwm.connect('kill-maximize',
function(o, actor) {
me._maximizeWindowDone(actor);
});
this._shellwm.connect('unmaximize',
function(o, actor, tx, ty, tw, th) {
me._unmaximizeWindow(actor, tx, ty, tw, th);
});
this._shellwm.connect('kill-unmaximize',
function(o, actor) {
me._unmaximizeWindowDone(actor);
});
this._shellwm.connect('map',
function(o, actor) {
me._mapWindow(actor);
});
this._shellwm.connect('kill-map',
function(o, actor) {
me._mapWindowDone(actor);
});
this._shellwm.connect('destroy',
function(o, actor) {
me._destroyWindow(actor);
});
this._shellwm.connect('kill-destroy',
function(o, actor) {
me._destroyWindowDone(actor);
});
shellwm.connect('switch-workspace', Lang.bind(this, this._switchWorkspace));
shellwm.connect('kill-switch-workspace', Lang.bind(this, this._switchWorkspaceDone));
shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
shellwm.connect('kill-minimize', Lang.bind(this, this._minimizeWindowDone));
shellwm.connect('maximize', Lang.bind(this, this._maximizeWindow));
shellwm.connect('kill-maximize', Lang.bind(this, this._maximizeWindowDone));
shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
shellwm.connect('kill-unmaximize', Lang.bind(this, this._unmaximizeWindowDone));
shellwm.connect('map', Lang.bind(this, this._mapWindow));
shellwm.connect('kill-map', Lang.bind(this, this._mapWindowDone));
shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
shellwm.connect('kill-destroy', Lang.bind(this, this._destroyWindowDone));
this._shellwm.connect('begin-alt-tab',
function(o, handler) {
me._beginAltTab(handler);
});
shellwm.connect('begin-alt-tab', Lang.bind(this, this._beginAltTab));
},
_shouldAnimate : function(actor) {
if (Main.overlay.visible)
if (Main.overview.visible)
return false;
if (actor && (actor.get_window_type() != Meta.CompWindowType.NORMAL))
return false;
@ -101,9 +59,9 @@ WindowManager.prototype = {
return false;
},
_minimizeWindow : function(actor) {
_minimizeWindow : function(shellwm, actor) {
if (!this._shouldAnimate(actor)) {
this._shellwm.completed_minimize(actor);
shellwm.completed_minimize(actor);
return;
}
@ -121,86 +79,49 @@ WindowManager.prototype = {
transition: "easeOutQuad",
onComplete: this._minimizeWindowDone,
onCompleteScope: this,
onCompleteParams: [actor],
onCompleteParams: [shellwm, actor],
onOverwrite: this._minimizeWindowOverwritten,
onOverwriteScope: this,
onOverwriteParams: [actor]
onOverwriteParams: [shellwm, actor]
});
},
_minimizeWindowDone : function(actor) {
_minimizeWindowDone : function(shellwm, actor) {
if (this._removeEffect(this._minimizing, actor)) {
Tweener.removeTweens(actor);
actor.set_scale(1.0, 1.0);
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
this._shellwm.completed_minimize(actor);
shellwm.completed_minimize(actor);
}
},
_minimizeWindowOverwritten : function(actor) {
_minimizeWindowOverwritten : function(shellwm, actor) {
if (this._removeEffect(this._minimizing, actor)) {
this._shellwm.completed_minimize(actor);
shellwm.completed_minimize(actor);
}
},
_maximizeWindow : function(actor, targetX, targetY, targetWidth, targetHeight) {
_maximizeWindow : function(shellwm, actor, targetX, targetY, targetWidth, targetHeight) {
shellwm.completed_maximize(actor);
},
_maximizeWindowDone : function(shellwm, actor) {
},
_maximizeWindowOverwrite : function(shellwm, actor) {
},
_unmaximizeWindow : function(shellwm, actor, targetX, targetY, targetWidth, targetHeight) {
shellwm.completed_unmaximize(actor);
},
_unmaximizeWindowDone : function(shellwm, actor) {
},
_mapWindow : function(shellwm, actor) {
if (!this._shouldAnimate(actor)) {
this._shellwm.completed_maximize(actor);
return;
}
/* this doesn't work very well, as simply scaling up the existing
* window contents doesn't produce anything like the same results as
* actually maximizing the window.
*/
let scaleX = targetWidth / actor.width;
let scaleY = targetHeight / actor.height;
let anchorX = (actor.x - targetX) * actor.width/(targetWidth - actor.width);
let anchorY = (actor.y - targetY) * actor.height/(targetHeight - actor.height);
actor.move_anchor_point(anchorX, anchorY);
this._maximizing.push(actor);
Tweener.addTween(actor,
{ scale_x: scaleX,
scale_y: scaleY,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._maximizeWindowDone,
onCompleteScope: this,
onCompleteParams: [actor],
onOverwrite: this._maximizeWindowOverwrite,
onOverwriteScope: this,
onOverwriteParams: [actor]
});
},
_maximizeWindowDone : function(actor) {
if (this._removeEffect(this._maximizing, actor)) {
Tweener.removeTweens(actor);
actor.set_scale(1.0, 1.0);
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
this._shellwm.completed_maximize(actor);
}
},
_maximizeWindowOverwrite : function(actor) {
if (this._removeEffect(this._maximizing, actor)) {
this._shellwm.completed_maximize(actor);
}
},
_unmaximizeWindow : function(actor, targetX, targetY, targetWidth, targetHeight) {
this._shellwm.completed_unmaximize(actor);
},
_unmaximizeWindowDone : function(actor) {
},
_mapWindow : function(actor) {
if (!this._shouldAnimate(actor)) {
this._shellwm.completed_map(actor);
shellwm.completed_map(actor);
return;
}
@ -217,31 +138,31 @@ WindowManager.prototype = {
transition: "easeOutQuad",
onComplete: this._mapWindowDone,
onCompleteScope: this,
onCompleteParams: [actor],
onCompleteParams: [shellwm, actor],
onOverwrite: this._mapWindowOverwrite,
onOverwriteScope: this,
onOverwriteParams: [actor]
onOverwriteParams: [shellwm, actor]
});
},
_mapWindowDone : function(actor) {
_mapWindowDone : function(shellwm, actor) {
if (this._removeEffect(this._mapping, actor)) {
Tweener.removeTweens(actor);
actor.set_scale(1.0, 1.0);
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
this._shellwm.completed_map(actor);
shellwm.completed_map(actor);
}
},
_mapWindowOverwrite : function(actor) {
_mapWindowOverwrite : function(shellwm, actor) {
if (this._removeEffect(this._mapping, actor)) {
this._shellwm.completed_map(actor);
shellwm.completed_map(actor);
}
},
_destroyWindow : function(actor) {
_destroyWindow : function(shellwm, actor) {
if (!this._shouldAnimate(actor)) {
this._shellwm.completed_destroy(actor);
shellwm.completed_destroy(actor);
return;
}
@ -256,33 +177,35 @@ WindowManager.prototype = {
transition: "easeOutQuad",
onComplete: this._destroyWindowDone,
onCompleteScope: this,
onCompleteParams: [actor],
onCompleteParams: [shellwm, actor],
onOverwrite: this._destroyWindowOverwrite,
onOverwriteScope: this,
onOverwriteParams: [actor]
onOverwriteParams: [shellwm, actor]
});
},
_destroyWindowDone : function(actor) {
_destroyWindowDone : function(shellwm, actor) {
if (this._removeEffect(this._destroying, actor)) {
this._shellwm.completed_destroy(actor);
shellwm.completed_destroy(actor);
Tweener.removeTweens(actor);
actor.set_scale(1.0, 1.0);
}
},
_destroyWindowOverwrite : function(actor) {
_destroyWindowOverwrite : function(shellwm, actor) {
if (this._removeEffect(this._destroying, actor)) {
this._shellwm.completed_destroy(actor);
shellwm.completed_destroy(actor);
}
},
_switchWorkspace : function(windows, from, to, direction) {
_switchWorkspace : function(shellwm, from, to, direction) {
if (!this._shouldAnimate()) {
this._shellwm.completed_switch_workspace();
shellwm.completed_switch_workspace();
return;
}
let windows = shellwm.get_switch_workspace_actors();
/* @direction is the direction that the "camera" moves, so the
* screen contents have to move one screen's worth in the
* opposite direction.
@ -292,20 +215,20 @@ WindowManager.prototype = {
if (direction == Meta.MotionDirection.UP ||
direction == Meta.MotionDirection.UP_LEFT ||
direction == Meta.MotionDirection.UP_RIGHT)
yDest = this._global.screen_height;
yDest = global.screen_height;
else if (direction == Meta.MotionDirection.DOWN ||
direction == Meta.MotionDirection.DOWN_LEFT ||
direction == Meta.MotionDirection.DOWN_RIGHT)
yDest = -this._global.screen_height;
yDest = -global.screen_height;
if (direction == Meta.MotionDirection.LEFT ||
direction == Meta.MotionDirection.UP_LEFT ||
direction == Meta.MotionDirection.DOWN_LEFT)
xDest = this._global.screen_width;
xDest = global.screen_width;
else if (direction == Meta.MotionDirection.RIGHT ||
direction == Meta.MotionDirection.UP_RIGHT ||
direction == Meta.MotionDirection.DOWN_RIGHT)
xDest = -this._global.screen_width;
xDest = -global.screen_width;
let switchData = {};
this._switchData = switchData;
@ -313,7 +236,7 @@ WindowManager.prototype = {
switchData.outGroup = new Clutter.Group();
switchData.windows = [];
let wgroup = this._global.window_group;
let wgroup = global.window_group;
wgroup.add_actor(switchData.inGroup);
wgroup.add_actor(switchData.outGroup);
@ -344,7 +267,8 @@ WindowManager.prototype = {
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._switchWorkspaceDone,
onCompleteScope: this
onCompleteScope: this,
onCompleteParams: [shellwm]
});
Tweener.addTween(switchData.inGroup,
{ x: 0,
@ -354,7 +278,7 @@ WindowManager.prototype = {
});
},
_switchWorkspaceDone : function() {
_switchWorkspaceDone : function(shellwm) {
let switchData = this._switchData;
if (!switchData)
return;
@ -373,10 +297,10 @@ WindowManager.prototype = {
switchData.inGroup.destroy();
switchData.outGroup.destroy();
this._shellwm.completed_switch_workspace();
shellwm.completed_switch_workspace();
},
_beginAltTab : function(handler) {
_beginAltTab : function(shellwm, handler) {
let popup = new AltTab.AltTabPopup();
handler.connect('window-added', function(handler, window) { popup.addWindow(window); });

File diff suppressed because it is too large Load Diff

20
po/LINGUAS Normal file
View File

@ -0,0 +1,20 @@
ca
cs
da
de
en_GB
es
fr
ga
gl
hu
it
ko
nb
nl
pa
pl
pt_BR
sv
tr
zh_CN

9
po/POTFILES.in Normal file
View File

@ -0,0 +1,9 @@
data/gnome-shell.desktop.in.in
js/ui/panel.js
js/ui/dash.js
js/ui/overview.js
js/ui/runDialog.js
src/gdmuser/gdm-user.c
src/shell-global.c
src/shell-status-menu.c
src/shell-uri-util.c

1
po/POTFILES.skip Normal file
View File

@ -0,0 +1 @@
data/gnome-shell.desktop.in

189
po/ca.po Normal file
View File

@ -0,0 +1,189 @@
# Catalan gnome-shell translation.
# Copyright (C) 2009 Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>
# This file is distributed under the same license as the gnome-shell package.
#
# Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>, 2009.
msgid ""
msgstr ""
"Project-Id-Version: HEAD\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-30 18:53+0200\n"
"PO-Revision-Date: 2009-08-30 18:57+0100\n"
"Last-Translator: Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Gestió de finestres i execució d'aplicacions"
#. left side
#: ../js/ui/panel.js:271
msgid "Activities"
msgstr "Activitats"
#. Translators: This is a time format.
#: ../js/ui/panel.js:454
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#: ../js/ui/dash.js:256
msgid "Find..."
msgstr "Cerca..."
#: ../js/ui/dash.js:374
msgid "Browse"
msgstr "Navega"
#: ../js/ui/dash.js:451
msgid "(see all)"
msgstr "(mostra tot)"
#. **** Applications ****
#: ../js/ui/dash.js:633
#: ../js/ui/dash.js:681
msgid "APPLICATIONS"
msgstr "APLICACIONS"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:653
msgid "PLACES"
msgstr "LLOCS"
#. **** Documents ****
#: ../js/ui/dash.js:660
#: ../js/ui/dash.js:692
msgid "RECENT DOCUMENTS"
msgstr "DOCUMENTS RECENTS"
#. **** Search Results ****
#: ../js/ui/dash.js:679
msgid "SEARCH RESULTS"
msgstr "RESULTATS DE LA CERCA"
#: ../js/ui/runDialog.js:82
msgid "Please enter a command:"
msgstr "Introduïu una ordre:"
#: ../src/shell-global.c:840
msgid "Less than a minute ago"
msgstr "Fa menys d'un minut"
#: ../src/shell-global.c:843
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "Fa %d minut"
msgstr[1] "Fa %d minuts"
#: ../src/shell-global.c:846
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "Fa %d hora"
msgstr[1] "Fa %d hores"
#: ../src/shell-global.c:849
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "Fa %d dia"
msgstr[1] "Fa %d dies"
#: ../src/shell-global.c:852
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "Fa %d setmana"
msgstr[1] "Fa %d setmanes"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Desconegut"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "No es pot blocar la pantalla: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "No es pot establir temporalment l'estalvi de pantalla a pantalla negra: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "No es pot sortir: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Informació del compte..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Barra lateral"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Preferències del sistema..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Bloca la pantalla"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Canvia d'usuari"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Surt..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Atura..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Carpeta d'inici"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Sistema de fitxers"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Cerca"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Find apps or documents"
#~ msgstr "Cerca aplicacions o documents"
#~ msgid "Manager"
#~ msgstr "Gestor"
#~ msgid "The user manager object this user is controlled by."
#~ msgstr "L'objecte gestor d'usuaris que controla a aquest usuari."

189
po/cs.po Normal file
View File

@ -0,0 +1,189 @@
# Czech translation of gnome-shell.
# Copyright (C) 2009 the author(s) of gnome-shell.
# This file is distributed under the same license as the gnome-shell package.
# Andre Klapper <ak-47@gmx.net>, 2009.
# Petr Kovar <pknbe@volny.cz>, 2009.
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-30 17:37+0200\n"
"PO-Revision-Date: 2009-08-30 17:33+0200\n"
"Last-Translator: Petr Kovar <pknbe@volny.cz>\n"
"Language-Team: Czech <gnome-cs-list@gnome.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "Prostředí GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Správa oken a spouštění aplikací"
#. left side
#: ../js/ui/panel.js:271
msgid "Activities"
msgstr "Činnosti"
#. Translators: This is a time format.
#: ../js/ui/panel.js:454
msgid "%a %l:%M %p"
msgstr "%a, %H:%M"
#: ../js/ui/dash.js:256
msgid "Find..."
msgstr "Najít..."
#: ../js/ui/dash.js:374
msgid "Browse"
msgstr "Procházet"
#: ../js/ui/dash.js:451
msgid "(see all)"
msgstr "(zobrazit vše)"
#. **** Applications ****
#: ../js/ui/dash.js:633 ../js/ui/dash.js:681
msgid "APPLICATIONS"
msgstr "APLIKACE"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:653
msgid "PLACES"
msgstr "MÍSTA"
#. **** Documents ****
#: ../js/ui/dash.js:660 ../js/ui/dash.js:692
msgid "RECENT DOCUMENTS"
msgstr "NEDÁVNÉ DOKUMENTY"
#. **** Search Results ****
#: ../js/ui/dash.js:679
msgid "SEARCH RESULTS"
msgstr "VÝSLEDKY HLEDÁNÍ"
#: ../js/ui/runDialog.js:82
msgid "Please enter a command:"
msgstr "Zadejte prosím příkaz:"
#: ../src/shell-global.c:840
msgid "Less than a minute ago"
msgstr "Před méně než minutou"
#: ../src/shell-global.c:843
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "Před %d minutou"
msgstr[1] "Před %d minutami"
msgstr[2] "Před %d minutami"
#: ../src/shell-global.c:846
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "Před %d hodinou"
msgstr[1] "Před %d hodinami"
msgstr[2] "Před %d hodinami"
#: ../src/shell-global.c:849
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "Před %d dnem"
msgstr[1] "Před %d dny"
msgstr[2] "Před %d dny"
#: ../src/shell-global.c:852
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "Před %d týdnem"
msgstr[1] "Před %d týdny"
msgstr[2] "Před %d týdny"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Neznámé"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Nelze uzamknout obrazovku: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "Šetřič obrazovky nelze dočasně nastavit na prázdnou obrazovku: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Nelze se odhlásit: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Informace o účtu..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Postranní lišta"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Předvolby systému..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Uzamknout obrazovku"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Přepnout uživatele"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Odhlásit..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Vypnout..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Domovská složka"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Systém souborů"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Hledat"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Manager"
#~ msgstr "Správce"
#~ msgid "The user manager object this user is controlled by."
#~ msgstr "Objekt správce uživatele, kterým je tento uživatel ovládán."

188
po/da.po Normal file
View File

@ -0,0 +1,188 @@
# Danish translation of gnome-shell
# Copyright (C) 2009 gnome-shell
# This file is distributed under the same license as the gnome-shell package.
# Kris Thomsen <lakristho@gmail.com>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-09-04 01:26+0200\n"
"PO-Revision-Date: 2009-09-01 21:48+0200\n"
"Last-Translator: Kris Thomsen <lakristho@gmail.com>\n"
"Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "Skal til GNOME"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Vinduehåndtering og åbning af programmer"
#. left side
#: ../js/ui/panel.js:271
msgid "Activities"
msgstr "Aktiviteter"
#. Translators: This is a time format.
#: ../js/ui/panel.js:454
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#: ../js/ui/dash.js:256
msgid "Find..."
msgstr "Find..."
#: ../js/ui/dash.js:374
msgid "Browse"
msgstr "Gennemse"
#: ../js/ui/dash.js:511
msgid "(see all)"
msgstr "(se alle)"
#. **** Applications ****
#: ../js/ui/dash.js:705 ../js/ui/dash.js:761 ../js/ui/dash.js:893
msgid "APPLICATIONS"
msgstr "PROGRAMMER"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:725
msgid "PLACES"
msgstr "STEDER"
#. **** Documents ****
#: ../js/ui/dash.js:732 ../js/ui/dash.js:773 ../js/ui/dash.js:867
msgid "RECENT DOCUMENTS"
msgstr "SENESTE DOKUMENTER"
#. **** Search Results ****
#: ../js/ui/dash.js:751 ../js/ui/dash.js:856 ../js/ui/dash.js:882
msgid "SEARCH RESULTS"
msgstr "SØGERESULTATER"
#: ../js/ui/runDialog.js:82
msgid "Please enter a command:"
msgstr "Indtast en kommando:"
#: ../src/shell-global.c:840
msgid "Less than a minute ago"
msgstr "Mindre end et minut siden"
#: ../src/shell-global.c:843
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minut siden"
msgstr[1] "%d minutter siden"
#: ../src/shell-global.c:846
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d time siden"
msgstr[1] "%d timer siden"
#: ../src/shell-global.c:849
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d dag siden"
msgstr[1] "%d dage siden"
#: ../src/shell-global.c:852
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d uge siden"
msgstr[1] "%d uger siden"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Ukendt"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Kan ikke låse skærm: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "Kan ikke midlertidigt sætte pauseskærm til blank skærm: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Kan ikke logge ud: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Kontoinformation..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Sidebjælke"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Systemindstillinger..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Lås skærm"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Skift bruger"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Log ud..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Luk ned..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Hjemmemappe"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Filsystem"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Søg"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Find apps or documents"
#~ msgstr "Find programmer eller dokumenter"
#~ msgid "Manager"
#~ msgstr "Håndtering"
#~ msgid "The user manager object this user is controlled by."
#~ msgstr "Brugerhåndteringsobjektet, denne bruger er styret af."

182
po/de.po Normal file
View File

@ -0,0 +1,182 @@
# German gnome-shell translation.
# Copyright (C) 2009 Free Software Foundation, Inc.
# This file is distributed under the same license as the gnome-shell package.
#
# Hendrik Brandt <heb@gnome-de.org>, 2009.
# Hendrik Richter <hendrikr@gnome.org>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: HEAD\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-20 16:47+0200\n"
"PO-Revision-Date: 2009-08-20 16:49+0200\n"
"Last-Translator: Hendrik Richter <hendrikr@gnome.org>\n"
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME-Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Fenster verwalten und Anwendungen starten"
#. left side
#: ../js/ui/panel.js:266
msgid "Activities"
msgstr "Aktivitäten"
#. Translators: This is a time format.
#: ../js/ui/panel.js:433
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#: ../js/ui/dash.js:251
msgid "Find apps or documents"
msgstr "Anwendungen oder Dokumente suchen"
#: ../js/ui/dash.js:369
msgid "Browse"
msgstr "Durchsuchen"
#. **** Applications ****
#: ../js/ui/dash.js:505 ../js/ui/dash.js:578
msgid "APPLICATIONS"
msgstr "ANWENDUNGEN"
#. **** Documents ****
#: ../js/ui/dash.js:510 ../js/ui/dash.js:605
msgid "RECENT DOCUMENTS"
msgstr "ZULETZT GEÖFFNETE DOKUMENTE"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:598
msgid "PLACES"
msgstr "ORTE"
#: ../js/ui/runDialog.js:75
msgid "Please enter a command:"
msgstr "Bitte geben Sie einen Befehl ein:"
#: ../src/gdmuser/gdm-user.c:243
msgid "Manager"
msgstr "Verwaltung"
#: ../src/gdmuser/gdm-user.c:244
msgid "The user manager object this user is controlled by."
msgstr "Das Benutzerverwaltungsobjekt welches diesen Benutzer überwacht."
#: ../src/shell-global.c:841
msgid "Less than a minute ago"
msgstr "Vor weniger als einer Minute"
#: ../src/shell-global.c:844
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "Vor %d Minute"
msgstr[1] "Vor %d Minuten"
#: ../src/shell-global.c:847
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "Vor %d Stunde"
msgstr[1] "Vor %d Stunden"
#: ../src/shell-global.c:850
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "Vor %d Tag"
msgstr[1] "Vor %d Tagen"
#: ../src/shell-global.c:853
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "Vor %d Woche"
msgstr[1] "Vor %d Wochen"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Unbekannt"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Bildschirm kann nicht gesperrt werden: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr ""
"Der Bildschirmschoner kann vorübergehend nicht auf einen leeren Schirm "
"gesetzt werden: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Abmelden ist nicht möglich: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Benutzerinformationen …"
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Seitenleiste"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Systemeinstellungen …"
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Bildschirm sperren"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Benutzer wechseln"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Abmelden …"
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Ausschalten …"
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Persönlicher Ordner"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Dateisystem"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Suchen"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

184
po/en_GB.po Normal file
View File

@ -0,0 +1,184 @@
# British English translation for gnome-shell.
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
# Philip Withnall <philip@tecnocode.co.uk>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2009-09-12 12:41+0000\n"
"PO-Revision-Date: 2009-09-12 12:41+0000\n"
"Last-Translator: Philip Withnall <philip@tecnocode.co.uk>\n"
"Language-Team: British English <en_GB@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Window management and application launching"
#. left side
#: ../js/ui/panel.js:269
msgid "Activities"
msgstr "Activities"
#. Translators: This is a time format.
#: ../js/ui/panel.js:452
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/dash.js:283
msgid "Find..."
msgstr "Find…"
#: ../js/ui/dash.js:400
msgid "Browse"
msgstr "Browse"
#: ../js/ui/dash.js:536
msgid "(see all)"
msgstr "(see all)"
#. **** Applications ****
#: ../js/ui/dash.js:753 ../js/ui/dash.js:809
msgid "APPLICATIONS"
msgstr "APPLICATIONS"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:773
msgid "PLACES"
msgstr "PLACES"
#. **** Documents ****
#: ../js/ui/dash.js:780 ../js/ui/dash.js:819
msgid "RECENT DOCUMENTS"
msgstr "RECENT DOCUMENTS"
#. **** Search Results ****
#: ../js/ui/dash.js:799 ../js/ui/dash.js:931
msgid "SEARCH RESULTS"
msgstr "SEARCH RESULTS"
#: ../js/ui/dash.js:814
msgid "PREFERENCES"
msgstr "PREFERENCES"
#: ../js/ui/runDialog.js:90
msgid "Please enter a command:"
msgstr "Please enter a command:"
#: ../src/shell-global.c:799
msgid "Less than a minute ago"
msgstr "Less than a minute ago"
#: ../src/shell-global.c:802
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minute ago"
msgstr[1] "%d minutes ago"
#: ../src/shell-global.c:805
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d hour ago"
msgstr[1] "%d hours ago"
#: ../src/shell-global.c:808
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d day ago"
msgstr[1] "%d days ago"
#: ../src/shell-global.c:811
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d week ago"
msgstr[1] "%d weeks ago"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Unknown"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Can't lock screen: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "Can't temporarily set screensaver to blank screen: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Can't logout: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Account Information…"
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Sidebar"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "System Preferences…"
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Lock Screen"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Switch User"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Log Out…"
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Shut Down…"
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Home Folder"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "File System"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Search"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

199
po/es.po Normal file
View File

@ -0,0 +1,199 @@
# Spanish translation of gnome-shell.
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
#
# Jorge González <jorgegonz@svn.gnome.org>, 2009.
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2009-09-11 21:48+0000\n"
"PO-Revision-Date: 2009-09-12 14:40+0200\n"
"Last-Translator: Jorge González <jorgegonz@svn.gnome.org>\n"
"Language-Team: Español <gnome-es-list@gnome.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Gestión de ventanas e inicio de aplicaciones"
#. left side
#: ../js/ui/panel.js:269
msgid "Activities"
msgstr "Actividades"
#. Translators: This is a time format.
#: ../js/ui/panel.js:452
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#: ../js/ui/dash.js:283
msgid "Find..."
msgstr "Buscar…"
#: ../js/ui/dash.js:400
msgid "Browse"
msgstr "Examine"
#: ../js/ui/dash.js:536
msgid "(see all)"
msgstr "(ver todo)"
#. **** Applications ****
#: ../js/ui/dash.js:736 ../js/ui/dash.js:792
msgid "APPLICATIONS"
msgstr "APLICACIONES"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:756
msgid "PLACES"
msgstr "LUGARES"
#. **** Documents ****
#: ../js/ui/dash.js:763 ../js/ui/dash.js:802
msgid "RECENT DOCUMENTS"
msgstr "DOCUMENTOS RECIENTES"
#. **** Search Results ****
#: ../js/ui/dash.js:782 ../js/ui/dash.js:907
msgid "SEARCH RESULTS"
msgstr "RESULTADOS DE LA BÚSQUEDA"
#: ../js/ui/dash.js:797
msgid "PREFERENCES"
msgstr "PREFERENCIAS"
#: ../js/ui/runDialog.js:90
msgid "Please enter a command:"
msgstr "Introduzca un comando:"
#: ../src/shell-global.c:799
msgid "Less than a minute ago"
msgstr "Hace menos de un minuto"
#: ../src/shell-global.c:802
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "Hace %d minuto"
msgstr[1] "Hace %d minutos"
#: ../src/shell-global.c:805
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "Hace %d hora"
msgstr[1] "Hace %d horas"
#: ../src/shell-global.c:808
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "Hace %d día"
msgstr[1] "Hace %d días"
#: ../src/shell-global.c:811
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "Hace %d semana"
msgstr[1] "Hace %d semanas"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Desconocido"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "No se puede bloquear la pantalla: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr ""
"No se puede establecer temporalmente el salvapantallas a oscurecer pantalla: "
"%s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "No se puede salir de la sesión: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Información de la cuenta…"
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Barra lateral"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Preferencias del sistema…"
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Bloquear la pantalla"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Cambiar de usuario"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Salir…"
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Apagar…"
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Carpeta personal"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Sistema de archivos"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Buscar"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Find apps or documents"
#~ msgstr "Encuentre aplicaciones o documentos"
#~| msgid "RECENT DOCUMENTS"
#~ msgid "DOCUMENTS"
#~ msgstr "DOCUMENTOS"
#~ msgid "Manager"
#~ msgstr "Gestor"
#~ msgid "The user manager object this user is controlled by."
#~ msgstr "El objeto de gestión de usuarios que controla a este usuario."

182
po/fr.po Normal file
View File

@ -0,0 +1,182 @@
# French translations for gnome-shell package.
# Copyright (C) 2009 THE gnome-shell'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
#
# Mathieu Bridon <bochecha@fedoraproject.org>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: HEAD\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2009-09-09 21:30+0000\n"
"PO-Revision-Date: 2009-09-11 21:40+0200\n"
"Last-Translator: Mathieu Bridon <bochecha@fedoraproject.org>\n"
"Language-Team: GNOME French Team\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Gestion des fenêtres et lancement des applications"
#. left side
#: ../js/ui/panel.js:269
msgid "Activities"
msgstr "Activités"
#. Translators: This is a time format.
#: ../js/ui/panel.js:452
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#: ../js/ui/dash.js:255
msgid "Find..."
msgstr "Rechercher..."
#: ../js/ui/dash.js:372
msgid "Browse"
msgstr "Parcourir"
#: ../js/ui/dash.js:508
msgid "(see all)"
msgstr "(tout afficher)"
#. **** Applications ****
#: ../js/ui/dash.js:700 ../js/ui/dash.js:756 ../js/ui/dash.js:887
msgid "APPLICATIONS"
msgstr "APPLICATIONS"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:720
msgid "PLACES"
msgstr "RACCOURCIS"
#. **** Documents ****
#: ../js/ui/dash.js:727 ../js/ui/dash.js:768 ../js/ui/dash.js:861
msgid "RECENT DOCUMENTS"
msgstr "DOCUMENTS RÉCENTS"
#. **** Search Results ****
#: ../js/ui/dash.js:746 ../js/ui/dash.js:850 ../js/ui/dash.js:876
msgid "SEARCH RESULTS"
msgstr "RÉSULTATS DE LA RECHERCHE"
#: ../js/ui/runDialog.js:90
msgid "Please enter a command:"
msgstr "Veuillez saisir une commande :"
#: ../src/shell-global.c:799
msgid "Less than a minute ago"
msgstr "Il y a moins d'une minute"
#: ../src/shell-global.c:802
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "Il y a %d minute"
msgstr[1] "Il y a %d minutes"
#: ../src/shell-global.c:805
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "Il y a %d heure"
msgstr[1] "Il y a %d heures"
#: ../src/shell-global.c:808
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "Il y a %d jour"
msgstr[1] "Il y a %d jours"
#: ../src/shell-global.c:811
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "Il y a %d semaine"
msgstr[1] "Il y a %d semaines"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Inconnu"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Impossible de verrouiller l'écran : %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr ""
"Impossible de régler temporairement l'écran de veille sur un écran vide : %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Impossible de fermer la session : %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Informations personnelles..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Barre latérale"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Préférences du système..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Verrouiller l'écran"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Changer d'utilisateur"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Fermer la session..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Éteindre..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Dossier personnel"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Système de fichiers"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Recherche"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s : %2$s"

181
po/ga.po Normal file
View File

@ -0,0 +1,181 @@
# Irish translations for gnome-shell package.
# Copyright (C) 2009 Free Software Foundation, Inc.
# This file is distributed under the same license as the gnome-shell package.
# Seán de Búrca <leftmostcat@gmail.com>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell.master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-15 06:01-0600\n"
"PO-Revision-Date: 2009-08-15 06:01-0600\n"
"Last-Translator: Seán de Búrca <leftmostcat@gmail.com>\n"
"Language-Team: Irish <gaeilge-gnulinux@lists.sourceforge.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=5; plural=n==1 ? 0 : (n%10==1 || n%10==2) ? 1 : (n%"
"10>=3 && n%10<= 6) ? 2 : ((n%10>=7 && n%10<=9) || n==10) ? 3 : 4;\n"
#. left side
#: ../js/ui/panel.js:266
msgid "Activities"
msgstr "Gníomhartha"
#. Translators: This is a time format.
#: ../js/ui/panel.js:412
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/dash.js:235
msgid "Find apps or documents"
msgstr "Aimsigh feidhmchláir nó cáipéisí"
#: ../js/ui/dash.js:336
msgid "Browse"
msgstr "Brabhsáil"
#. **** Applications ****
#: ../js/ui/dash.js:472 ../js/ui/dash.js:545
msgid "APPLICATIONS"
msgstr "FEIDHMCHLÁIR"
#. **** Documents ****
#: ../js/ui/dash.js:477 ../js/ui/dash.js:570
msgid "RECENT DOCUMENTS"
msgstr "CÁIPÉISÍ IS DÉANAÍ"
#. **** Places ****
#: ../js/ui/dash.js:563
msgid "PLACES"
msgstr "ÁITEANNA"
#: ../js/ui/runDialog.js:74
msgid "Please enter a command:"
msgstr "Iontráil ordú, le do thoil:"
#: ../src/gdmuser/gdm-user.c:242
msgid "Manager"
msgstr "Bainisteoir"
#: ../src/gdmuser/gdm-user.c:243
msgid "The user manager object this user is controlled by."
msgstr "An réad bhainisteoir úsáideoirí a rialaíonn an t-úsáideoir seo."
#: ../src/shell-global.c:841
msgid "Less than a minute ago"
msgstr "Níos lú ná nóiméad ó shin"
#: ../src/shell-global.c:844
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d nóiméad ó shin"
msgstr[1] "%d nóiméad ó shin"
msgstr[2] "%d nóiméad ó shin"
msgstr[3] "%d nóiméad ó shin"
msgstr[4] "%d nóiméad ó shin"
#: ../src/shell-global.c:847
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d uair ó shin"
msgstr[1] "%d uair ó shin"
msgstr[2] "%d uaire ó shin"
msgstr[3] "%d n-uaire ó shin"
msgstr[4] "%d uair ó shin"
#: ../src/shell-global.c:850
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d lá ó shin"
msgstr[1] "%d lá ó shin"
msgstr[2] "%d lá ó shin"
msgstr[3] "%d lá ó shin"
msgstr[4] "%d lá ó shin"
#: ../src/shell-global.c:853
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d seachtain ó shin"
msgstr[1] "%d sheachtain ó shin"
msgstr[2] "%d sheachtain ó shin"
msgstr[3] "%d seachtain ó shin"
msgstr[4] "%d seachtain ó shin"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Anaithnid"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Ní féidir scáileán a chur faoi ghlas: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "Ní féidir spárálaí scáileáin a shocrú chun scáileán a bhánú: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Ní féidir logáil amach: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Eolas Cuntais..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Barra Taoibh"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Sainroghanna an Chórais..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Cuir Scáileán Faoi Ghlas"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Athraigh Úsáideoir"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Logáil Amach..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Múch..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Fillteán Baile"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Córas Comhad"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Cuardaigh"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

194
po/gl.po Normal file
View File

@ -0,0 +1,194 @@
# Galician translation for gnome-shell.
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
# Fran Diéguez <fran.dieguez@mabishu.com>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-09-15 23:06+0200\n"
"PO-Revision-Date: 2009-09-10 22:32+0100\n"
"Last-Translator: Fran Diéguez <fran.dieguez@glug.es>\n"
"Language-Team: Galician <gnome@mancomun.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Xestor de xanelas e lanzado de aplicativos"
#. left side
#: ../js/ui/panel.js:269
msgid "Activities"
msgstr "Actividades"
#. Translators: This is a time format.
#: ../js/ui/panel.js:452
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/dash.js:283
msgid "Find..."
msgstr "Buscar..."
#: ../js/ui/dash.js:400
msgid "Browse"
msgstr "Explorar"
#: ../js/ui/dash.js:536
msgid "(see all)"
msgstr "(ver todos)"
#. **** Applications ****
#: ../js/ui/dash.js:753 ../js/ui/dash.js:809
msgid "APPLICATIONS"
msgstr "APLICATIVOS"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:773
msgid "PLACES"
msgstr "LUGARES"
#. **** Documents ****
#: ../js/ui/dash.js:780 ../js/ui/dash.js:819
msgid "RECENT DOCUMENTS"
msgstr "DOCUMENTOS RECENTES"
#. **** Search Results ****
#: ../js/ui/dash.js:799 ../js/ui/dash.js:931
msgid "SEARCH RESULTS"
msgstr "RESULTADOS DA BÚSQUEDA"
#: ../js/ui/dash.js:814
msgid "PREFERENCES"
msgstr ""
#: ../js/ui/runDialog.js:96
msgid "Please enter a command:"
msgstr "Insira unha orde:"
#: ../src/shell-global.c:799
msgid "Less than a minute ago"
msgstr "Menos de un minuto"
#: ../src/shell-global.c:802
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "fai %d minuto"
msgstr[1] "fai %d minutos"
#: ../src/shell-global.c:805
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "fai %d hora"
msgstr[1] "fai %d horas"
#: ../src/shell-global.c:808
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "fai %d día"
msgstr[1] "fai %d días"
#: ../src/shell-global.c:811
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "fai %d semana"
msgstr[1] "fai %d semanas"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Descoñecido"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Non foi posíbel bloquear a pantalla: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr ""
"Non foi posíbel establecer o salvapantallas a unha pantalla en branco: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Non foi posíbel pechar a sesión: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Información da conta..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Barra lateral"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Preferenzas do sistema..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Bloquear pantalla"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Cambiar de usuario"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Pechar sesión..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Apagar..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Cartafol persoal"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Sistema de ficheiros"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Buscar"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Find apps or documents"
#~ msgstr "Atopar aplicativos ou documentos"
#, fuzzy
#~ msgid "DOCUMENTS"
#~ msgstr "DOCUMENTOS RECENTES"
#~ msgid "Manager"
#~ msgstr "Xestor"

180
po/hu.po Normal file
View File

@ -0,0 +1,180 @@
# Hungarian translation of gnome-shell
# Copyright 2009. Free Software Foundation, Inc.
# This file is distributed under the same license as the gnome-shell package.
#
# Gabor Kelemen <kelemeng at gnome dot hu>, 2009.
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-15 11:35+0200\n"
"PO-Revision-Date: 2009-08-15 11:35+0200\n"
"Last-Translator: Gabor Kelemen <kelemeng at gnome dot hu>\n"
"Language-Team: Hungarian <gnome at fsf dot hu>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: KBabel 1.11.4\n"
#. left side
#: ../js/ui/panel.js:266
msgid "Activities"
msgstr "Tevékenységek"
#. Translators: This is a time format.
#: ../js/ui/panel.js:412
msgid "%a %l:%M %p"
msgstr "%a., %k.%M"
#: ../js/ui/dash.js:235
msgid "Find apps or documents"
msgstr "Alkalmazások vagy dokumentumok keresése"
#: ../js/ui/dash.js:336
msgid "Browse"
msgstr "Tallózás"
#. **** Applications ****
#: ../js/ui/dash.js:472 ../js/ui/dash.js:545
msgid "APPLICATIONS"
msgstr "ALKALMAZÁSOK"
#. **** Documents ****
#: ../js/ui/dash.js:477 ../js/ui/dash.js:570
msgid "RECENT DOCUMENTS"
msgstr "LEGUTÓBBI DOKUMENTUMOK"
#. **** Places ****
#: ../js/ui/dash.js:563
msgid "PLACES"
msgstr "HELYEK"
#: ../js/ui/runDialog.js:74
msgid "Please enter a command:"
msgstr "Adjon meg egy parancsot:"
#: ../src/gdmuser/gdm-user.c:242
msgid "Manager"
msgstr "Kezelő"
#: ../src/gdmuser/gdm-user.c:243
msgid "The user manager object this user is controlled by."
msgstr "A felhasználót kezelő felhasználókezelő objektum."
#: ../src/shell-global.c:841
msgid "Less than a minute ago"
msgstr "Kevesebb, mint egy perce"
#: ../src/shell-global.c:844
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d perce"
msgstr[1] "%d perce"
#: ../src/shell-global.c:847
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d órája"
msgstr[1] "%d órája"
#: ../src/shell-global.c:850
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d napja"
msgstr[1] "%d napja"
#: ../src/shell-global.c:853
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d hete"
msgstr[1] "%d hete"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Ismeretlen"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Nem lehet zárolni a képernyőt: %s "
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr ""
"Átmenetileg nem lehet beállítani a képernyővédőt a képernyő elsötétítésére: %"
"s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Nem lehet kijelentkezni: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Fiókinformációk…"
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Oldalsáv"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Rendszerbeállítások…"
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Képernyő zárolása"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Felhasználóváltás"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Kijelentkezés…"
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Leállítás…"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Ablakkezelés és alkalmazásindítás"
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Saját mappa"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Fájlrendszer"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Oldalsáv"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

197
po/it.po Normal file
View File

@ -0,0 +1,197 @@
# Italian translations for gnome-shell package.
# Copyright (C) 2009 the gnome-shell copyright holder
# This file is distributed under the same license as the gnome-shell package.
# Milo Casagrande <milo@ubuntu.com>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2009-09-05 00:19+0000\n"
"PO-Revision-Date: 2009-09-06 18:31+0200\n"
"Last-Translator: Milo Casagrande <milo@ubuntu.com>\n"
"Language-Team: Italian <tp@lists.linux.it>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Gestione finestre e avvio applicazioni"
#. left side
#: ../js/ui/panel.js:271
msgid "Activities"
msgstr "Attività"
# (ndt) proviamo col k, se non funge, sappiamo il perché...
#. Translators: This is a time format.
#: ../js/ui/panel.js:454
msgid "%a %l:%M %p"
msgstr "%a %k.%M"
#: ../js/ui/dash.js:256
msgid "Find..."
msgstr "Trova..."
#: ../js/ui/dash.js:374
msgid "Browse"
msgstr "Esplora"
#: ../js/ui/dash.js:511
msgid "(see all)"
msgstr "(vedi tutto)"
#. **** Applications ****
#: ../js/ui/dash.js:705 ../js/ui/dash.js:761 ../js/ui/dash.js:893
msgid "APPLICATIONS"
msgstr "Applicazioni"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:725
msgid "PLACES"
msgstr "Risorse"
#. **** Documents ****
#: ../js/ui/dash.js:732 ../js/ui/dash.js:773 ../js/ui/dash.js:867
msgid "RECENT DOCUMENTS"
msgstr "Documenti recenti"
#. **** Search Results ****
#: ../js/ui/dash.js:751 ../js/ui/dash.js:856 ../js/ui/dash.js:882
msgid "SEARCH RESULTS"
msgstr "Risultati ricerca"
#: ../js/ui/runDialog.js:82
msgid "Please enter a command:"
msgstr "Inserire un comando:"
#: ../src/shell-global.c:840
msgid "Less than a minute ago"
msgstr "Meno di un minuto fa"
#: ../src/shell-global.c:843
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minuto fa"
msgstr[1] "%d minuti fa"
#: ../src/shell-global.c:846
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d ora fa"
msgstr[1] "%d ore fa"
#: ../src/shell-global.c:849
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d giorno fa"
msgstr[1] "%d giorni fa"
#: ../src/shell-global.c:852
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d settimana fa"
msgstr[1] "%d settimane fa"
# (ndt) valutare se vada al femminile
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Sconosciuto"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Impossibile bloccare lo schermo: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr ""
"Impossibile impostare temporaneamente il salva schermo a schermo nero: %s "
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Impossibile terminare la sessione: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Informazioni account..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Barra laterale"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Preferenze di sistema..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Blocca schermo"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Cambia utente"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Termina sessione..."
# (ndt) da valutare... pare che ora anche Windows usi 'Arresta...'...
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Spegni..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Cartella home"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "File system"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Cerca"
# (ndt) valutare...
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
# (ndt) è da valutare se è troppo lunga, è in una casella di ricerca
#~ msgid "Find apps or documents"
#~ msgstr "Trova programmi e documenti"
# (ndt) no idea...
#~ msgid "Manager"
#~ msgstr "Manager"
# (ndt) no idea...
#~ msgid "The user manager object this user is controlled by."
#~ msgstr "L'oggetto user manager che controlla questo utente."

166
po/ko.po Normal file
View File

@ -0,0 +1,166 @@
# gnome-shell korean translation.
# Copyright (C) 2009 THE gnome-shell'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
# Young-Ho Cha <ganadist@gmail.com>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-21 10:09+0900\n"
"PO-Revision-Date: 2009-08-21 10:10+0900\n"
"Last-Translator: Young-Ho Cha <ganadist@gmail.com>\n"
"Language-Team: GNOME Korea <gnome-kr-hackers@lists.kldp.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "그놈 쉘"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "창 관리와 프로그램 시작"
#. left side
#: ../js/ui/panel.js:266
msgid "Activities"
msgstr ""
#. Translators: This is a time format.
#: ../js/ui/panel.js:433
msgid "%a %l:%M %p"
msgstr "%A %p %l:%M"
#: ../js/ui/dash.js:250
msgid "Find apps or documents"
msgstr "프로그램과 문서를 찾습니다"
#: ../js/ui/dash.js:368
msgid "Browse"
msgstr "찾아보기"
#. **** Applications ****
#: ../js/ui/dash.js:504 ../js/ui/dash.js:577
msgid "APPLICATIONS"
msgstr "프로그램"
#. **** Documents ****
#: ../js/ui/dash.js:509 ../js/ui/dash.js:604
msgid "RECENT DOCUMENTS"
msgstr "최근 문서"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:597
msgid "PLACES"
msgstr "위치"
#: ../js/ui/runDialog.js:75
msgid "Please enter a command:"
msgstr "명령을 입력하십시오:"
#: ../src/shell-global.c:841
msgid "Less than a minute ago"
msgstr "1분 이내"
#: ../src/shell-global.c:844
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d분 전"
#: ../src/shell-global.c:847
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d시간 전"
#: ../src/shell-global.c:850
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d일 전"
#: ../src/shell-global.c:853
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d주 전"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "알 수 없음"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "화면을 잠글 수 없습니다: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "임시로 화면보호기를 빈 화면으로 설정할 수 없습니다: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "로그아웃 할 수 없습니다: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "계정 정보..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "사이드바"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "시스템 설정..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "화면 잠그기"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "사용자 바꾸기"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "로그아웃..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "컴퓨터 끄기..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "내 폴더"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "파일시스템"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "찾기"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%s: %s"

170
po/nb.po Normal file
View File

@ -0,0 +1,170 @@
# Norwegian bokmål translation of gnome-shell.
# Copyright (C) 2009 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
# Kjartan Maraas <kmaraas@broadpark.no>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell 0.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-21 12:36+0200\n"
"PO-Revision-Date: 2009-08-21 12:44+0200\n"
"Last-Translator: Kjartan Maraas <kmaraas@broadpark.no>\n"
"Language-Team: Norwegian bokmål <i18n-nb@lister.ping.uio.no>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Vindushåndtering og oppstart av programmer"
#. left side
#: ../js/ui/panel.js:266
msgid "Activities"
msgstr "Aktiviteter"
#. Translators: This is a time format.
#: ../js/ui/panel.js:433
msgid "%a %l:%M %p"
msgstr "%a %l:%M"
#: ../js/ui/dash.js:250
msgid "Find apps or documents"
msgstr "Finn programmer eller dokumenter"
#: ../js/ui/dash.js:368
msgid "Browse"
msgstr "Bla gjennom"
#. **** Applications ****
#: ../js/ui/dash.js:504 ../js/ui/dash.js:577
msgid "APPLICATIONS"
msgstr "PROGRAMMER"
#. **** Documents ****
#: ../js/ui/dash.js:509 ../js/ui/dash.js:604
msgid "RECENT DOCUMENTS"
msgstr "SISTE DOKUMENTER"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:597
msgid "PLACES"
msgstr "STEDER"
#: ../js/ui/runDialog.js:75
msgid "Please enter a command:"
msgstr "Oppgi en kommando:"
#: ../src/shell-global.c:841
msgid "Less than a minute ago"
msgstr "Mindre enn ett minutt siden"
#: ../src/shell-global.c:844
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minutt siden"
msgstr[1] "%d minutter siden"
#: ../src/shell-global.c:847
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d time siden"
msgstr[1] "%d timer siden"
#: ../src/shell-global.c:850
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d dag siden"
msgstr[1] "%d dager siden"
#: ../src/shell-global.c:853
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d uke siden"
msgstr[1] "%d uker siden"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Ukjent"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Kan ikke låse skjermen: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "Kan ikke sette skjermsparer midlertidig til blank skjerm: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Kan ikke logge ut: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Kontoinformasjon..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Sidelinje"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Brukervalg for systemet..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Lås skjerm"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Bytt bruker"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Logg ut..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Slå av..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Hjemmemappe"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Filsystem"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Søk"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

179
po/nl.po Normal file
View File

@ -0,0 +1,179 @@
# Dutch translation for gnome-shell
#
# This file is distributed under the same license as the gnome-shell package.
#
# Sander Dijkhuis <sander.dijkhuis@gmail.com>, 2009.
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-29 14:37+0200\n"
"PO-Revision-Date: 2009-08-29 15:10+0200\n"
"Last-Translator: Sander Dijkhuis <sander.dijkhuis@gmail.com>\n"
"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Vensterbeheer en toepassingen starten"
#. left side
#: ../js/ui/panel.js:271
msgid "Activities"
msgstr "Activiteiten"
#. Translators: This is a time format.
#: ../js/ui/panel.js:451
msgid "%a %l:%M %p"
msgstr "%a %k:%M"
#: ../js/ui/dash.js:256
msgid "Find..."
msgstr "Zoeken…"
#: ../js/ui/dash.js:374
msgid "Browse"
msgstr "Bladeren"
#: ../js/ui/dash.js:451
msgid "(see all)"
msgstr "(alles tonen)"
#. **** Applications ****
#: ../js/ui/dash.js:634 ../js/ui/dash.js:682
msgid "APPLICATIONS"
msgstr "TOEPASSINGEN"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:654
msgid "PLACES"
msgstr "LOCATIES"
#. **** Documents ****
#: ../js/ui/dash.js:661 ../js/ui/dash.js:694
msgid "RECENT DOCUMENTS"
msgstr "RECENTE DOCUMENTEN"
#. **** Search Results ****
#: ../js/ui/dash.js:680
msgid "SEARCH RESULTS"
msgstr "ZOEKRESULTATEN"
#: ../js/ui/runDialog.js:82
msgid "Please enter a command:"
msgstr "Voer een opdracht in:"
#: ../src/shell-global.c:840
msgid "Less than a minute ago"
msgstr "Korter dan een minuut geleden"
#: ../src/shell-global.c:843
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minuut geleden"
msgstr[1] "%d minuten geleden"
#: ../src/shell-global.c:846
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d uur geleden"
msgstr[1] "%d uur geleden"
#: ../src/shell-global.c:849
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d dag geleden"
msgstr[1] "%d dagen geleden"
#: ../src/shell-global.c:852
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d week geleden"
msgstr[1] "%d weken geleden"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Onbekend"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Kan het scherm niet vergrendelen: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "Kan de schermbeveiliging niet tijdelijk als zwart scherm instellen: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Kan niet afmelden: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Account-informatie…"
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Zijbalk"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Systeemvoorkeuren…"
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Scherm vergrendelen"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Gebruiker wisselen"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Afmelden…"
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Afsluiten…"
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Persoonlijke map"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Bestandssysteem"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Zoeken"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

182
po/pa.po Normal file
View File

@ -0,0 +1,182 @@
# Punjabi translation for gnome-shell.
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
#
# A S Alam <aalam@users.sf.net>, 2009.
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug."
"cgi?product=gnome-shell&component=general\n"
"POT-Creation-Date: 2009-08-31 22:31+0000\n"
"PO-Revision-Date: 2009-09-01 06:51+0530\n"
"Last-Translator: A S Alam <aalam@users.sf.net>\n"
"Language-Team: Punjabi/Panjabi <punjabi-users@lists.sf.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Lokalize 1.0\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "ਗਨੋਮ ਸ਼ੈਲ"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "ਵਿੰਡੋ ਪਰਬੰਧ ਅਤੇ ਐਪਲੀਕੇਸ਼ਨ ਚਲਾਓ"
#. left side
#: ../js/ui/panel.js:271
msgid "Activities"
msgstr "ਸਰਗਰਮੀਆਂ"
#. Translators: This is a time format.
#: ../js/ui/panel.js:454
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/dash.js:256
msgid "Find..."
msgstr "ਖੋਜ..."
#: ../js/ui/dash.js:374
msgid "Browse"
msgstr "ਝਲਕ"
#: ../js/ui/dash.js:451
msgid "(see all)"
msgstr "(ਸਭ ਵੇਖੋ)"
#. **** Applications ****
#: ../js/ui/dash.js:633 ../js/ui/dash.js:681
msgid "APPLICATIONS"
msgstr "ਐਪਲੀਕੇਸ਼ਨ"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:653
msgid "PLACES"
msgstr "ਥਾਵਾਂ"
#. **** Documents ****
#: ../js/ui/dash.js:660 ../js/ui/dash.js:692
msgid "RECENT DOCUMENTS"
msgstr "ਤਾਜ਼ਾ ਡੌਕੂਮੈਂਟ"
#. **** Search Results ****
#: ../js/ui/dash.js:679
msgid "SEARCH RESULTS"
msgstr "ਖੋਜ ਨਤੀਜੇ"
#: ../js/ui/runDialog.js:82
msgid "Please enter a command:"
msgstr "ਕਮਾਂਡ ਦਿਓ ਜੀ:"
#: ../src/shell-global.c:840
msgid "Less than a minute ago"
msgstr "ਇੱਕ ਮਿੰਟ ਤੋਂ ਘੱਟ ਚਿਰ ਪਹਿਲਾਂ"
#: ../src/shell-global.c:843
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d ਮਿੰਟ ਪਹਿਲਾਂ"
msgstr[1] "%d ਮਿੰਟ ਪਹਿਲਾਂ"
#: ../src/shell-global.c:846
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d ਘੰਟਾ ਪਹਿਲਾਂ"
msgstr[1] "%d ਘੰਟੇ ਪਹਿਲਾਂ"
#: ../src/shell-global.c:849
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d ਦਿਨ ਪਹਿਲਾਂ"
msgstr[1] "%d ਦਿਨ ਪਹਿਲਾਂ"
#: ../src/shell-global.c:852
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d ਹਫ਼ਤਾ ਪਹਿਲਾਂ"
msgstr[1] "%d ਹਫ਼ਤੇ ਪਹਿਲਾਂ"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "ਅਣਜਾਣ"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "ਸਕਰੀਨ ਲਾਕ ਨਹੀਂ ਹੋ ਸਕਦੀ: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "ਸਕਰੀਨ ਬੰਦ ਕਰਨ ਲਈ ਆਰਜ਼ੀ ਰੂਪ ਵਿੱਚ ਸਕਰੀਨ-ਸੇਵਰ ਨਹੀਂ ਸੈੱਟ ਕੀਤਾ ਜਾ ਸਕਦਾ: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "ਲਾਗਆਉਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "ਅਕਾਊਂਟ ਜਾਣਕਾਰੀ..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "ਬਾਹੀ"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "ਸਿਸਟਮ ਪਸੰਦ..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "ਸਕਰੀਨ ਲਾਕ ਕਰੋ"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "ਯੂਜ਼ਰ ਬਦਲੋ"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "ਲਾਗਆਉਟ..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "ਬੰਦ ਕਰੋ..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "ਘਰ ਫੋਲਡਰ"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "ਫਾਇਲ ਸਿਸਟਮ"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "ਖੋਜ"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

188
po/pl.po Normal file
View File

@ -0,0 +1,188 @@
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
# Aviary.pl
# Jeśli masz jakiekolwiek uwagi odnoszące się do tłumaczenia lub chcesz
# pomóc w jego rozwijaniu i pielęgnowaniu, napisz do nas:
# gnomepl@aviary.pl
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-09-09 03:06+0200\n"
"PO-Revision-Date: 2009-09-09 03:02+0100\n"
"Last-Translator: Tomasz Dominikowski <dominikowski@gmail.com>\n"
"Language-Team: Polish <gnomepl@aviary.pl>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"
"X-Poedit-Language: Polish\n"
"X-Poedit-Country: Poland\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "Powłoka środowiska GNOME"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Zarządzanie oknami i uruchamianiem programów"
#. left side
#: ../js/ui/panel.js:269
msgid "Activities"
msgstr "Czynności"
#. Translators: This is a time format.
#: ../js/ui/panel.js:452
msgid "%a %l:%M %p"
msgstr "%a, %H:%M"
#: ../js/ui/dash.js:255
msgid "Find..."
msgstr "Znajdź..."
#: ../js/ui/dash.js:372
msgid "Browse"
msgstr "Przeglądaj"
#: ../js/ui/dash.js:508
msgid "(see all)"
msgstr "(wyświetl wszystko)"
#. **** Applications ****
#: ../js/ui/dash.js:700 ../js/ui/dash.js:756 ../js/ui/dash.js:887
msgid "APPLICATIONS"
msgstr "Programy"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:720
msgid "PLACES"
msgstr "Miejsca"
#. **** Documents ****
#: ../js/ui/dash.js:727 ../js/ui/dash.js:768 ../js/ui/dash.js:861
msgid "RECENT DOCUMENTS"
msgstr "Ostatnie dokumenty"
#. **** Search Results ****
#: ../js/ui/dash.js:746 ../js/ui/dash.js:850 ../js/ui/dash.js:876
msgid "SEARCH RESULTS"
msgstr "Wyniki wyszukiwania"
#: ../js/ui/runDialog.js:90
msgid "Please enter a command:"
msgstr "Proszę wprowadzić polecenie:"
#: ../src/shell-global.c:799
msgid "Less than a minute ago"
msgstr "Mniej niż minutę temu"
#: ../src/shell-global.c:802
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minuta temu"
msgstr[1] "%d minuty temu"
msgstr[2] "%d minut temu"
#: ../src/shell-global.c:805
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d godzina temu"
msgstr[1] "%d godziny temu"
msgstr[2] "%d godzin temu"
#: ../src/shell-global.c:808
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d dzień temu"
msgstr[1] "%d dni temu"
msgstr[2] "%d dni temu"
#: ../src/shell-global.c:811
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d tydzień temu"
msgstr[1] "%d tygodnie temu"
msgstr[2] "%d tygodni temu"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Nieznane"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Nie można zablokować ekranu: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr ""
"Nie można tymczasowo ustawić wygaszacza ekranu na wygaszenie ekranu: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Nie można się wylogować: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Informacje o koncie..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Panel boczny"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Preferencje systemu..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Zablokuj ekran"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Przełącz użytkownika"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Wyloguj się..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Wyłącz komputer..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Katalog domowy"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "System plików"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Wyszukaj"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

144
po/pt_BR.po Normal file
View File

@ -0,0 +1,144 @@
# Portuguese translations for gnome-shell package.
# Copyright (C) 2009 THE gnome-shell'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
# Og Maciel <ogmaciel@gnome.org>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-14 17:53-0400\n"
"PO-Revision-Date: 2009-08-14 17:53-0400\n"
"Last-Translator: Og Maciel <ogmaciel@gnome.org>\n"
"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#. left side
#: ../js/ui/panel.js:266
msgid "Activities"
msgstr "Atividades"
#. Translators: This is a time format.
#: ../js/ui/panel.js:412
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/dash.js:235
msgid "Find apps or documents"
msgstr "Localizar aplicativos ou documentos"
#: ../js/ui/dash.js:336
msgid "Browse"
msgstr "Navegar"
#. **** Applications ****
#: ../js/ui/dash.js:472 ../js/ui/dash.js:545
msgid "APPLICATIONS"
msgstr "APLICATIVOS"
#. **** Documents ****
#: ../js/ui/dash.js:477 ../js/ui/dash.js:570
msgid "RECENT DOCUMENTS"
msgstr "DOCUMENTOS RECENTES"
#. **** Places ****
#: ../js/ui/dash.js:563
msgid "PLACES"
msgstr "LOCAIS"
#: ../js/ui/runDialog.js:74
msgid "Please enter a command:"
msgstr "Por favor digite um comando:"
#: ../src/gdmuser/gdm-user.c:242
msgid "Manager"
msgstr "Gerenciador"
#: ../src/gdmuser/gdm-user.c:243
msgid "The user manager object this user is controlled by."
msgstr "O objeto gerenciador de usuários que controla este usuário."
#: ../src/shell-global.c:841
msgid "Less than a minute ago"
msgstr "Menos de um minuto atrás"
#: ../src/shell-global.c:844
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minuto atrás"
msgstr[1] "%d minutos atrás"
#: ../src/shell-global.c:847
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d hora atrás"
msgstr[1] "%d horas atrás"
#: ../src/shell-global.c:850
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d dia atrás"
msgstr[1] "%d dias atrás"
#: ../src/shell-global.c:853
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d semana atrás"
msgstr[1] "%d semanas atrás"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Desconhecido"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Não foi possível travar a tela: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "Não foi possível definir a proteção de tela para uma tela vazia: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Não foi possível encerrar a sessão: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Informação da conta..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Barra lateral"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Preferências do sistema..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Travar a tela"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Alternar usuário"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Encerrar sessão..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Desligar..."

191
po/sv.po Normal file
View File

@ -0,0 +1,191 @@
# Swedish translation for gnome-shell.
# Copyright (C) 2009 Free Software Foundation, Inc.
# This file is distributed under the same license as the gnome-shell package.
# Daniel Nylander <po@danielnylander.se>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-09-01 00:31+0200\n"
"PO-Revision-Date: 2009-09-01 00:31+0100\n"
"Last-Translator: Daniel Nylander <po@danielnylander.se>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME-skal"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Fönsterhantering och programstarter"
#. left side
#: ../js/ui/panel.js:271
msgid "Activities"
msgstr "Aktiviteter"
#. Translators: This is a time format.
#: ../js/ui/panel.js:454
msgid "%a %l:%M %p"
msgstr "%a %H.%M"
#: ../js/ui/dash.js:256
msgid "Find..."
msgstr "Sök..."
#: ../js/ui/dash.js:374
msgid "Browse"
msgstr "Bläddra"
#: ../js/ui/dash.js:451
msgid "(see all)"
msgstr "(se alla)"
#. **** Applications ****
#: ../js/ui/dash.js:633
#: ../js/ui/dash.js:681
msgid "APPLICATIONS"
msgstr "PROGRAM"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:653
msgid "PLACES"
msgstr "PLATSER"
#. **** Documents ****
#: ../js/ui/dash.js:660
#: ../js/ui/dash.js:692
msgid "RECENT DOCUMENTS"
msgstr "SENASTE DOKUMENT"
#. **** Search Results ****
#: ../js/ui/dash.js:679
msgid "SEARCH RESULTS"
msgstr "SÖKRESULTAT"
#: ../js/ui/runDialog.js:82
msgid "Please enter a command:"
msgstr "Ange ett kommando:"
#: ../src/shell-global.c:840
msgid "Less than a minute ago"
msgstr "Mindre än en minut sedan"
#: ../src/shell-global.c:843
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d minut sedan"
msgstr[1] "%d minuter sedan"
#: ../src/shell-global.c:846
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d timme sedan"
msgstr[1] "%d timmar sedan"
#: ../src/shell-global.c:849
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d dag sedan"
msgstr[1] "%d dagar sedan"
#: ../src/shell-global.c:852
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d vecka sedan"
msgstr[1] "%d veckor sedan"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Okänt"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Kan inte låsa skärmen: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "Kan inte temporärt ställa in skärmsläckaren till blank skärm: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Kan inte logga ut: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Kontoinformation..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Sidopanel"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Systeminställningar..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Lås skärmen"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Växla användare"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Logga ut..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Stäng av..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Hemmapp"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Filsystem"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Sök"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Find apps or documents"
#~ msgstr "Hitta program eller dokument"
#~ msgid "DOCUMENTS"
#~ msgstr "DOKUMENT"
#~ msgid "Manager"
#~ msgstr "Hanterare"
#~ msgid "The user manager object this user is controlled by."
#~ msgstr "Användarhanteringsobjektet som denna användare styrs av."

166
po/tr.po Normal file
View File

@ -0,0 +1,166 @@
# gnome-shell
# Copyright (C) 2009
# This file is distributed under the same license as the gnome-shell package.
#
# Baris Cicek <baris@teamforce.name.tr>, 2009.
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-08-21 00:41+0300\n"
"PO-Revision-Date: 2009-08-21 00:40+0300\n"
"Last-Translator: Baris Cicek <baris@teamforce.name.tr>\n"
"Language-Team: Turkish <gnome-turk@gnome.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Kabuğu"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Pencere yönetimi ve uygulama başlatma"
#. left side
#: ../js/ui/panel.js:266
msgid "Activities"
msgstr "Etkinlikler"
#. Translators: This is a time format.
#: ../js/ui/panel.js:433
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#: ../js/ui/dash.js:251
msgid "Find apps or documents"
msgstr "Uygulamalar ve belgeler bul"
#: ../js/ui/dash.js:369
msgid "Browse"
msgstr "Göz at"
#. **** Applications ****
#: ../js/ui/dash.js:505 ../js/ui/dash.js:578
msgid "APPLICATIONS"
msgstr "UYGULAMALAR"
#. **** Documents ****
#: ../js/ui/dash.js:510 ../js/ui/dash.js:605
msgid "RECENT DOCUMENTS"
msgstr "SON ERİŞİLEN BELGELER"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:598
msgid "PLACES"
msgstr "YERLER"
#: ../js/ui/runDialog.js:75
msgid "Please enter a command:"
msgstr "Lütfen bir komut girin:"
#: ../src/shell-global.c:841
msgid "Less than a minute ago"
msgstr "Bir dakikadan daha az süre önce"
#: ../src/shell-global.c:844
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d dakika önce"
#: ../src/shell-global.c:847
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d saat önce"
#: ../src/shell-global.c:850
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d gün önce"
#: ../src/shell-global.c:853
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d hafta önce"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "Bilinmeyen"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "Ekran kilitlenemedi: %s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "Ekran koruyucu geçici olarak boş ekran olarak atanamadı: %s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "Çıkış yapılamadı: %s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "Hesap Bilgisi..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "Kenar Çubuğu"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "Sistem Tercihleri..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "Ekrani Kilitle"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "Kullanıcı Değiştir"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "Çıkış..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "Kapat..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "Ev Klasörü"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "Dosya Sistemi"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "Arama"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

176
po/zh_CN.po Normal file
View File

@ -0,0 +1,176 @@
# Chinese (China) translation for gnome-shell.
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
# Ray Wang <raywang@gnome.org>, 2009.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2009-08-29 19:32+0000\n"
"PO-Revision-Date: 2009-08-30 00:08+0800\n"
"Last-Translator: Ray Wang <raywang@gnome.org>\n"
"Language-Team: Chinese (Simplified) <i18n-zh@googlegroups.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: utf-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "窗口管理和应用程序启动"
#. left side
#: ../js/ui/panel.js:271
msgid "Activities"
msgstr "活动"
#. Translators: This is a time format.
#: ../js/ui/panel.js:454
msgid "%a %l:%M %p"
msgstr "%A %H:%M"
#: ../js/ui/dash.js:256
msgid "Find..."
msgstr "查找..."
#: ../js/ui/dash.js:374
msgid "Browse"
msgstr "浏览"
#: ../js/ui/dash.js:451
msgid "(see all)"
msgstr "(查看所有)"
#. **** Applications ****
#: ../js/ui/dash.js:633 ../js/ui/dash.js:681
msgid "APPLICATIONS"
msgstr "应用程序"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:653
msgid "PLACES"
msgstr "位置"
#. **** Documents ****
#: ../js/ui/dash.js:660 ../js/ui/dash.js:692
msgid "RECENT DOCUMENTS"
msgstr "最近的文档"
#. **** Search Results ****
#: ../js/ui/dash.js:679
msgid "SEARCH RESULTS"
msgstr "搜索结果"
#: ../js/ui/runDialog.js:82
msgid "Please enter a command:"
msgstr "请输入一个命令:"
#: ../src/shell-global.c:840
msgid "Less than a minute ago"
msgstr "少于一分钟前"
#: ../src/shell-global.c:843
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d 分钟前"
#: ../src/shell-global.c:846
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d 小时前"
#: ../src/shell-global.c:849
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d 天前"
#: ../src/shell-global.c:852
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d 周前"
#: ../src/shell-status-menu.c:156
msgid "Unknown"
msgstr "未知"
#: ../src/shell-status-menu.c:212
#, c-format
msgid "Can't lock screen: %s"
msgstr "不能锁住屏幕:%s"
#: ../src/shell-status-menu.c:227
#, c-format
msgid "Can't temporarily set screensaver to blank screen: %s"
msgstr "不能临时将屏幕保护设置成空白屏幕:%s"
#: ../src/shell-status-menu.c:351
#, c-format
msgid "Can't logout: %s"
msgstr "不能退出:%s"
#: ../src/shell-status-menu.c:492
msgid "Account Information..."
msgstr "帐户信息..."
#: ../src/shell-status-menu.c:502
msgid "Sidebar"
msgstr "侧边栏"
#: ../src/shell-status-menu.c:510
msgid "System Preferences..."
msgstr "系统首选项..."
#: ../src/shell-status-menu.c:525
msgid "Lock Screen"
msgstr "锁住屏幕"
#: ../src/shell-status-menu.c:535
msgid "Switch User"
msgstr "切换用户"
#. Only show switch user if there are other users
#. Log Out
#: ../src/shell-status-menu.c:546
msgid "Log Out..."
msgstr "退出..."
#. Shut down
#: ../src/shell-status-menu.c:557
msgid "Shut Down..."
msgstr "关机..."
#: ../src/shell-uri-util.c:87
msgid "Home Folder"
msgstr "主文件夹"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
msgid "File System"
msgstr "文件系统"
#: ../src/shell-uri-util.c:248
msgid "Search"
msgstr "搜索"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

View File

@ -33,21 +33,21 @@ big_source_c = \
big-enum-types.h: stamp-big-enum-types.h Makefile
@true
stamp-big-enum-types.h: $(big_source_h) big/big-enum-types.h.in
( cd $(srcdir) && \
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/big/big-enum-types.h.in \
$(big_source_h) ) >> xgen-teth && \
(cmp xgen-teth big-enum-types.h || cp xgen-teth big-enum-types.h) && \
rm -f xgen-teth && \
$(big_source_h) ) >> xgen-beth && \
(cmp -s xgen-beth big-enum-types.h || cp xgen-beth big-enum-types.h) && \
rm -f xgen-beth && \
echo timestamp > $(@F)
big-enum-types.c: stamp-big-enum-types.h big/big-enum-types.c.in
( cd $(srcdir) && \
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/big/big-enum-types.c.in \
$(big_source_h) ) >> xgen-tetc && \
cp xgen-tetc big-enum-types.c && \
rm -f xgen-tetc
$(big_source_h) ) >> xgen-betc && \
cp xgen-betc big-enum-types.c && \
rm -f xgen-betc
noinst_LTLIBRARIES += libbig-1.0.la

View File

@ -1,17 +0,0 @@
gnomeshell_taskpanel_CPPFLAGS = \
-I$(top_srcdir)/src \
-DG_DISABLE_DEPRECATED \
-DWNCK_I_KNOW_THIS_IS_UNSTABLE \
-DG_LOG_DOMAIN=\"gnomeshell-taskpanel\" \
$(TASKPANEL_CFLAGS) \
$(NULL)
gnomeshell_taskpanel_SOURCES = \
gnomeshell-taskpanel.c \
shell-panel-window.c \
shell-panel-window.h \
$(NULL)
gnomeshell_taskpanel_LDADD = $(TASKPANEL_LIBS)
libexec_PROGRAMS += gnomeshell-taskpanel

View File

@ -1,89 +0,0 @@
tidy_cflags = \
-I$(top_srcdir)/src \
-DPREFIX=\""$(prefix)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DG_DISABLE_DEPRECATED \
-DG_LOG_DOMAIN=\"Tidy\" \
$(MUTTER_PLUGIN_CFLAGS) \
$(NULL)
tidy_built_sources = \
tidy-enum-types.h \
tidy-enum-types.c \
tidy-marshal.h \
tidy-marshal.c
BUILT_SOURCES += $(tidy_built_sources)
TIDY_STAMP_FILES = stamp-tidy-marshal.h stamp-tidy-enum-types.h
# please, keep this sorted alphabetically
tidy_source_h = \
tidy/tidy-grid.h \
$(NULL)
tidy_source_h_priv = \
$(NULL)
# please, keep this sorted alphabetically
tidy_source_c = \
tidy/tidy-grid.c \
$(NULL)
tidy-marshal.h: stamp-tidy-marshal.h
@true
stamp-tidy-marshal.h: Makefile tidy/tidy-marshal.list
$(GLIB_GENMARSHAL) \
--prefix=_tidy_marshal \
--header \
$(srcdir)/tidy/tidy-marshal.list > xgen-tmh && \
(cmp -s xgen-tmh tidy-marshal.h || cp -f xgen-tmh tidy-marshal.h) && \
rm -f xgen-tmh && \
echo timestamp > $(@F)
tidy-marshal.c: Makefile tidy/tidy-marshal.list
(echo "#include \"tidy-marshal.h\"" ; \
$(GLIB_GENMARSHAL) \
--prefix=_tidy_marshal \
--body \
$(srcdir)/tidy/tidy-marshal.list ) > xgen-tmc && \
cp -f xgen-tmc tidy-marshal.c && \
rm -f xgen-tmc
tidy-enum-types.h: stamp-tidy-enum-types.h Makefile
@true
stamp-tidy-enum-types.h: $(tidy_source_h) tidy/tidy-enum-types.h.in
( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/tidy/tidy-enum-types.h.in \
$(tidy_source_h) ) >> xgen-teth && \
(cmp xgen-teth tidy-enum-types.h || cp xgen-teth tidy-enum-types.h) && \
rm -f xgen-teth && \
echo timestamp > $(@F)
tidy-enum-types.c: stamp-tidy-enum-types.h tidy/tidy-enum-types.c.in
( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/tidy/tidy-enum-types.c.in \
$(tidy_source_h) ) >> xgen-tetc && \
cp xgen-tetc tidy-enum-types.c && \
rm -f xgen-tetc
noinst_LTLIBRARIES += libtidy-1.0.la
libtidy_1_0_la_LIBADD = $(TIDY_LIBS)
libtidy_1_0_la_SOURCES = \
$(tidy_source_c) \
$(tidy_source_h) \
$(tidy_source_h_priv) \
$(tidy_built_sources) \
$(NULL)
libtidy_1_0_la_CPPFLAGS = $(tidy_cflags)
libtidy_1_0_la_LDFLAGS = $(LDADD)
CLEANFILES += $(TIDY_STAMP_FILES) $(BUILT_SOURCES)
EXTRA_DIST += \
tidy/tidy-enum-types.h.in \
tidy/tidy-enum-types.c.in \
tidy/tidy-marshal.list

View File

@ -24,7 +24,7 @@ tray_source = \
na-marshal.h: stamp-na-marshal.h
@true
stamp-na-marshal.h: Makefile tray/na-marshal.list
$(GLIB_GENMARSHAL) \
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
--prefix=_na_marshal \
--header \
$(srcdir)/tray/na-marshal.list > xgen-tmh && \
@ -33,7 +33,7 @@ stamp-na-marshal.h: Makefile tray/na-marshal.list
echo timestamp > $(@F)
na-marshal.c: Makefile tray/na-marshal.list
(echo "#include \"na-marshal.h\"" ; \
$(AM_V_GEN) (echo "#include \"na-marshal.h\"" ; \
$(GLIB_GENMARSHAL) \
--prefix=_na_marshal \
--body \

View File

@ -5,30 +5,33 @@ EXTRA_DIST =
libexec_PROGRAMS =
noinst_LTLIBRARIES =
.AUTOPARALLEL:
bin_SCRIPTS = gnome-shell
gnome-shell: gnome-shell.in
sed -e "s|@MUTTER_BIN_DIR[@]|$(MUTTER_BIN_DIR)|" \
$(AM_V_GEN) sed -e "s|@MUTTER_BIN_DIR[@]|$(MUTTER_BIN_DIR)|" \
-e "s|@GJS_JS_DIR[@]|$(GJS_JS_DIR)|" \
-e "s|@GJS_JS_NATIVE_DIR[@]|$(GJS_JS_NATIVE_DIR)|" \
-e "s|@libexecdir[@]|$(libexecdir)|" \
-e "s|@libdir[@]|$(libdir)|" \
-e "s|@pkgdatadir[@]|$(pkgdatadir)|" \
-e "s|@PYTHON[@]|$(PYTHON)|" \
-e "s|@sysconfdir[@]|$(sysconfdir)|" \
$< > $@ && chmod a+x $@
CLEANFILES += gnome-shell
EXTRA_DIST += gnome-shell.in
include Makefile-tidy.am
include Makefile-big.am
include Makefile-gdmuser.am
include Makefile-tray.am
include Makefile-taskpanel.am
gnome_shell_cflags = \
$(MUTTER_PLUGIN_CFLAGS) \
$(LIBGNOMEUI_CFLAGS) \
-I$(srcdir)/tray \
-DGETTEXT_PACKAGE=gnome-shell \
-DGETTEXT_PACKAGE=\"gnome-shell\" \
-DLOCALEDIR=\"$(datadir)/locale\" \
-DGNOME_SHELL_DATADIR=\"$(pkgdatadir)\" \
-DGNOME_SHELL_PKGLIBDIR=\"$(pkglibdir)\" \
-DJSDIR=\"$(pkgdatadir)/js\"
@ -57,21 +60,39 @@ libgnome_shell_la_SOURCES = \
shell-app-system.h \
shell-arrow.c \
shell-arrow.h \
shell-button-box.c \
shell-button-box.h \
shell-drawing.c \
shell-drawing.h \
shell-drawing-area.c \
shell-drawing-area.h \
shell-embedded-window.c \
shell-embedded-window.h \
shell-embedded-window-private.h \
shell-gconf.c \
shell-gconf.h \
shell-generic-container.c \
shell-generic-container.h \
shell-gtk-embed.c \
shell-gtk-embed.h \
shell-menu.c \
shell-menu.h \
shell-overflow-list.c \
shell-overflow-list.h \
shell-process.c \
shell-process.h \
shell-global.c \
shell-global.h \
shell-status-menu.c \
shell-status-menu.h \
shell-stack.c \
shell-stack.h \
shell-tray-manager.c \
shell-tray-manager.h \
shell-texture-cache.c \
shell-texture-cache.h \
shell-uri-util.c \
shell-uri-util.h \
shell-wm.c \
shell-wm.h
@ -109,22 +130,22 @@ libgnome_shell_la_gir_sources = \
shell-marshal.h: stamp-shell-marshal.h
@true
stamp-shell-marshal.h: Makefile shell-marshal.list
$(GLIB_GENMARSHAL) \
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
--prefix=_shell_marshal \
--header \
$(srcdir)/shell-marshal.list > xgen-tmh && \
(cmp -s xgen-tmh shell-marshal.h || cp -f xgen-tmh shell-marshal.h) && \
rm -f xgen-tmh && \
$(srcdir)/shell-marshal.list > xgen-smh && \
(cmp -s xgen-smh shell-marshal.h || cp -f xgen-smh shell-marshal.h) && \
rm -f xgen-smh && \
echo timestamp > $(@F)
shell-marshal.c: Makefile shell-marshal.list
(echo "#include \"shell-marshal.h\"" ; \
$(AM_V_GEN) (echo "#include \"shell-marshal.h\"" ; \
$(GLIB_GENMARSHAL) \
--prefix=_shell_marshal \
--body \
$(srcdir)/shell-marshal.list ) > xgen-tmc && \
cp -f xgen-tmc shell-marshal.c && \
rm -f xgen-tmc
$(srcdir)/shell-marshal.list ) > xgen-smc && \
cp -f xgen-smc shell-marshal.c && \
rm -f xgen-smc
libgnome_shell_la_LDFLAGS = -avoid-version -module
libgnome_shell_la_LIBADD = \
@ -132,20 +153,20 @@ libgnome_shell_la_LIBADD = \
$(LIBGNOMEUI_LIBS) \
libbig-1.0.la \
libgdmuser-1.0.la \
libtidy-1.0.la \
libtray.la
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
typelibdir = $(pkglibdir)
typelib_DATA = Shell-0.1.typelib Tidy-1.0.typelib Big-1.0.typelib
typelib_DATA = Shell-0.1.typelib Big-1.0.typelib
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir libgnome-shell.la Makefile
$(G_IR_SCANNER) \
$(AM_V_GEN) $(G_IR_SCANNER) \
--namespace=Shell \
--nsversion=0.1 \
--add-include-path=$(MUTTER_LIB_DIR)/mutter/ \
--include=Clutter-0.9 \
--include=Clutter-1.0 \
--include=Meta-2.27 \
--libtool="$(LIBTOOL)" \
--add-include-path=$(builddir) \
--include=Big-1.0 \
--program=mutter \
@ -158,33 +179,20 @@ CLEANFILES += Shell-0.1.gir
# The dependency on libgnome-shell.la here is because g-ir-compiler opens it
# (not the fake library, since we've already done the rewriting)
Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir Big-1.0.gir
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler --includedir=$(builddir) --includedir=$(MUTTER_LIB_DIR)/mutter/ Shell-0.1.gir -o $@
$(AM_V_GEN) LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} \
$(G_IR_COMPILER) \
--includedir=. \
--includedir=$(MUTTER_LIB_DIR)/mutter/ \
Shell-0.1.gir -o $@
CLEANFILES += Shell-0.1.typelib
Tidy-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libtidy-1.0.la Makefile
$(G_IR_SCANNER) \
--namespace=Tidy \
Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la $(srcdir)/big-enum-types.h Makefile
$(AM_V_GEN) $(G_IR_SCANNER) \
--namespace=Big \
--nsversion=1.0 \
--include=Clutter-0.9 \
--program=mutter \
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
$(addprefix $(srcdir)/,$(tidy_source_h)) \
$(addprefix $(srcdir)/,$(tidy_source_c)) \
$(srcdir)/tidy-enum-types.h \
$(tidy_cflags) \
-o $@
CLEANFILES += Tidy-1.0.gir
Tidy-1.0.typelib: libtidy-1.0.la Tidy-1.0.gir
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Tidy-1.0.gir -o $@
CLEANFILES += Tidy-1.0.typelib
Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la Makefile
$(G_IR_SCANNER) \
--namespace=Big \
--nsversion=1.0 \
--include=Clutter-0.9 \
--include=Clutter-1.0 \
--include=GdkPixbuf-2.0 \
--libtool="$(LIBTOOL)" \
--program=mutter \
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
$(addprefix $(srcdir)/,$(big_source_h)) \
@ -195,5 +203,6 @@ Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la Makefile
CLEANFILES += Big-1.0.gir
Big-1.0.typelib: libbig-1.0.la Big-1.0.gir
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Big-1.0.gir -o $@
$(AM_V_GEN) LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} \
$(G_IR_COMPILER) Big-1.0.gir -o $@
CLEANFILES += Big-1.0.typelib

View File

@ -1,208 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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 <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-object.h>
#include <gtk/gtk.h>
#include "gdm-user-chooser-widget.h"
#include "gdm-user-chooser-dialog.h"
#define GDM_USER_CHOOSER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_USER_CHOOSER_DIALOG, GdmUserChooserDialogPrivate))
struct GdmUserChooserDialogPrivate
{
GtkWidget *chooser_widget;
};
enum {
PROP_0,
};
static void gdm_user_chooser_dialog_class_init (GdmUserChooserDialogClass *klass);
static void gdm_user_chooser_dialog_init (GdmUserChooserDialog *user_chooser_dialog);
static void gdm_user_chooser_dialog_finalize (GObject *object);
G_DEFINE_TYPE (GdmUserChooserDialog, gdm_user_chooser_dialog, GTK_TYPE_DIALOG)
char *
gdm_user_chooser_dialog_get_chosen_user_name (GdmUserChooserDialog *dialog)
{
char *user_name;
g_return_val_if_fail (GDM_IS_USER_CHOOSER_DIALOG (dialog), NULL);
user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget));
return user_name;
}
void
gdm_user_chooser_dialog_set_show_user_other (GdmUserChooserDialog *dialog,
gboolean show_user)
{
g_return_if_fail (GDM_IS_USER_CHOOSER_DIALOG (dialog));
gdm_user_chooser_widget_set_show_user_other (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), show_user);
}
void
gdm_user_chooser_dialog_set_show_user_guest (GdmUserChooserDialog *dialog,
gboolean show_user)
{
g_return_if_fail (GDM_IS_USER_CHOOSER_DIALOG (dialog));
gdm_user_chooser_widget_set_show_user_guest (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), show_user);
}
void
gdm_user_chooser_dialog_set_show_user_auto (GdmUserChooserDialog *dialog,
gboolean show_user)
{
g_return_if_fail (GDM_IS_USER_CHOOSER_DIALOG (dialog));
gdm_user_chooser_widget_set_show_user_auto (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), show_user);
}
static void
gdm_user_chooser_dialog_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_user_chooser_dialog_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GObject *
gdm_user_chooser_dialog_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmUserChooserDialog *user_chooser_dialog;
user_chooser_dialog = GDM_USER_CHOOSER_DIALOG (G_OBJECT_CLASS (gdm_user_chooser_dialog_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
return G_OBJECT (user_chooser_dialog);
}
static void
gdm_user_chooser_dialog_dispose (GObject *object)
{
G_OBJECT_CLASS (gdm_user_chooser_dialog_parent_class)->dispose (object);
}
static void
gdm_user_chooser_dialog_class_init (GdmUserChooserDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_user_chooser_dialog_get_property;
object_class->set_property = gdm_user_chooser_dialog_set_property;
object_class->constructor = gdm_user_chooser_dialog_constructor;
object_class->dispose = gdm_user_chooser_dialog_dispose;
object_class->finalize = gdm_user_chooser_dialog_finalize;
g_type_class_add_private (klass, sizeof (GdmUserChooserDialogPrivate));
}
static void
on_response (GdmUserChooserDialog *dialog,
gint response_id)
{
switch (response_id) {
default:
break;
}
}
static void
gdm_user_chooser_dialog_init (GdmUserChooserDialog *dialog)
{
dialog->priv = GDM_USER_CHOOSER_DIALOG_GET_PRIVATE (dialog);
dialog->priv->chooser_widget = gdm_user_chooser_widget_new ();
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), dialog->priv->chooser_widget);
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
g_signal_connect (dialog,
"response",
G_CALLBACK (on_response),
dialog);
gtk_widget_show_all (GTK_WIDGET (dialog));
}
static void
gdm_user_chooser_dialog_finalize (GObject *object)
{
GdmUserChooserDialog *user_chooser_dialog;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_USER_CHOOSER_DIALOG (object));
user_chooser_dialog = GDM_USER_CHOOSER_DIALOG (object);
g_return_if_fail (user_chooser_dialog->priv != NULL);
G_OBJECT_CLASS (gdm_user_chooser_dialog_parent_class)->finalize (object);
}
GtkWidget *
gdm_user_chooser_dialog_new (void)
{
GObject *object;
object = g_object_new (GDM_TYPE_USER_CHOOSER_DIALOG,
NULL);
return GTK_WIDGET (object);
}

View File

@ -1,62 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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 __GDM_USER_CHOOSER_DIALOG_H
#define __GDM_USER_CHOOSER_DIALOG_H
#include <glib-object.h>
#include <gtk/gtkdialog.h>
G_BEGIN_DECLS
#define GDM_TYPE_USER_CHOOSER_DIALOG (gdm_user_chooser_dialog_get_type ())
#define GDM_USER_CHOOSER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_USER_CHOOSER_DIALOG, GdmUserChooserDialog))
#define GDM_USER_CHOOSER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_USER_CHOOSER_DIALOG, GdmUserChooserDialogClass))
#define GDM_IS_USER_CHOOSER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_USER_CHOOSER_DIALOG))
#define GDM_IS_USER_CHOOSER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_USER_CHOOSER_DIALOG))
#define GDM_USER_CHOOSER_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_USER_CHOOSER_DIALOG, GdmUserChooserDialogClass))
typedef struct GdmUserChooserDialogPrivate GdmUserChooserDialogPrivate;
typedef struct
{
GtkDialog parent;
GdmUserChooserDialogPrivate *priv;
} GdmUserChooserDialog;
typedef struct
{
GtkDialogClass parent_class;
} GdmUserChooserDialogClass;
GType gdm_user_chooser_dialog_get_type (void);
GtkWidget * gdm_user_chooser_dialog_new (void);
char * gdm_user_chooser_dialog_get_chosen_user_name (GdmUserChooserDialog *dialog);
void gdm_user_chooser_dialog_set_show_other_user (GdmUserChooserDialog *dialog,
gboolean show);
void gdm_user_chooser_dialog_set_show_user_guest (GdmUserChooserDialog *dialog,
gboolean show);
void gdm_user_chooser_dialog_set_show_user_auto (GdmUserChooserDialog *dialog,
gboolean show);
G_END_DECLS
#endif /* __GDM_USER_CHOOSER_DIALOG_H */

View File

@ -1,723 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
* Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
*
* 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 <string.h>
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <gconf/gconf-client.h>
#include "gdm-user-manager.h"
#include "gdm-user-chooser-widget.h"
#define KEY_DISABLE_USER_LIST "/apps/gdm/simple-greeter/disable_user_list"
enum {
USER_NO_DISPLAY = 1 << 0,
USER_ACCOUNT_DISABLED = 1 << 1,
};
#define DEFAULT_USER_ICON "stock_person"
#define GDM_USER_CHOOSER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_USER_CHOOSER_WIDGET, GdmUserChooserWidgetPrivate))
#define MAX_ICON_SIZE 128
struct GdmUserChooserWidgetPrivate
{
GdmUserManager *manager;
GtkIconTheme *icon_theme;
GdkPixbuf *logged_in_pixbuf;
GdkPixbuf *stock_person_pixbuf;
guint loaded : 1;
guint show_user_other : 1;
guint show_user_guest : 1;
guint show_user_auto : 1;
guint show_normal_users : 1;
guint load_idle_id;
};
enum {
PROP_0,
PROP_SHOW_USER_GUEST,
PROP_SHOW_USER_AUTO,
PROP_SHOW_USER_OTHER,
};
static void gdm_user_chooser_widget_class_init (GdmUserChooserWidgetClass *klass);
static void gdm_user_chooser_widget_init (GdmUserChooserWidget *user_chooser_widget);
static void gdm_user_chooser_widget_finalize (GObject *object);
G_DEFINE_TYPE (GdmUserChooserWidget, gdm_user_chooser_widget, GDM_TYPE_CHOOSER_WIDGET)
static int
get_font_height_for_widget (GtkWidget *widget)
{
PangoFontMetrics *metrics;
PangoContext *context;
int ascent;
int descent;
int height;
gtk_widget_ensure_style (widget);
context = gtk_widget_get_pango_context (widget);
metrics = pango_context_get_metrics (context,
widget->style->font_desc,
pango_context_get_language (context));
ascent = pango_font_metrics_get_ascent (metrics);
descent = pango_font_metrics_get_descent (metrics);
height = PANGO_PIXELS (ascent + descent);
pango_font_metrics_unref (metrics);
return height;
}
static int
get_icon_height_for_widget (GtkWidget *widget)
{
int font_height;
int height;
font_height = get_font_height_for_widget (widget);
height = 3 * font_height;
if (height > MAX_ICON_SIZE) {
height = MAX_ICON_SIZE;
}
g_debug ("GdmUserChooserWidget: font height %d; using icon size %d", font_height, height);
return height;
}
static void
add_user_other (GdmUserChooserWidget *widget)
{
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
GDM_USER_CHOOSER_USER_OTHER,
NULL,
_("Other..."),
_("Choose a different account"),
0,
FALSE,
TRUE);
}
static void
add_user_guest (GdmUserChooserWidget *widget)
{
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
GDM_USER_CHOOSER_USER_GUEST,
widget->priv->stock_person_pixbuf,
_("Guest"),
_("Login as a temporary guest"),
0,
FALSE,
TRUE);
}
static void
add_user_auto (GdmUserChooserWidget *widget)
{
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
GDM_USER_CHOOSER_USER_AUTO,
NULL,
_("Automatic Login"),
_("Automatically login to the system after selecting options"),
0,
FALSE,
TRUE);
}
static void
remove_user_other (GdmUserChooserWidget *widget)
{
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
GDM_USER_CHOOSER_USER_OTHER);
}
static void
remove_user_guest (GdmUserChooserWidget *widget)
{
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
GDM_USER_CHOOSER_USER_GUEST);
}
static void
remove_user_auto (GdmUserChooserWidget *widget)
{
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
GDM_USER_CHOOSER_USER_AUTO);
}
void
gdm_user_chooser_widget_set_show_user_other (GdmUserChooserWidget *widget,
gboolean show_user)
{
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
if (widget->priv->show_user_other != show_user) {
widget->priv->show_user_other = show_user;
if (show_user) {
add_user_other (widget);
} else {
remove_user_other (widget);
}
}
}
void
gdm_user_chooser_widget_set_show_user_guest (GdmUserChooserWidget *widget,
gboolean show_user)
{
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
if (widget->priv->show_user_guest != show_user) {
widget->priv->show_user_guest = show_user;
if (show_user) {
add_user_guest (widget);
} else {
remove_user_guest (widget);
}
}
}
void
gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget,
gboolean show_user)
{
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
if (widget->priv->show_user_auto != show_user) {
widget->priv->show_user_auto = show_user;
if (show_user) {
add_user_auto (widget);
} else {
remove_user_auto (widget);
}
}
}
char *
gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget)
{
g_return_val_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget), NULL);
return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
}
void
gdm_user_chooser_widget_set_chosen_user_name (GdmUserChooserWidget *widget,
const char *name)
{
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
gdm_chooser_widget_set_active_item (GDM_CHOOSER_WIDGET (widget), name);
}
void
gdm_user_chooser_widget_set_show_only_chosen (GdmUserChooserWidget *widget,
gboolean show_only) {
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
gdm_chooser_widget_set_hide_inactive_items (GDM_CHOOSER_WIDGET (widget),
show_only);
}
static void
gdm_user_chooser_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdmUserChooserWidget *self;
self = GDM_USER_CHOOSER_WIDGET (object);
switch (prop_id) {
case PROP_SHOW_USER_AUTO:
gdm_user_chooser_widget_set_show_user_auto (self, g_value_get_boolean (value));
break;
case PROP_SHOW_USER_GUEST:
gdm_user_chooser_widget_set_show_user_guest (self, g_value_get_boolean (value));
break;
case PROP_SHOW_USER_OTHER:
gdm_user_chooser_widget_set_show_user_other (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gdm_user_chooser_widget_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdmUserChooserWidget *self;
self = GDM_USER_CHOOSER_WIDGET (object);
switch (prop_id) {
case PROP_SHOW_USER_AUTO:
g_value_set_boolean (value, self->priv->show_user_auto);
break;
case PROP_SHOW_USER_GUEST:
g_value_set_boolean (value, self->priv->show_user_guest);
break;
case PROP_SHOW_USER_OTHER:
g_value_set_boolean (value, self->priv->show_user_other);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
is_user_list_disabled (GdmUserChooserWidget *widget)
{
GConfClient *client;
GError *error;
gboolean result;
client = gconf_client_get_default ();
error = NULL;
result = gconf_client_get_bool (client, KEY_DISABLE_USER_LIST, &error);
if (error != NULL) {
g_debug ("GdmUserChooserWidget: unable to get disable-user-list configuration: %s", error->message);
g_error_free (error);
}
g_object_unref (client);
return result;
}
static void
add_user (GdmUserChooserWidget *widget,
GdmUser *user)
{
GdkPixbuf *pixbuf;
char *tooltip;
gboolean is_logged_in;
int size;
if (!widget->priv->show_normal_users) {
return;
}
size = get_icon_height_for_widget (widget);
pixbuf = gdm_user_render_icon (user, size);
if (pixbuf == NULL && widget->priv->stock_person_pixbuf != NULL) {
pixbuf = g_object_ref (widget->priv->stock_person_pixbuf);
}
tooltip = g_strdup_printf (_("Log in as %s"),
gdm_user_get_user_name (user));
is_logged_in = gdm_user_get_num_sessions (user) > 0;
g_debug ("GdmUserChooserWidget: User added name:%s logged-in:%d pixbuf:%p",
gdm_user_get_user_name (user),
is_logged_in,
pixbuf);
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
gdm_user_get_user_name (user),
pixbuf,
gdm_user_get_real_name (user),
tooltip,
gdm_user_get_login_frequency (user),
is_logged_in,
FALSE);
g_free (tooltip);
if (pixbuf != NULL) {
g_object_unref (pixbuf);
}
}
static void
on_user_added (GdmUserManager *manager,
GdmUser *user,
GdmUserChooserWidget *widget)
{
/* wait for all users to be loaded */
if (! widget->priv->loaded) {
return;
}
add_user (widget, user);
}
static void
on_user_removed (GdmUserManager *manager,
GdmUser *user,
GdmUserChooserWidget *widget)
{
const char *user_name;
g_debug ("GdmUserChooserWidget: User removed: %s", gdm_user_get_user_name (user));
/* wait for all users to be loaded */
if (! widget->priv->loaded) {
return;
}
user_name = gdm_user_get_user_name (user);
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
user_name);
}
static void
on_user_is_logged_in_changed (GdmUserManager *manager,
GdmUser *user,
GdmUserChooserWidget *widget)
{
const char *user_name;
gboolean is_logged_in;
g_debug ("GdmUserChooserWidget: User logged in changed: %s", gdm_user_get_user_name (user));
user_name = gdm_user_get_user_name (user);
is_logged_in = gdm_user_get_num_sessions (user) > 0;
gdm_chooser_widget_set_item_in_use (GDM_CHOOSER_WIDGET (widget),
user_name,
is_logged_in);
}
static void
on_user_login_frequency_changed (GdmUserManager *manager,
GdmUser *user,
GdmUserChooserWidget *widget)
{
const char *user_name;
gulong freq;
g_debug ("GdmUserChooserWidget: User login frequency changed: %s", gdm_user_get_user_name (user));
user_name = gdm_user_get_user_name (user);
freq = gdm_user_get_login_frequency (user);
gdm_chooser_widget_set_item_priority (GDM_CHOOSER_WIDGET (widget),
user_name,
freq);
}
static void
on_users_loaded (GdmUserManager *manager,
GdmUserChooserWidget *widget)
{
GSList *users;
widget->priv->loaded = TRUE;
g_debug ("GdmUserChooserWidget: Users loaded");
users = gdm_user_manager_list_users (manager);
while (users != NULL) {
add_user (widget, users->data);
users = g_slist_delete_link (users, users);
}
gtk_widget_grab_focus (GTK_WIDGET (widget));
gdm_chooser_widget_loaded (GDM_CHOOSER_WIDGET (widget));
}
static gboolean
load_users (GdmUserChooserWidget *widget)
{
if (widget->priv->show_normal_users) {
widget->priv->manager = gdm_user_manager_ref_default ();
g_signal_connect (widget->priv->manager,
"user-added",
G_CALLBACK (on_user_added),
widget);
g_signal_connect (widget->priv->manager,
"user-removed",
G_CALLBACK (on_user_removed),
widget);
g_signal_connect (widget->priv->manager,
"users-loaded",
G_CALLBACK (on_users_loaded),
widget);
g_signal_connect (widget->priv->manager,
"user-is-logged-in-changed",
G_CALLBACK (on_user_is_logged_in_changed),
widget);
g_signal_connect (widget->priv->manager,
"user-login-frequency-changed",
G_CALLBACK (on_user_login_frequency_changed),
widget);
} else {
gdm_chooser_widget_loaded (GDM_CHOOSER_WIDGET (widget));
}
widget->priv->load_idle_id = 0;
return FALSE;
}
static GObject *
gdm_user_chooser_widget_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GdmUserChooserWidget *widget;
widget = GDM_USER_CHOOSER_WIDGET (G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->constructor (type,
n_construct_properties,
construct_properties));
widget->priv->show_normal_users = !is_user_list_disabled (widget);
widget->priv->load_idle_id = g_idle_add ((GSourceFunc)load_users, widget);
return G_OBJECT (widget);
}
static void
gdm_user_chooser_widget_dispose (GObject *object)
{
GdmUserChooserWidget *widget;
widget = GDM_USER_CHOOSER_WIDGET (object);
G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->dispose (object);
if (widget->priv->load_idle_id > 0) {
g_source_remove (widget->priv->load_idle_id);
widget->priv->load_idle_id = 0;
}
if (widget->priv->logged_in_pixbuf != NULL) {
g_object_unref (widget->priv->logged_in_pixbuf);
widget->priv->logged_in_pixbuf = NULL;
}
if (widget->priv->stock_person_pixbuf != NULL) {
g_object_unref (widget->priv->stock_person_pixbuf);
widget->priv->stock_person_pixbuf = NULL;
}
}
static void
gdm_user_chooser_widget_class_init (GdmUserChooserWidgetClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = gdm_user_chooser_widget_get_property;
object_class->set_property = gdm_user_chooser_widget_set_property;
object_class->constructor = gdm_user_chooser_widget_constructor;
object_class->dispose = gdm_user_chooser_widget_dispose;
object_class->finalize = gdm_user_chooser_widget_finalize;
g_object_class_install_property (object_class,
PROP_SHOW_USER_AUTO,
g_param_spec_boolean ("show-user-auto",
"show user auto",
"show user auto",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_SHOW_USER_GUEST,
g_param_spec_boolean ("show-user-guest",
"show user guest",
"show user guest",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class,
PROP_SHOW_USER_OTHER,
g_param_spec_boolean ("show-user-other",
"show user other",
"show user other",
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_type_class_add_private (klass, sizeof (GdmUserChooserWidgetPrivate));
}
static GdkPixbuf *
get_stock_person_pixbuf (GdmUserChooserWidget *widget)
{
GdkPixbuf *pixbuf;
int size;
size = get_icon_height_for_widget (widget);
pixbuf = gtk_icon_theme_load_icon (widget->priv->icon_theme,
DEFAULT_USER_ICON,
size,
0,
NULL);
return pixbuf;
}
static GdkPixbuf *
get_logged_in_pixbuf (GdmUserChooserWidget *widget)
{
GdkPixbuf *pixbuf;
int size;
size = get_icon_height_for_widget (widget);
pixbuf = gtk_icon_theme_load_icon (widget->priv->icon_theme,
"emblem-default",
size / 3,
0,
NULL);
return pixbuf;
}
typedef struct {
GdkPixbuf *old_icon;
GdkPixbuf *new_icon;
} IconUpdateData;
static gboolean
update_icons (GdmChooserWidget *widget,
const char *id,
GdkPixbuf **image,
char **name,
char **comment,
gulong *priority,
gboolean *is_in_use,
gboolean *is_separate,
IconUpdateData *data)
{
if (data->old_icon == *image) {
*image = data->new_icon;
return TRUE;
}
return FALSE;
}
static void
load_icons (GdmUserChooserWidget *widget)
{
GdkPixbuf *old_pixbuf;
IconUpdateData data;
if (widget->priv->logged_in_pixbuf != NULL) {
g_object_unref (widget->priv->logged_in_pixbuf);
}
widget->priv->logged_in_pixbuf = get_logged_in_pixbuf (widget);
old_pixbuf = widget->priv->stock_person_pixbuf;
widget->priv->stock_person_pixbuf = get_stock_person_pixbuf (widget);
/* update the icons in the model */
data.old_icon = old_pixbuf;
data.new_icon = widget->priv->stock_person_pixbuf;
gdm_chooser_widget_update_foreach_item (GDM_CHOOSER_WIDGET (widget),
(GdmChooserUpdateForeachFunc)update_icons,
&data);
if (old_pixbuf != NULL) {
g_object_unref (old_pixbuf);
}
}
static void
on_icon_theme_changed (GtkIconTheme *icon_theme,
GdmUserChooserWidget *widget)
{
g_debug ("GdmUserChooserWidget: icon theme changed");
load_icons (widget);
}
static void
setup_icons (GdmUserChooserWidget *widget)
{
if (gtk_widget_has_screen (GTK_WIDGET (widget))) {
widget->priv->icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (widget)));
} else {
widget->priv->icon_theme = gtk_icon_theme_get_default ();
}
if (widget->priv->icon_theme != NULL) {
g_signal_connect (widget->priv->icon_theme,
"changed",
G_CALLBACK (on_icon_theme_changed),
widget);
}
load_icons (widget);
}
static void
gdm_user_chooser_widget_init (GdmUserChooserWidget *widget)
{
widget->priv = GDM_USER_CHOOSER_WIDGET_GET_PRIVATE (widget);
gdm_chooser_widget_set_separator_position (GDM_CHOOSER_WIDGET (widget),
GDM_CHOOSER_WIDGET_POSITION_BOTTOM);
gdm_chooser_widget_set_in_use_message (GDM_CHOOSER_WIDGET (widget),
_("Currently logged in"));
setup_icons (widget);
}
static void
gdm_user_chooser_widget_finalize (GObject *object)
{
GdmUserChooserWidget *widget;
g_return_if_fail (object != NULL);
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (object));
widget = GDM_USER_CHOOSER_WIDGET (object);
g_return_if_fail (widget->priv != NULL);
G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->finalize (object);
}
GtkWidget *
gdm_user_chooser_widget_new (void)
{
GObject *object;
object = g_object_new (GDM_TYPE_USER_CHOOSER_WIDGET,
NULL);
return GTK_WIDGET (object);
}

View File

@ -1,70 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
*
* 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 __GDM_USER_CHOOSER_WIDGET_H
#define __GDM_USER_CHOOSER_WIDGET_H
#include <glib-object.h>
#include "gdm-chooser-widget.h"
G_BEGIN_DECLS
#define GDM_TYPE_USER_CHOOSER_WIDGET (gdm_user_chooser_widget_get_type ())
#define GDM_USER_CHOOSER_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_USER_CHOOSER_WIDGET, GdmUserChooserWidget))
#define GDM_USER_CHOOSER_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_USER_CHOOSER_WIDGET, GdmUserChooserWidgetClass))
#define GDM_IS_USER_CHOOSER_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_USER_CHOOSER_WIDGET))
#define GDM_IS_USER_CHOOSER_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_USER_CHOOSER_WIDGET))
#define GDM_USER_CHOOSER_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_USER_CHOOSER_WIDGET, GdmUserChooserWidgetClass))
typedef struct GdmUserChooserWidgetPrivate GdmUserChooserWidgetPrivate;
typedef struct
{
GdmChooserWidget parent;
GdmUserChooserWidgetPrivate *priv;
} GdmUserChooserWidget;
typedef struct
{
GdmChooserWidgetClass parent_class;
} GdmUserChooserWidgetClass;
#define GDM_USER_CHOOSER_USER_OTHER "__other"
#define GDM_USER_CHOOSER_USER_GUEST "__guest"
#define GDM_USER_CHOOSER_USER_AUTO "__auto"
GType gdm_user_chooser_widget_get_type (void);
GtkWidget * gdm_user_chooser_widget_new (void);
char * gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget);
void gdm_user_chooser_widget_set_chosen_user_name (GdmUserChooserWidget *widget,
const char *user_name);
void gdm_user_chooser_widget_set_show_only_chosen (GdmUserChooserWidget *widget,
gboolean show_only);
void gdm_user_chooser_widget_set_show_user_other (GdmUserChooserWidget *widget,
gboolean show);
void gdm_user_chooser_widget_set_show_user_guest (GdmUserChooserWidget *widget,
gboolean show);
void gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget,
gboolean show);
G_END_DECLS
#endif /* __GDM_USER_CHOOSER_WIDGET_H */

View File

@ -35,7 +35,8 @@
#endif /* HAVE_PATHS_H */
#include <glib.h>
#include <glib/gi18n.h>
/* Note on sync with gdm; need to use -lib here */
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
#include <glib-object.h>
#include <gio/gio.h>

View File

@ -20,12 +20,14 @@
#include <config.h>
#include <float.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <glib/gi18n.h>
/* Note on sync with gdm; need to use -lib here */
#include <glib/gi18n-lib.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
@ -238,8 +240,8 @@ gdm_user_class_init (GdmUserClass *class)
g_object_class_install_property (gobject_class,
PROP_MANAGER,
g_param_spec_object ("manager",
_("Manager"),
_("The user manager object this user is controlled by."),
"Manager",
"The user manager object this user is controlled by.",
GDM_TYPE_USER_MANAGER,
(G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY)));
@ -411,13 +413,16 @@ _gdm_user_update (GdmUser *user,
/* Display Name */
if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
gchar *first_comma;
gchar *real_name_utf8;
first_comma = strchr (pwent->pw_gecos, ',');
real_name_utf8 = g_locale_to_utf8 (pwent->pw_gecos, -1, NULL, NULL, NULL);
first_comma = strchr (real_name_utf8, ',');
if (first_comma) {
real_name = g_strndup (pwent->pw_gecos,
(first_comma - pwent->pw_gecos));
real_name = g_strndup (real_name_utf8, first_comma - real_name_utf8);
g_free (real_name_utf8);
} else {
real_name = g_strdup (pwent->pw_gecos);
real_name = real_name_utf8;
}
if (real_name[0] == '\0') {
@ -881,7 +886,7 @@ curved_rectangle (cairo_t *cr,
x1 = x0 + width;
y1 = y0 + height;
if (!width || !height) {
if (width < FLT_EPSILON || height < FLT_EPSILON) {
return;
}
@ -1156,8 +1161,8 @@ gdm_user_render_icon (GdmUser *user,
} else {
pixbuf = NULL;
}
out:
g_free (path);
out:
if (pixbuf != NULL) {
framed = frame_pixbuf (pixbuf);

View File

@ -153,6 +153,9 @@ gnome_shell_plugin_constructed (GObject *object)
ClutterBackend *backend;
cairo_font_options_t *font_options;
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
/* Disable text mipmapping; it causes problems on pre-GEM Intel
* drivers and we should just be rendering text at the right
* size rather than scaling it. If we do effects where we dynamically

161
src/gnome-shell.in Executable file → Normal file
View File

@ -1,4 +1,4 @@
#!/usr/bin/python
#!@PYTHON@
import atexit
import optparse
@ -14,43 +14,6 @@ import termios
import time
import errno
def find_cmd (cmd_list):
"""
Takes a list of command candidates and returns the first one that exists.
Raises a system exit if none of the commands exist.
"""
for cmd in cmd_list:
if os.path.exists(cmd):
return cmd
raise SystemExit("None of the commands %s exist" % cmd_list)
def pidof(command):
pidof_cmd = find_cmd(["/sbin/pidof", "/bin/pidof", "/usr/bin/pidof"])
pidof = subprocess.Popen([pidof_cmd, command], stdout=subprocess.PIPE)
pids = pidof.communicate()[0].split()
pidof.wait()
# pidof doesn't have a "current user only" option, so we may have
# gotten the pids of other users' processes. Fix that.
for pid in pids:
try:
os.kill(int(pid), 0)
return pid
except Exception, e:
pass
return None
def kill_gnome_panel(pid):
if options.verbose:
print "Terminating panel process %s" % pid
devnull = open("/dev/null", "w")
subprocess.call(["gdb", "-batch-silent",
"-ex", "call panel_session_do_not_restart()",
"-ex", "call exit(0)",
"-p", pid], stdout=devnull, stderr=devnull)
devnull.close()
def start_xephyr():
tmpdir = tempfile.mkdtemp("", "gnome-shell.")
atexit.register(shutil.rmtree, tmpdir)
@ -122,25 +85,27 @@ def start_shell():
top_dir = os.path.dirname(bin_dir)
plugin = os.path.join(top_dir, 'src', 'libgnome-shell.la')
typelib_dir = os.path.join(top_dir, "src")
taskpanel_dir = os.path.join(top_dir, "src")
js_dir = os.path.join(top_dir, "js")
data_dir = os.path.join(top_dir, "data")
else:
running_from_source_tree = False
plugin = 'libgnome-shell'
js_dir = os.path.join('@pkgdatadir@', 'js')
taskpanel_dir = '@libexecdir@'
# Set up environment
env = dict(os.environ)
env.update({'GNOME_SHELL_JS' : '@GJS_JS_DIR@:@GJS_JS_NATIVE_DIR@:' + js_dir,
'PATH' : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', '') + ':' + taskpanel_dir,
'PATH' : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', ''),
'GNOME_DISABLE_CRASH_DIALOG' : '1'})
if running_from_source_tree:
env.update({'GNOME_SHELL_DATADIR' : data_dir,
'GI_TYPELIB_PATH' : typelib_dir})
jhbuild_gconf_source = os.path.join('@sysconfdir@', 'gconf/2/path.jhbuild')
if os.path.exists(jhbuild_gconf_source):
env['GCONF_DEFAULT_SOURCE_PATH'] = jhbuild_gconf_source
# Work around Ubuntu xulrunner bug,
# http://bugzilla.gnome.org/show_bug.cgi?id=573413
pkgconfig = subprocess.Popen(['pkg-config', '--variable=sdkdir', 'mozilla-js'],
@ -187,11 +152,47 @@ def start_shell():
else:
args = []
args.extend(['mutter', '--mutter-plugins=' + plugin, '--replace'])
args.extend(['mutter', '--mutter-plugins=' + plugin])
if options.replace:
args.append('--replace')
if options.sync:
args.append('--sync')
return subprocess.Popen(args, env=env)
def restore_gnome():
# Do imports lazily to save time and memory
import gio
import gconf
# We don't want to start the new gnome-panel in the current
# directory; $HOME is better for stuff launched from it
os.chdir(os.path.expanduser("~"))
def launch_component(gconf_path):
client = gconf.client_get_default()
component = client.get_string(gconf_path)
if component == None or component == "":
return
# See gnome-session/gsm-util.c:gsm_util_find_desktop_file_for_app_name()
# The one difference is that we don't search the autostart directories,
# and just search normal application search path. (Gio doesnt' know
# how to search the autostart dirs, so we'd have to do that ourselves.)
appinfo = None
try:
appinfo = gio.unix.DesktopAppInfo(component + ".desktop")
except:
try:
appinfo = gio.unix.DesktopAppInfo("gnome-" + component + ".desktop")
except:
pass
if appinfo:
appinfo.launch()
launch_component("/desktop/gnome/session/required_components/windowmanager")
launch_component("/desktop/gnome/session/required_components/panel")
# Main program
@ -204,6 +205,8 @@ parser.add_option("", "--debug-command", metavar="COMMAND",
help="Command to use for debugging (defaults to 'gdb --args')")
parser.add_option("-v", "--verbose", action="store_true")
parser.add_option("", "--sync", action="store_true")
parser.add_option("", "--xephyr", action="store_true",
help="Run a debugging instance inside Xephyr")
parser.add_option("", "--geometry", metavar="GEOMETRY",
help="Specify Xephyr screen geometry",
default="1024x768");
@ -224,18 +227,6 @@ elif options.debug:
if options.wide:
options.geometry = "1280x800"
metacity_pid = pidof("metacity")
compiz_pid = pidof("compiz.real") or pidof("compiz")
gnome_panel_pid = pidof("gnome-panel")
# Run in Xephyr if gnome-panel is already running and the user didn't
# specify --replace. Otherwise, run fullscreen
if options.replace:
run_in_xephyr = False
else:
run_in_xephyr = (metacity_pid != None or compiz_pid != None or
gnome_panel_pid != None)
# Figure out whether or not to use GL_EXT_texture_from_pixmap. By default
# we use it iff we aren't running Xephyr, but we allow the user to
# explicitly disable it.
@ -246,7 +237,7 @@ if 'GNOME_SHELL_DISABLE_TFP' in os.environ and \
use_tfp = False
else:
# tfp does not work correctly in Xephyr
use_tfp = not run_in_xephyr
use_tfp = not options.xephyr
if options.verbose:
print "Starting shell"
@ -256,21 +247,26 @@ if options.debug:
# later, in case we kill gdb at a bad time
termattrs = termios.tcgetattr(0);
# We only respawn the previous environment on abnormal exit;
# for a clean exit, we assume that gnome-shell was replaced with
# something else.
normal_exit = False
try:
if run_in_xephyr:
shell = start_xephyr()
start_shell()
shell = None
if options.xephyr:
xephyr = start_xephyr()
# This makes us not grab the org.gnome.Panel name
os.environ['GNOME_SHELL_NO_REPLACE_PANEL'] = '1'
shell = start_shell()
else:
if gnome_panel_pid is not None:
kill_gnome_panel(gnome_panel_pid)
xephyr = None
shell = start_shell()
# Wait for shell to exit
if options.verbose:
print "Waiting for shell to exit"
shell.wait()
if options.verbose:
print "Shell is dead"
except KeyboardInterrupt, e:
try:
@ -278,24 +274,31 @@ except KeyboardInterrupt, e:
except:
pass
shell.wait()
if options.verbose:
print "Shell killed"
finally:
# Clean up Xephyr if it outlived the shell
if xephyr:
try:
os.kill(xephyr.pid, signal.SIGKILL)
except OSError:
pass
if shell is None:
print "Failed to start shell"
elif shell.returncode == 0:
normal_exit = True
if options.verbose:
print "Shell exited normally"
elif shell.returncode < 0:
# Python has no mapping for strsignal; not worth using
# ctypes for this.
print "Shell killed with signal %d" % - shell.returncode
else:
# Normal reason here would be losing connection the X server
if options.verbose:
print "Shell exited with return code %d" % shell.returncode
if options.debug:
termios.tcsetattr(0, termios.TCSANOW, termattrs);
if not run_in_xephyr:
# Restart gnome-panel and window manager
if metacity_pid:
if options.verbose:
print "Restarting Metacity"
subprocess.Popen(["/usr/bin/metacity"])
elif compiz_pid:
if options.verbose:
print "Restarting Compiz"
subprocess.Popen(["/usr/bin/compiz"])
if gnome_panel_pid:
if options.verbose:
print "Restarting gnome-panel"
subprocess.Popen(["/usr/bin/gnome-panel"])
if not options.xephyr and options.replace and not normal_exit:
restore_gnome()

View File

@ -1,90 +0,0 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include "shell-panel-window.h"
#include <libwnck/libwnck.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus-glib.h>
static void
on_name_owner_changed (DBusGProxy *proxy,
const char *name,
const char *prev_owner,
const char *new_owner,
gpointer user_data)
{
if (strcmp (name, "org.gnome.Shell") == 0 && new_owner[0] == '\0')
exit (0);
}
static void
monitor_main_shell (const char *shell_name)
{
DBusGConnection *session;
DBusGProxy *driver;
GError *error = NULL;
gboolean have_shell;
session = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
driver = dbus_g_proxy_new_for_name (session,
DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS);
if (!dbus_g_proxy_call (driver, "NameHasOwner", &error, G_TYPE_STRING,
shell_name, G_TYPE_INVALID, G_TYPE_BOOLEAN,
&have_shell, G_TYPE_INVALID))
{
/* Shouldn't happen */
exit (1);
}
if (!have_shell)
{
/* Shell doesn't exist; either crashed or was restarted. Just abort. */
exit (0);
}
dbus_g_proxy_add_signal (driver,
"NameOwnerChanged",
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (driver,
"NameOwnerChanged",
G_CALLBACK (on_name_owner_changed),
NULL,
NULL);
}
int
main (int argc, char **argv)
{
ShellPanelWindow *panel;
WnckScreen *screen;
WnckTasklist *tasks;
gtk_init (&argc, &argv);
if (argc != 2) {
g_printerr ("Usage: gnomeshell-taskpanel [PARENT_DBUS_SERVICE]\n");
exit (1);
}
monitor_main_shell (argv[1]);
panel = shell_panel_window_new ();
screen = wnck_screen_get_default();
tasks = WNCK_TASKLIST (wnck_tasklist_new (screen));
gtk_container_add (GTK_CONTAINER (panel), GTK_WIDGET (tasks));
gtk_widget_show_all (GTK_WIDGET (panel));
gtk_main ();
exit (0);
}

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,9 @@
#include <glib-object.h>
#include <glib.h>
#include "window.h"
#include "shell-app-system.h"
/*
* This object provides monitoring of system application directories (.desktop files)
* and activity-based statistics about applications usage
@ -27,22 +30,36 @@ struct _ShellAppMonitorClass
{
GObjectClass parent_class;
void (*apps_changed)(ShellAppMonitor *menuwrapper,
gpointer data);
};
GType shell_app_monitor_get_type (void) G_GNUC_CONST;
ShellAppMonitor* shell_app_monitor_get_default(void);
/* Get the most popular applications for a given activity */
GSList *shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
int activity,
gint number);
ShellAppInfo *shell_app_monitor_get_window_app (ShellAppMonitor *monitor, MetaWindow *metawin);
GList *shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
const char *context,
gint number);
GSList *shell_app_monitor_get_windows_for_app (ShellAppMonitor *monitor, const char *appid);
gboolean shell_app_monitor_is_window_usage_tracked (MetaWindow *window);
/* Get whatever's running right now */
GSList *shell_app_monitor_get_running_apps (ShellAppMonitor *monitor,
int activity);
GSList *shell_app_monitor_get_running_apps (ShellAppMonitor *monitor, const char *context);
GSList *shell_app_monitor_get_startup_sequences (ShellAppMonitor *monitor);
/* Hidden typedef for SnStartupSequence */
typedef struct _ShellStartupSequence ShellStartupSequence;
#define SHELL_TYPE_STARTUP_SEQUENCE (shell_startup_sequence_get_type ())
GType shell_startup_sequence_get_type (void);
const char *shell_startup_sequence_get_id (ShellStartupSequence *sequence);
const char *shell_startup_sequence_get_name (ShellStartupSequence *sequence);
gboolean shell_startup_sequence_get_completed (ShellStartupSequence *sequence);
ClutterActor *shell_startup_sequence_create_icon (ShellStartupSequence *sequence, guint size);
G_END_DECLS

View File

@ -1,19 +1,39 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include "shell-app-system.h"
#include <string.h>
#include <gio/gio.h>
#include <gio/gdesktopappinfo.h>
#include <gtk/gtk.h>
#include <gconf/gconf.h>
#include <gconf/gconf-client.h>
#include <clutter/clutter.h>
#include "shell-global.h"
#include "shell-texture-cache.h"
#include "display.h"
#define GMENU_I_KNOW_THIS_IS_UNSTABLE
#include <gmenu-tree.h>
#define SHELL_APP_FAVORITES_KEY "/desktop/gnome/shell/favorite_apps"
/* Vendor prefixes are something that can be preprended to a .desktop
* file name. Undo this.
*/
static const char*const known_vendor_prefixes[] = { "gnome",
"fedora",
"mozilla" };
enum {
PROP_0,
};
enum {
CHANGED,
INSTALLED_CHANGED,
FAVORITES_CHANGED,
LAST_SIGNAL
};
@ -23,17 +43,129 @@ struct _ShellAppSystemPrivate {
GMenuTree *apps_tree;
GMenuTree *settings_tree;
GHashTable *app_id_to_app;
GSList *cached_app_menus; /* ShellAppMenuEntry */
GSList *cached_setting_ids; /* utf8 */
GSList *cached_settings; /* ShellAppInfo */
GList *cached_favorites; /* utf8 */
gint app_monitor_id;
guint app_change_timeout_id;
};
static void shell_app_system_finalize (GObject *object);
static void on_tree_changed (GMenuTree *tree, gpointer user_data);
static gboolean on_tree_changed (gpointer user_data);
static void on_tree_changed_cb (GMenuTree *tree, gpointer user_data);
static void reread_menus (ShellAppSystem *self);
static void on_favorite_apps_changed (GConfClient *client, guint id, GConfEntry *entry, gpointer user_data);
static void reread_favorite_apps (ShellAppSystem *system);
G_DEFINE_TYPE(ShellAppSystem, shell_app_system, G_TYPE_OBJECT);
typedef enum {
SHELL_APP_INFO_TYPE_ENTRY,
SHELL_APP_INFO_TYPE_DESKTOP_FILE,
SHELL_APP_INFO_TYPE_WINDOW
} ShellAppInfoType;
struct _ShellAppInfo {
ShellAppInfoType type;
/* We need this for two reasons. First, GKeyFile doesn't have a refcount.
* http://bugzilla.gnome.org/show_bug.cgi?id=590808
*
* But more generally we'll always need it so we know when to free this
* structure (short of weak references on each item).
*/
guint refcount;
GMenuTreeItem *entry;
GKeyFile *keyfile;
char *keyfile_path;
MetaWindow *window;
char *window_id;
};
ShellAppInfo*
shell_app_info_ref (ShellAppInfo *info)
{
info->refcount++;
return info;
}
void
shell_app_info_unref (ShellAppInfo *info)
{
if (--info->refcount > 0)
return;
switch (info->type)
{
case SHELL_APP_INFO_TYPE_ENTRY:
gmenu_tree_item_unref (info->entry);
break;
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
g_key_file_free (info->keyfile);
g_free (info->keyfile_path);
break;
case SHELL_APP_INFO_TYPE_WINDOW:
g_object_unref (info->window);
g_free (info->window_id);
break;
}
g_slice_free (ShellAppInfo, info);
}
static ShellAppInfo *
shell_app_info_new_from_tree_item (GMenuTreeItem *item)
{
ShellAppInfo *info;
if (!item)
return NULL;
info = g_slice_alloc (sizeof (ShellAppInfo));
info->type = SHELL_APP_INFO_TYPE_ENTRY;
info->refcount = 1;
info->entry = gmenu_tree_item_ref (item);
return info;
}
static ShellAppInfo *
shell_app_info_new_from_window (MetaWindow *window)
{
ShellAppInfo *info;
info = g_slice_alloc (sizeof (ShellAppInfo));
info->type = SHELL_APP_INFO_TYPE_WINDOW;
info->refcount = 1;
info->window = g_object_ref (window);
/* For windows, its id is simply its pointer address as a string.
* There are various other alternatives, but the address is unique
* and unchanging, which is pretty much the best we can do.
*/
info->window_id = g_strdup_printf ("window:%p", window);
return info;
}
static ShellAppInfo *
shell_app_info_new_from_keyfile_take_ownership (GKeyFile *keyfile,
const char *path)
{
ShellAppInfo *info;
info = g_slice_alloc (sizeof (ShellAppInfo));
info->type = SHELL_APP_INFO_TYPE_DESKTOP_FILE;
info->refcount = 1;
info->keyfile = keyfile;
info->keyfile_path = g_strdup (path);
return info;
}
static gpointer
shell_app_menu_entry_copy (gpointer entryp)
{
@ -63,14 +195,22 @@ static void shell_app_system_class_init(ShellAppSystemClass *klass)
gobject_class->finalize = shell_app_system_finalize;
signals[CHANGED] =
g_signal_new ("changed",
signals[INSTALLED_CHANGED] =
g_signal_new ("installed-changed",
SHELL_TYPE_APP_SYSTEM,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ShellAppSystemClass, changed),
G_STRUCT_OFFSET (ShellAppSystemClass, installed_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[FAVORITES_CHANGED] =
g_signal_new ("favorites-changed",
SHELL_TYPE_APP_SYSTEM,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ShellAppSystemClass, favorites_changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
g_type_class_add_private (gobject_class, sizeof (ShellAppSystemPrivate));
}
@ -79,17 +219,35 @@ static void
shell_app_system_init (ShellAppSystem *self)
{
ShellAppSystemPrivate *priv;
GConfClient *client;
self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
SHELL_TYPE_APP_SYSTEM,
ShellAppSystemPrivate);
priv->apps_tree = gmenu_tree_lookup ("applications.menu", GMENU_TREE_FLAGS_NONE);
/* The key is owned by the value */
priv->app_id_to_app = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, (GDestroyNotify) shell_app_info_unref);
/* For now, we want to pick up Evince, Nautilus, etc. We'll
* handle NODISPLAY semantics at a higher level or investigate them
* case by case.
*/
priv->apps_tree = gmenu_tree_lookup ("applications.menu", GMENU_TREE_FLAGS_INCLUDE_NODISPLAY);
priv->settings_tree = gmenu_tree_lookup ("settings.menu", GMENU_TREE_FLAGS_NONE);
gmenu_tree_add_monitor (priv->apps_tree, on_tree_changed, self);
gmenu_tree_add_monitor (priv->settings_tree, on_tree_changed, self);
priv->app_change_timeout_id = 0;
gmenu_tree_add_monitor (priv->apps_tree, on_tree_changed_cb, self);
gmenu_tree_add_monitor (priv->settings_tree, on_tree_changed_cb, self);
reread_menus (self);
client = gconf_client_get_default ();
self->priv->app_monitor_id = gconf_client_notify_add (client, SHELL_APP_FAVORITES_KEY,
on_favorite_apps_changed, self, NULL, NULL);
reread_favorite_apps (self);
}
static void
@ -98,19 +256,25 @@ shell_app_system_finalize (GObject *object)
ShellAppSystem *self = SHELL_APP_SYSTEM (object);
ShellAppSystemPrivate *priv = self->priv;
gmenu_tree_remove_monitor (priv->apps_tree, on_tree_changed, self);
gmenu_tree_remove_monitor (priv->settings_tree, on_tree_changed, self);
gmenu_tree_remove_monitor (priv->apps_tree, on_tree_changed_cb, self);
gmenu_tree_remove_monitor (priv->settings_tree, on_tree_changed_cb, self);
gmenu_tree_unref (priv->apps_tree);
gmenu_tree_unref (priv->settings_tree);
g_hash_table_destroy (priv->app_id_to_app);
g_slist_foreach (priv->cached_app_menus, (GFunc)shell_app_menu_entry_free, NULL);
g_slist_free (priv->cached_app_menus);
priv->cached_app_menus = NULL;
g_slist_foreach (priv->cached_setting_ids, (GFunc)g_free, NULL);
g_slist_free (priv->cached_setting_ids);
priv->cached_setting_ids = NULL;
g_slist_foreach (priv->cached_settings, (GFunc)shell_app_info_unref, NULL);
g_slist_free (priv->cached_settings);
priv->cached_settings = NULL;
g_list_free (priv->cached_favorites);
gconf_client_notify_remove (gconf_client_get_default (), priv->app_monitor_id);
G_OBJECT_CLASS (shell_app_system_parent_class)->finalize(object);
}
@ -118,7 +282,6 @@ shell_app_system_finalize (GObject *object)
static void
reread_directories (ShellAppSystem *self, GSList **cache, GMenuTree *tree)
{
ShellAppSystemPrivate *priv = self->priv;
GMenuTreeDirectory *trunk;
GSList *entries;
GSList *iter;
@ -161,7 +324,7 @@ reread_directories (ShellAppSystem *self, GSList **cache, GMenuTree *tree)
static GSList *
gather_entries_recurse (ShellAppSystem *monitor,
GSList *ids,
GSList *apps,
GMenuTreeDirectory *root)
{
GSList *contents;
@ -176,15 +339,14 @@ gather_entries_recurse (ShellAppSystem *monitor,
{
case GMENU_TREE_ITEM_ENTRY:
{
GMenuTreeEntry *entry = (GMenuTreeEntry *)item;
const char *id = gmenu_tree_entry_get_desktop_file_id (entry);
ids = g_slist_prepend (ids, g_strdup (id));
ShellAppInfo *app = shell_app_info_new_from_tree_item (item);
apps = g_slist_prepend (apps, app);
}
break;
case GMENU_TREE_ITEM_DIRECTORY:
{
GMenuTreeDirectory *dir = (GMenuTreeDirectory*)item;
ids = gather_entries_recurse (monitor, ids, dir);
apps = gather_entries_recurse (monitor, apps, dir);
}
break;
default:
@ -195,7 +357,7 @@ gather_entries_recurse (ShellAppSystem *monitor,
g_slist_free (contents);
return ids;
return apps;
}
static void
@ -207,7 +369,7 @@ reread_entries (ShellAppSystem *self,
trunk = gmenu_tree_get_root_directory (tree);
g_slist_foreach (*cache, (GFunc)g_free, NULL);
g_slist_foreach (*cache, (GFunc)shell_app_info_unref, NULL);
g_slist_free (*cache);
*cache = NULL;
@ -217,20 +379,145 @@ reread_entries (ShellAppSystem *self,
}
static void
reread_menus (ShellAppSystem *self)
cache_by_id (ShellAppSystem *self, GSList *apps, gboolean ref)
{
reread_directories (self, &(self->priv->cached_app_menus), self->priv->apps_tree);
reread_entries (self, &(self->priv->cached_setting_ids), self->priv->settings_tree);
GSList *iter;
for (iter = apps; iter; iter = iter->next)
{
ShellAppInfo *info = iter->data;
if (ref)
shell_app_info_ref (info);
/* the name is owned by the info itself */
g_hash_table_insert (self->priv->app_id_to_app, (char*)shell_app_info_get_id (info),
info);
}
}
static void
on_tree_changed (GMenuTree *monitor, gpointer user_data)
reread_menus (ShellAppSystem *self)
{
GSList *apps;
GMenuTreeDirectory *trunk;
reread_directories (self, &(self->priv->cached_app_menus), self->priv->apps_tree);
reread_entries (self, &(self->priv->cached_settings), self->priv->settings_tree);
/* Now loop over applications.menu and settings.menu, inserting each by desktop file
* ID into a hash */
g_hash_table_remove_all (self->priv->app_id_to_app);
trunk = gmenu_tree_get_root_directory (self->priv->apps_tree);
apps = gather_entries_recurse (self, NULL, trunk);
gmenu_tree_item_unref (trunk);
cache_by_id (self, apps, FALSE);
g_slist_free (apps);
cache_by_id (self, self->priv->cached_settings, TRUE);
}
static gboolean
on_tree_changed (gpointer user_data)
{
ShellAppSystem *self = SHELL_APP_SYSTEM (user_data);
g_signal_emit (self, signals[INSTALLED_CHANGED], 0);
reread_menus (self);
self->priv->app_change_timeout_id = 0;
return FALSE;
}
static void
on_tree_changed_cb (GMenuTree *monitor, gpointer user_data)
{
ShellAppSystem *self = SHELL_APP_SYSTEM (user_data);
g_signal_emit (self, signals[CHANGED], 0);
/* GMenu currently gives us a separate notification on the entire
* menu tree for each node in the tree that might potentially have
* changed. (See http://bugzilla.gnome.org/show_bug.cgi?id=172046.)
* We need to compress these to avoid doing large extra amounts of
* work.
*
* Even when that bug is fixed, compression is still useful; for one
* thing we want to need to compress across notifications of changes
* to the settings tree. Second we want to compress if multiple
* changes are made to the desktop files at different times but in
* short succession.
*/
reread_menus (self);
if (self->priv->app_change_timeout_id != 0)
return;
self->priv->app_change_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 3000,
(GSourceFunc) on_tree_changed,
self, NULL);
}
static GList *
convert_gconf_value_string_list_to_list_uniquify (GConfValue *value )
{
GSList *list;
GSList *tmp;
GList *result = NULL;
GHashTable *tmp_table = g_hash_table_new (g_str_hash, g_str_equal);
list = gconf_value_get_list (value);
for (tmp = list ; tmp; tmp = tmp->next)
{
GConfValue *value = tmp->data;
char *str = g_strdup (gconf_value_get_string (value));
if (!str)
continue;
if (g_hash_table_lookup (tmp_table, str))
{
g_free (str);
continue;
}
g_hash_table_insert (tmp_table, str, GUINT_TO_POINTER(1));
result = g_list_prepend (result, str);
}
g_hash_table_destroy (tmp_table);
return g_list_reverse (result);
}
static void
reread_favorite_apps (ShellAppSystem *system)
{
GConfClient *client = gconf_client_get_default ();
GConfValue *val;
val = gconf_client_get (client, SHELL_APP_FAVORITES_KEY, NULL);
if (!(val && val->type == GCONF_VALUE_LIST && gconf_value_get_list_type (val) == GCONF_VALUE_STRING))
return;
g_list_foreach (system->priv->cached_favorites, (GFunc) g_free, NULL);
g_list_free (system->priv->cached_favorites);
system->priv->cached_favorites = convert_gconf_value_string_list_to_list_uniquify (val);
gconf_value_free (val);
}
void
on_favorite_apps_changed (GConfClient *client,
guint id,
GConfEntry *entry,
gpointer user_data)
{
ShellAppSystem *system = SHELL_APP_SYSTEM (user_data);
reread_favorite_apps (system);
g_signal_emit (G_OBJECT (system), signals[FAVORITES_CHANGED], 0);
}
GType
shell_app_info_get_type (void)
{
static GType gtype = G_TYPE_INVALID;
if (gtype == G_TYPE_INVALID)
{
gtype = g_boxed_type_register_static ("ShellAppInfo",
(GBoxedCopyFunc)shell_app_info_ref,
(GBoxedFreeFunc)shell_app_info_unref);
}
return gtype;
}
GType
@ -252,7 +539,7 @@ shell_app_menu_entry_get_type (void)
* Traverses a toplevel menu, and returns all items under it. Nested items
* are flattened.
*
* Return value: (transfer full) (element-type utf8): List of desktop file ids
* Return value: (transfer container) (element-type ShellAppInfo): List of applications
*/
GSList *
shell_app_system_get_applications_for_menu (ShellAppSystem *monitor,
@ -277,7 +564,7 @@ shell_app_system_get_applications_for_menu (ShellAppSystem *monitor,
/**
* shell_app_system_get_menus:
*
* Returns a list of toplevel menu names, like "Accessories", "Programming", etc.
* Returns a list of toplevel #ShellAppMenuEntry items
*
* Return value: (transfer none) (element-type AppMenuEntry): List of toplevel menus
*/
@ -290,14 +577,14 @@ shell_app_system_get_menus (ShellAppSystem *monitor)
/**
* shell_app_system_get_all_settings:
*
* Returns a list of all desktop file ids under "settings.menu".
* Returns a list of application items under "settings.menu".
*
* Return value: (transfer none) (element-type utf8): List of desktop file ids
* Return value: (transfer none) (element-type ShellAppInfo): List of applications
*/
GSList *
shell_app_system_get_all_settings (ShellAppSystem *monitor)
{
return monitor->priv->cached_setting_ids;
return monitor->priv->cached_settings;
}
/**
@ -315,3 +602,475 @@ shell_app_system_get_default ()
return instance;
}
/**
* shell_app_system_get_favorites:
*
* Return the list of applications which have been explicitly added to the
* favorites.
*
* Return value: (transfer none) (element-type utf8): List of favorite application ids
*/
GList *
shell_app_system_get_favorites (ShellAppSystem *system)
{
return system->priv->cached_favorites;
}
static void
set_gconf_value_string_list (GConfValue *val, GList *items)
{
GList *iter;
GSList *tmp = NULL;
for (iter = items; iter; iter = iter->next)
{
const char *str = iter->data;
GConfValue *strval = gconf_value_new (GCONF_VALUE_STRING);
gconf_value_set_string (strval, str);
tmp = g_slist_prepend (tmp, strval);
}
tmp = g_slist_reverse (tmp);
gconf_value_set_list (val, tmp);
g_slist_free (tmp);
}
void
shell_app_system_add_favorite (ShellAppSystem *system, const char *id)
{
GConfClient *client = gconf_client_get_default ();
GConfValue *val;
GList *iter;
iter = g_list_find_custom (system->priv->cached_favorites, id, (GCompareFunc)strcmp);
if (iter)
return;
val = gconf_value_new (GCONF_VALUE_LIST);
gconf_value_set_list_type (val, GCONF_VALUE_STRING);
system->priv->cached_favorites = g_list_append (system->priv->cached_favorites, g_strdup (id));
set_gconf_value_string_list (val, system->priv->cached_favorites);
gconf_client_set (client, SHELL_APP_FAVORITES_KEY, val, NULL);
}
void
shell_app_system_remove_favorite (ShellAppSystem *system, const char *id)
{
GConfClient *client = gconf_client_get_default ();
GConfValue *val;
GList *iter;
iter = g_list_find_custom (system->priv->cached_favorites, id, (GCompareFunc)strcmp);
if (!iter)
return;
g_free (iter->data);
system->priv->cached_favorites = g_list_delete_link (system->priv->cached_favorites, iter);
val = gconf_value_new (GCONF_VALUE_LIST);
gconf_value_set_list_type (val, GCONF_VALUE_STRING);
set_gconf_value_string_list (val, system->priv->cached_favorites);
gconf_client_set (client, SHELL_APP_FAVORITES_KEY, val, NULL);
}
/**
* shell_app_system_lookup_app:
*
* Return value: (transfer full): The #ShellAppInfo for id, or %NULL if none
*/
ShellAppInfo *
shell_app_system_lookup_cached_app (ShellAppSystem *self, const char *id)
{
ShellAppInfo *info;
info = g_hash_table_lookup (self->priv->app_id_to_app, id);
if (info)
shell_app_info_ref (info);
return info;
}
ShellAppInfo *
shell_app_system_load_from_desktop_file (ShellAppSystem *system,
const char *filename,
GError **error)
{
ShellAppInfo *appinfo;
GKeyFile *keyfile;
char *full_path = NULL;
gboolean success;
keyfile = g_key_file_new ();
if (strchr (filename, '/') != NULL)
{
success = g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, error);
full_path = g_strdup (filename);
}
else
{
char *app_path = g_build_filename ("applications", filename, NULL);
success = g_key_file_load_from_data_dirs (keyfile, app_path, &full_path,
G_KEY_FILE_NONE, error);
g_free (app_path);
}
if (!success)
{
g_key_file_free (keyfile);
g_free (full_path);
return NULL;
}
appinfo = shell_app_info_new_from_keyfile_take_ownership (keyfile, full_path);
g_free (full_path);
return appinfo;
}
/**
* shell_app_system_create_from_window:
*
* In the case where we can't otherwise determine an application
* associated with a window, this function can create a "fake"
* application just backed by information from the window itself.
*
* Return value: (transfer full): A new #ShellAppInfo
*/
ShellAppInfo *
shell_app_system_create_from_window (ShellAppSystem *system, MetaWindow *window)
{
return shell_app_info_new_from_window (window);
}
/**
* shell_app_system_lookup_heuristic_basename:
* @name: Probable application identifier
*
* Find a valid application corresponding to a given
* heuristically determined application identifier
* string, or %NULL if none.
*
* Returns: (transfer full): A #ShellAppInfo for name
*/
ShellAppInfo *
shell_app_system_lookup_heuristic_basename (ShellAppSystem *system,
const char *name)
{
ShellAppInfo *result;
char **vendor_prefixes;
result = shell_app_system_lookup_cached_app (system, name);
if (result != NULL)
return result;
for (vendor_prefixes = (char**)known_vendor_prefixes;
*vendor_prefixes; vendor_prefixes++)
{
char *tmpid = g_strjoin (NULL, *vendor_prefixes, "-", name, NULL);
result = shell_app_system_lookup_cached_app (system, tmpid);
g_free (tmpid);
if (result != NULL)
return result;
}
return NULL;
}
const char *
shell_app_info_get_id (ShellAppInfo *info)
{
switch (info->type)
{
case SHELL_APP_INFO_TYPE_ENTRY:
return gmenu_tree_entry_get_desktop_file_id ((GMenuTreeEntry*)info->entry);
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
return info->keyfile_path;
case SHELL_APP_INFO_TYPE_WINDOW:
return info->window_id;
}
g_assert_not_reached ();
return NULL;
}
#define DESKTOP_ENTRY_GROUP "Desktop Entry"
char *
shell_app_info_get_name (ShellAppInfo *info)
{
switch (info->type)
{
case SHELL_APP_INFO_TYPE_ENTRY:
return g_strdup (gmenu_tree_entry_get_name ((GMenuTreeEntry*)info->entry));
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
return g_key_file_get_locale_string (info->keyfile, DESKTOP_ENTRY_GROUP, "Name", NULL, NULL);
case SHELL_APP_INFO_TYPE_WINDOW:
{
char *title;
g_object_get (info->window, "title", &title, NULL);
return title;
}
}
g_assert_not_reached ();
return NULL;
}
char *
shell_app_info_get_description (ShellAppInfo *info)
{
switch (info->type)
{
case SHELL_APP_INFO_TYPE_ENTRY:
return g_strdup (gmenu_tree_entry_get_comment ((GMenuTreeEntry*)info->entry));
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
return g_key_file_get_locale_string (info->keyfile, DESKTOP_ENTRY_GROUP, "Comment", NULL, NULL);
case SHELL_APP_INFO_TYPE_WINDOW:
return NULL;
}
g_assert_not_reached ();
return NULL;
}
char *
shell_app_info_get_executable (ShellAppInfo *info)
{
switch (info->type)
{
case SHELL_APP_INFO_TYPE_ENTRY:
return g_strdup (gmenu_tree_entry_get_exec ((GMenuTreeEntry*)info->entry));
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
return g_key_file_get_string (info->keyfile, DESKTOP_ENTRY_GROUP, "Exec", NULL);
case SHELL_APP_INFO_TYPE_WINDOW:
return NULL;
}
g_assert_not_reached ();
return NULL;
}
char *
shell_app_info_get_desktop_file_path (ShellAppInfo *info)
{
switch (info->type)
{
case SHELL_APP_INFO_TYPE_ENTRY:
return g_strdup (gmenu_tree_entry_get_desktop_file_path ((GMenuTreeEntry*)info->entry));
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
return g_strdup (info->keyfile_path);
case SHELL_APP_INFO_TYPE_WINDOW:
return NULL;
}
g_assert_not_reached ();
return NULL;
}
static GIcon *
themed_icon_from_name (const char *iconname)
{
GIcon *icon;
if (!iconname)
return NULL;
if (g_path_is_absolute (iconname))
{
GFile *file;
file = g_file_new_for_path (iconname);
icon = G_ICON (g_file_icon_new (file));
g_object_unref (file);
}
else
{
char *tmp_name, *p;
tmp_name = strdup (iconname);
/* Work around a common mistake in desktop files */
if ((p = strrchr (tmp_name, '.')) != NULL &&
(strcmp (p, ".png") == 0 ||
strcmp (p, ".xpm") == 0 ||
strcmp (p, ".svg") == 0))
{
*p = 0;
}
icon = g_themed_icon_new (tmp_name);
g_free (tmp_name);
}
return icon;
}
static GIcon *
shell_app_info_get_icon (ShellAppInfo *info)
{
char *iconname = NULL;
GIcon *icon;
/* This code adapted from gdesktopappinfo.c
* Copyright (C) 2006-2007 Red Hat, Inc.
* Copyright © 2007 Ryan Lortie
* LGPL
*/
switch (info->type)
{
case SHELL_APP_INFO_TYPE_ENTRY:
return themed_icon_from_name (gmenu_tree_entry_get_icon ((GMenuTreeEntry*)info->entry));
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
iconname = g_key_file_get_locale_string (info->keyfile, DESKTOP_ENTRY_GROUP, "Icon", NULL, NULL);
icon = themed_icon_from_name (iconname);
g_free (iconname);
return icon;
break;
case SHELL_APP_INFO_TYPE_WINDOW:
return NULL;
}
g_assert_not_reached ();
return NULL;
}
GSList *
shell_app_info_get_categories (ShellAppInfo *info)
{
return NULL; /* TODO */
}
gboolean
shell_app_info_get_is_nodisplay (ShellAppInfo *info)
{
switch (info->type)
{
case SHELL_APP_INFO_TYPE_ENTRY:
return gmenu_tree_entry_get_is_nodisplay ((GMenuTreeEntry*)info->entry);
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
case SHELL_APP_INFO_TYPE_WINDOW:
return FALSE;
}
g_assert_not_reached ();
return TRUE;
}
/**
* shell_app_info_is_transient:
*
* A "transient" application is one which represents
* just an open window, i.e. we don't know how to launch it
* again.
*/
gboolean
shell_app_info_is_transient (ShellAppInfo *info)
{
return info->type == SHELL_APP_INFO_TYPE_WINDOW;
}
/**
* shell_app_info_create_icon_texture:
*
* Look up the icon for this application, and create a #ClutterTexture
* for it at the given size.
*
* Return value: (transfer none): A floating #ClutterActor
*/
ClutterActor *
shell_app_info_create_icon_texture (ShellAppInfo *info, float size)
{
GIcon *icon;
ClutterActor *ret;
if (info->type == SHELL_APP_INFO_TYPE_WINDOW)
{
return shell_texture_cache_bind_pixbuf_property (shell_texture_cache_get_default (),
G_OBJECT (info->window),
"icon");
}
icon = shell_app_info_get_icon (info);
if (!icon)
{
ret = clutter_texture_new ();
g_object_set (ret, "opacity", 0, "width", size, "height", size, NULL);
return ret;
}
return shell_texture_cache_load_gicon (shell_texture_cache_get_default (), icon, (int)size);
}
/**
* shell_app_info_launch_full:
* @timestamp: Event timestamp, or 0 for current event timestamp
* @uris: List of uris to pass to application
* @workspace: Start on this workspace, or -1 for default
* @startup_id: (out): Returned startup notification ID, or %NULL if none
* @error: A #GError
*/
gboolean
shell_app_info_launch_full (ShellAppInfo *info,
guint timestamp,
GList *uris,
int workspace,
char **startup_id,
GError **error)
{
GDesktopAppInfo *gapp;
char *filename;
GdkAppLaunchContext *context;
gboolean ret;
ShellGlobal *global;
MetaScreen *screen;
MetaDisplay *display;
if (startup_id)
*startup_id = NULL;
if (info->type == SHELL_APP_INFO_TYPE_WINDOW)
{
/* We can't pass URIs into a window; shouldn't hit this
* code path. If we do, fix the caller to disallow it.
*/
g_return_val_if_fail (uris == NULL, TRUE);
meta_window_activate (info->window, timestamp);
return TRUE;
}
filename = shell_app_info_get_desktop_file_path (info);
gapp = g_desktop_app_info_new_from_filename (filename);
g_free (filename);
if (!gapp)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Not found");
return FALSE;
}
global = shell_global_get ();
screen = shell_global_get_screen (global);
display = meta_screen_get_display (screen);
if (timestamp == 0)
timestamp = clutter_get_current_event_time ();
/* Shell design calls for on application launch, no window is focused,
* and we have startup notification displayed.
*/
meta_display_focus_the_no_focus_window (display, screen, timestamp);
if (workspace < 0)
workspace = meta_screen_get_active_workspace_index (screen);
context = gdk_app_launch_context_new ();
gdk_app_launch_context_set_timestamp (context, timestamp);
gdk_app_launch_context_set_desktop (context, workspace);
ret = g_app_info_launch (G_APP_INFO (gapp), uris, (GAppLaunchContext*) context, error);
g_object_unref (G_OBJECT (gapp));
return ret;
}
gboolean
shell_app_info_launch (ShellAppInfo *info,
GError **error)
{
return shell_app_info_launch_full (info, 0, NULL, -1, NULL, error);
}

View File

@ -1,7 +1,10 @@
#ifndef __SHELL_APP_SYSTEM_H__
#define __SHELL_APP_SYSTEM_H__
#include <glib-object.h>
#include <gio/gio.h>
#include <clutter/clutter.h>
#include "window.h"
#define SHELL_TYPE_APP_SYSTEM (shell_app_system_get_type ())
#define SHELL_APP_SYSTEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_APP_SYSTEM, ShellAppSystem))
@ -25,7 +28,8 @@ struct _ShellAppSystemClass
{
GObjectClass parent_class;
void (*changed)(ShellAppSystem *appsys, gpointer data);
void (*installed_changed)(ShellAppSystem *appsys, gpointer user_data);
void (*favorites_changed)(ShellAppSystem *appsys, gpointer user_data);
};
GType shell_app_system_get_type (void) G_GNUC_CONST;
@ -43,8 +47,48 @@ struct _ShellAppMenuEntry {
GType shell_app_menu_entry_get_type (void);
typedef struct _ShellAppInfo ShellAppInfo;
#define SHELL_TYPE_APP_INFO (shell_app_info_get_type ())
GType shell_app_info_get_type (void);
ShellAppInfo* shell_app_info_ref (ShellAppInfo *info);
void shell_app_info_unref (ShellAppInfo *info);
const char *shell_app_info_get_id (ShellAppInfo *info);
char *shell_app_info_get_name (ShellAppInfo *info);
char *shell_app_info_get_description (ShellAppInfo *info);
char *shell_app_info_get_executable (ShellAppInfo *info);
char *shell_app_info_get_desktop_file_path (ShellAppInfo *info);
ClutterActor *shell_app_info_create_icon_texture (ShellAppInfo *info, float size);
GSList *shell_app_info_get_categories (ShellAppInfo *info);
gboolean shell_app_info_get_is_nodisplay (ShellAppInfo *info);
gboolean shell_app_info_is_transient (ShellAppInfo *info);
gboolean shell_app_info_launch_full (ShellAppInfo *info,
guint timestamp,
GList *uris,
int workspace,
char **startup_id,
GError **error);
gboolean shell_app_info_launch (ShellAppInfo *info,
GError **error);
ShellAppInfo *shell_app_system_load_from_desktop_file (ShellAppSystem *system, const char *filename, GError **error);
ShellAppInfo *shell_app_system_lookup_cached_app (ShellAppSystem *system, const char *id);
ShellAppInfo *shell_app_system_lookup_heuristic_basename (ShellAppSystem *system, const char *id);
ShellAppInfo *shell_app_system_create_from_window (ShellAppSystem *system, MetaWindow *window);
GSList *shell_app_system_get_menus (ShellAppSystem *system);
GSList *shell_app_system_get_all_settings (ShellAppSystem *system);
GList *shell_app_system_get_favorites (ShellAppSystem *system);
void shell_app_system_add_favorite (ShellAppSystem *system, const char *id);
void shell_app_system_remove_favorite (ShellAppSystem *system, const char *id);
#endif /* __SHELL_APP_SYSTEM_H__ */

317
src/shell-button-box.c Normal file
View File

@ -0,0 +1,317 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* SECTION:shell-button-box
* @short_description: A box with properties useful for implementing buttons
*
* A #BigBox subclass which translates lower-level Clutter button events
* into higher level properties which are useful for implementing "button-like"
* actors.
*/
#include "shell-button-box.h"
G_DEFINE_TYPE(ShellButtonBox, shell_button_box, BIG_TYPE_BOX);
struct _ShellButtonBoxPrivate {
gboolean active;
gboolean held;
gboolean hover;
gboolean pressed;
};
/* Signals */
enum
{
ACTIVATE,
LAST_SIGNAL
};
enum {
PROP_0,
PROP_ACTIVE,
PROP_HOVER,
PROP_PRESSED,
};
static guint shell_button_box_signals [LAST_SIGNAL] = { 0 };
static void
set_active (ShellButtonBox *box,
gboolean active)
{
if (box->priv->active == active)
return;
box->priv->active = active;
g_object_notify (G_OBJECT (box), "active");
}
static void
set_hover (ShellButtonBox *box,
gboolean hover)
{
if (box->priv->hover == hover)
return;
box->priv->hover = hover;
g_object_notify (G_OBJECT (box), "hover");
}
static void
set_pressed (ShellButtonBox *box,
gboolean pressed)
{
if (box->priv->pressed == pressed)
return;
box->priv->pressed = pressed;
g_object_notify (G_OBJECT (box), "pressed");
}
static gboolean
shell_button_box_contains (ShellButtonBox *box,
ClutterActor *actor)
{
while (actor != NULL && actor != (ClutterActor*)box)
{
actor = clutter_actor_get_parent (actor);
}
return actor != NULL;
}
static gboolean
shell_button_box_enter_event (ClutterActor *actor,
ClutterCrossingEvent *event)
{
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
if (shell_button_box_contains (box, event->related))
return TRUE;
if (!shell_button_box_contains (box, event->source))
return TRUE;
g_object_freeze_notify (G_OBJECT (actor));
if (box->priv->held)
set_pressed (box, TRUE);
set_hover (box, TRUE);
g_object_thaw_notify (G_OBJECT (actor));
return TRUE;
}
static gboolean
shell_button_box_leave_event (ClutterActor *actor,
ClutterCrossingEvent *event)
{
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
if (shell_button_box_contains (box, event->related))
return TRUE;
set_hover (box, FALSE);
set_pressed (box, FALSE);
return TRUE;
}
static gboolean
shell_button_box_button_press_event (ClutterActor *actor,
ClutterButtonEvent *event)
{
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
if (event->button != 1 || event->click_count != 1)
return FALSE;
if (box->priv->held)
return TRUE;
if (!shell_button_box_contains (box, event->source))
return FALSE;
box->priv->held = TRUE;
clutter_grab_pointer (CLUTTER_ACTOR (box));
set_pressed (box, TRUE);
return TRUE;
}
static gboolean
shell_button_box_button_release_event (ClutterActor *actor,
ClutterButtonEvent *event)
{
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
if (event->button != 1 || event->click_count != 1)
return FALSE;
if (!box->priv->held)
return TRUE;
box->priv->held = FALSE;
clutter_ungrab_pointer ();
if (!shell_button_box_contains (box, event->source))
return FALSE;
set_pressed (box, FALSE);
g_signal_emit (G_OBJECT (box), shell_button_box_signals[ACTIVATE], 0, event);
return TRUE;
}
/**
* shell_button_box_fake_release:
* @box:
*
* If this button box is holding a pointer grab, this function will
* will ungrab it, and reset the pressed state. The effect is
* similar to if the user had released the mouse button, but without
* emitting the activate signal.
*
* This function is useful if for example you want to do something after the user
* is holding the mouse button for a given period of time, breaking the
* grab.
*/
void
shell_button_box_fake_release (ShellButtonBox *box)
{
if (!box->priv->held)
return;
box->priv->held = FALSE;
clutter_ungrab_pointer ();
set_pressed (box, FALSE);
}
static void
shell_button_box_set_property(GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ShellButtonBox *box = SHELL_BUTTON_BOX (object);
switch (prop_id)
{
case PROP_ACTIVE:
set_active (box, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
shell_button_box_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ShellButtonBox *box = SHELL_BUTTON_BOX (object);
switch (prop_id)
{
case PROP_ACTIVE:
g_value_set_boolean (value, box->priv->active);
break;
case PROP_PRESSED:
g_value_set_boolean (value, box->priv->pressed);
break;
case PROP_HOVER:
g_value_set_boolean (value, box->priv->hover);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
shell_button_box_class_init (ShellButtonBoxClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->get_property = shell_button_box_get_property;
gobject_class->set_property = shell_button_box_set_property;
actor_class->enter_event = shell_button_box_enter_event;
actor_class->leave_event = shell_button_box_leave_event;
actor_class->button_press_event = shell_button_box_button_press_event;
actor_class->button_release_event = shell_button_box_button_release_event;
/**
* ShellButtonBox::activate
* @box: The #ShellButtonBox
* @event: Release event which triggered the activation
*
* This signal is emitted when the button should take the action
* associated with button click+release.
*/
shell_button_box_signals[ACTIVATE] =
g_signal_new ("activate",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 1, CLUTTER_TYPE_EVENT);
/**
* ShellButtonBox:active
*
* The property allows the button to be used as a "toggle button"; it's up to the
* application to update the active property in response to the activate signal;
* it doesn't happen automatically.
*/
g_object_class_install_property (gobject_class,
PROP_ACTIVE,
g_param_spec_boolean ("active",
"Active",
"Whether the button persistently active",
FALSE,
G_PARAM_READWRITE));
/**
* ShellButtonBox:hover
*
* This property tracks whether the mouse is over the button; note this
* state is independent of whether the button is pressed.
*/
g_object_class_install_property (gobject_class,
PROP_HOVER,
g_param_spec_boolean ("hover",
"Hovering state",
"Whether the mouse is over the button",
FALSE,
G_PARAM_READABLE));
/**
* ShellButtonBox:pressed
*
* This property tracks whether the button should have a "pressed in"
* effect.
*/
g_object_class_install_property (gobject_class,
PROP_PRESSED,
g_param_spec_boolean ("pressed",
"Pressed state",
"Whether the button is currently pressed",
FALSE,
G_PARAM_READABLE));
g_type_class_add_private (gobject_class, sizeof (ShellButtonBoxPrivate));
}
static void
shell_button_box_init (ShellButtonBox *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SHELL_TYPE_BUTTON_BOX,
ShellButtonBoxPrivate);
}

35
src/shell-button-box.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef __SHELL_BUTTON_BOX_H__
#define __SHELL_BUTTON_BOX_H__
#include <clutter/clutter.h>
#include "big/box.h"
#define SHELL_TYPE_BUTTON_BOX (shell_button_box_get_type ())
#define SHELL_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_BUTTON_BOX, ShellButtonBox))
#define SHELL_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_BUTTON_BOX, ShellButtonBoxClass))
#define SHELL_IS_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_BUTTON_BOX))
#define SHELL_IS_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_BUTTON_BOX))
#define SHELL_BUTTON_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_BUTTON_BOX, ShellButtonBoxClass))
typedef struct _ShellButtonBox ShellButtonBox;
typedef struct _ShellButtonBoxClass ShellButtonBoxClass;
typedef struct _ShellButtonBoxPrivate ShellButtonBoxPrivate;
struct _ShellButtonBox
{
BigBox parent;
ShellButtonBoxPrivate *priv;
};
struct _ShellButtonBoxClass
{
BigBoxClass parent_class;
};
GType shell_button_box_get_type (void) G_GNUC_CONST;
void shell_button_box_fake_release (ShellButtonBox *box);
#endif /* __SHELL_BUTTON_BOX_H__ */

102
src/shell-drawing-area.c Normal file
View File

@ -0,0 +1,102 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* SECTION:shell-drawing-area
* @short_description: A dynamically-sized Cairo drawing area
*
* #ShellDrawingArea is similar to #ClutterCairoTexture in that
* it allows drawing via Cairo; the primary difference is that
* it is dynamically sized. To use, connect to the @redraw
* signal, and inside the signal handler, call
* clutter_cairo_texture_create() to begin drawing.
*/
#include "shell-drawing-area.h"
#include <clutter/clutter.h>
#include <gtk/gtk.h>
#include <cairo.h>
G_DEFINE_TYPE(ShellDrawingArea, shell_drawing_area, CLUTTER_TYPE_GROUP);
struct _ShellDrawingAreaPrivate {
ClutterCairoTexture *texture;
};
/* Signals */
enum
{
REDRAW,
LAST_SIGNAL
};
static guint shell_drawing_area_signals [LAST_SIGNAL] = { 0 };
static void
shell_drawing_area_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ShellDrawingArea *area = SHELL_DRAWING_AREA (self);
int width = box->x2 - box->x1;
int height = box->y2 - box->y1;
ClutterActorBox child_box;
/* Chain up directly to ClutterActor to set actor->allocation. We explicitly skip our parent class
* ClutterGroup here because we want to override the allocate function. */
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (self, box, flags);
child_box.x1 = 0;
child_box.x2 = width;
child_box.y1 = 0;
child_box.y2 = height;
clutter_actor_allocate (CLUTTER_ACTOR (area->priv->texture), &child_box, flags);
if (width > 0 && height > 0)
{
clutter_cairo_texture_set_surface_size (area->priv->texture,
width, height);
g_signal_emit (G_OBJECT (self), shell_drawing_area_signals[REDRAW], 0,
area->priv->texture);
}
}
static void
shell_drawing_area_class_init (ShellDrawingAreaClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->allocate = shell_drawing_area_allocate;
shell_drawing_area_signals[REDRAW] =
g_signal_new ("redraw",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ShellDrawingAreaClass, redraw),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, G_TYPE_OBJECT);
g_type_class_add_private (gobject_class, sizeof (ShellDrawingAreaPrivate));
}
static void
shell_drawing_area_init (ShellDrawingArea *area)
{
area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, SHELL_TYPE_DRAWING_AREA,
ShellDrawingAreaPrivate);
area->priv->texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (1, 1));
clutter_container_add_actor (CLUTTER_CONTAINER (area), CLUTTER_ACTOR (area->priv->texture));
}
/**
* shell_drawing_area_get_texture:
*
* Return Value: (transfer none):
*/
ClutterCairoTexture *
shell_drawing_area_get_texture (ShellDrawingArea *area)
{
return area->priv->texture;
}

37
src/shell-drawing-area.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __SHELL_DRAWING_AREA_H__
#define __SHELL_DRAWING_AREA_H__
#include <clutter/clutter.h>
#include <gtk/gtk.h>
#define SHELL_TYPE_DRAWING_AREA (shell_drawing_area_get_type ())
#define SHELL_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_DRAWING_AREA, ShellDrawingArea))
#define SHELL_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_DRAWING_AREA, ShellDrawingAreaClass))
#define SHELL_IS_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_DRAWING_AREA))
#define SHELL_IS_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_DRAWING_AREA))
#define SHELL_DRAWING_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_DRAWING_AREA, ShellDrawingAreaClass))
typedef struct _ShellDrawingArea ShellDrawingArea;
typedef struct _ShellDrawingAreaClass ShellDrawingAreaClass;
typedef struct _ShellDrawingAreaPrivate ShellDrawingAreaPrivate;
struct _ShellDrawingArea
{
ClutterGroup parent;
ShellDrawingAreaPrivate *priv;
};
struct _ShellDrawingAreaClass
{
ClutterGroupClass parent_class;
void (*redraw) (ShellDrawingArea *area, ClutterCairoTexture *texture);
};
GType shell_drawing_area_get_type (void) G_GNUC_CONST;
ClutterCairoTexture *shell_drawing_area_get_texture (ShellDrawingArea *area);
#endif /* __SHELL_DRAWING_AREA_H__ */

212
src/shell-drawing.c Normal file
View File

@ -0,0 +1,212 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include "shell-drawing.h"
#include <math.h>
/**
* shell_create_vertical_gradient:
* @top: the color at the top
* @bottom: the color at the bottom
*
* Creates a vertical gradient actor.
*
* Return value: (transfer none): a #ClutterCairoTexture actor with the
* gradient. The texture actor is floating, hence (transfer none).
*/
ClutterCairoTexture *
shell_create_vertical_gradient (ClutterColor *top,
ClutterColor *bottom)
{
ClutterCairoTexture *texture;
cairo_t *cr;
cairo_pattern_t *pattern;
/* Draw the gradient on an 8x8 pixel texture. Because the gradient is drawn
* from the uppermost to the lowermost row, after stretching 1/16 of the
* texture height has the top color and 1/16 has the bottom color. The 8
* pixel width is chosen for reasons related to graphics hardware internals.
*/
texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (8, 8));
cr = clutter_cairo_texture_create (texture);
pattern = cairo_pattern_create_linear (0, 0, 0, 8);
cairo_pattern_add_color_stop_rgba (pattern, 0,
top->red / 255.,
top->green / 255.,
top->blue / 255.,
top->alpha / 255.);
cairo_pattern_add_color_stop_rgba (pattern, 1,
bottom->red / 255.,
bottom->green / 255.,
bottom->blue / 255.,
bottom->alpha / 255.);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
cairo_destroy (cr);
return texture;
}
/**
* shell_create_horizontal_gradient:
* @left: the color on the left
* @right: the color on the right
*
* Creates a horizontal gradient actor.
*
* Return value: (transfer none): a #ClutterCairoTexture actor with the
* gradient. The texture actor is floating, hence (transfer none).
*/
ClutterCairoTexture *
shell_create_horizontal_gradient (ClutterColor *left,
ClutterColor *right)
{
ClutterCairoTexture *texture;
cairo_t *cr;
cairo_pattern_t *pattern;
/* Draw the gradient on an 8x1 pixel texture. Because the gradient is drawn
* from the left to the right column, after stretching 1/16 of the
* texture width has the left side color and 1/16 has the right side color.
* There is no reason to use the 8 pixel height that would be similar to the
* reason we are using the 8 pixel width for the vertical gradient, so we
* are just using the 1 pixel height instead.
*/
texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (8, 1));
cr = clutter_cairo_texture_create (texture);
pattern = cairo_pattern_create_linear (0, 0, 8, 0);
cairo_pattern_add_color_stop_rgba (pattern, 0,
left->red / 255.,
left->green / 255.,
left->blue / 255.,
left->alpha / 255.);
cairo_pattern_add_color_stop_rgba (pattern, 1,
right->red / 255.,
right->green / 255.,
right->blue / 255.,
right->alpha / 255.);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
cairo_destroy (cr);
return texture;
}
void
shell_draw_clock (ClutterCairoTexture *texture,
int hour,
int minute)
{
cairo_t *cr;
guint width, height;
double xc, yc, radius, hour_radius, minute_radius;
double angle;
clutter_cairo_texture_get_surface_size (texture, &width, &height);
xc = (double)width / 2;
yc = (double)height / 2;
radius = (double)(MIN(width, height)) / 2 - 2;
minute_radius = radius - 3;
hour_radius = radius / 2;
clutter_cairo_texture_clear (texture);
cr = clutter_cairo_texture_create (texture);
cairo_set_line_width (cr, 1.0);
/* Outline */
cairo_arc (cr, xc, yc, radius, 0.0, 2.0 * M_PI);
cairo_stroke (cr);
/* Hour hand. (We add a fraction to @hour for the minutes, then
* convert to radians, and then subtract pi/2 because cairo's origin
* is at 3:00, not 12:00.)
*/
angle = ((hour + minute / 60.0) / 12.0) * 2.0 * M_PI - M_PI / 2.0;
cairo_move_to (cr, xc, yc);
cairo_line_to (cr,
xc + hour_radius * cos (angle),
yc + hour_radius * sin (angle));
cairo_stroke (cr);
/* Minute hand */
angle = (minute / 60.0) * 2.0 * M_PI - M_PI / 2.0;
cairo_move_to (cr, xc, yc);
cairo_line_to (cr,
xc + minute_radius * cos (angle),
yc + minute_radius * sin (angle));
cairo_stroke (cr);
cairo_destroy (cr);
}
void
shell_draw_box_pointer (ClutterCairoTexture *texture,
ClutterColor *border_color,
ClutterColor *background_color)
{
guint width, height;
cairo_t *cr;
clutter_cairo_texture_get_surface_size (texture, &width, &height);
clutter_cairo_texture_clear (texture);
cr = clutter_cairo_texture_create (texture);
cairo_set_line_width (cr, 1.0);
clutter_cairo_set_source_color (cr, border_color);
cairo_move_to (cr, width, 0);
cairo_line_to (cr, 0, floor (height * 0.5));
cairo_line_to (cr, width, height);
cairo_stroke_preserve (cr);
clutter_cairo_set_source_color (cr, background_color);
cairo_fill (cr);
cairo_destroy (cr);
}
static void
hook_paint_red_border (ClutterActor *actor,
gpointer user_data)
{
CoglColor color;
ClutterGeometry geom;
float width = 2;
float x2;
float y2;
cogl_color_set_from_4ub (&color, 0xff, 0, 0, 0xc4);
cogl_set_source_color (&color);
clutter_actor_get_allocation_geometry (actor, &geom);
x2 = geom.x + geom.width;
y2 = geom.y + geom.height;
/** clockwise order **/
cogl_rectangle (geom.x, geom.y,
x2, geom.y + width);
cogl_rectangle (x2 - width, geom.y + width,
x2, y2);
cogl_rectangle (x2 - width, y2,
geom.x, y2 - width);
cogl_rectangle (geom.x + width, y2 - width,
geom.x, geom.y + width);
}
guint
shell_add_hook_paint_red_border (ClutterActor *actor)
{
return g_signal_connect_after (G_OBJECT (actor), "paint",
G_CALLBACK (hook_paint_red_border), NULL);
}

28
src/shell-drawing.h Normal file
View File

@ -0,0 +1,28 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef __SHELL_DRAWING_H__
#define __SHELL_DRAWING_H__
#include <clutter/clutter.h>
G_BEGIN_DECLS
ClutterCairoTexture *shell_create_vertical_gradient (ClutterColor *top,
ClutterColor *bottom);
ClutterCairoTexture *shell_create_horizontal_gradient (ClutterColor *left,
ClutterColor *right);
void shell_draw_box_pointer (ClutterCairoTexture *texture,
ClutterColor *border_color,
ClutterColor *background_color);
void shell_draw_clock (ClutterCairoTexture *texture,
int hour,
int minute);
guint shell_add_hook_paint_red_border (ClutterActor *actor);
G_END_DECLS
#endif /* __SHELL_GLOBAL_H__ */

396
src/shell-gconf.c Normal file
View File

@ -0,0 +1,396 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include "shell-gconf.h"
#include <gconf/gconf-client.h>
#include <string.h>
/**
* ShellGConf:
*
* A wrapper around #GConfClient that cleans up some of its
* non-gjs-bindable bits and makes a few gnome-shell-specific
* assumptions.
*
* For all #ShellGConf methods that take a GConf key path as an
* argument, you can pass either a full path (eg,
* "/desktop/gnome/shell/sidebar/visible"), or just a relative path
* starting from the root of the gnome-shell GConf key hierarchy (eg,
* "sidebar/visible").
*/
struct _ShellGConf
{
GObject parent;
GConfClient *client;
};
G_DEFINE_TYPE (ShellGConf, shell_gconf, G_TYPE_OBJECT);
/* Signals */
enum
{
CHANGED,
LAST_SIGNAL
};
static guint shell_gconf_signals [LAST_SIGNAL] = { 0 };
static void gconf_value_changed (GConfClient *client, const char *key,
GConfValue *new_value, gpointer user_data);
static void
shell_gconf_init (ShellGConf *gconf)
{
gconf->client = gconf_client_get_default ();
gconf_client_add_dir (gconf->client, SHELL_GCONF_DIR,
GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
g_signal_connect (gconf->client, "value_changed",
G_CALLBACK (gconf_value_changed), gconf);
}
static void
shell_gconf_finalize (GObject *object)
{
ShellGConf *gconf = SHELL_GCONF (object);
g_signal_handlers_disconnect_by_func (gconf->client,
gconf_value_changed, gconf);
g_object_unref (gconf->client);
G_OBJECT_CLASS (shell_gconf_parent_class)->finalize (object);
}
static void
shell_gconf_class_init (ShellGConfClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = shell_gconf_finalize;
/**
* ShellGConf::changed:
* @gconf: the #ShellGConf
*
* Emitted when a key in a watched directory is changed. The signal
* detail indicates which key changed. Eg, connect to
* "changed::sidebar/visible" to be notified when "sidebar/visible"
* changes. For gnome-shell's own GConf keys, the signal detail will
* be the relative path from the top of the gnome-shell GConf
* hierarchy ("/desktop/gnome/shell"). If you want to be notified
* about the value of a non-gnome-shell key, you must first call
* shell_gconf_watch_directory(), and then use the full GConf key path
* as the signal detail.
*/
shell_gconf_signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
G_STRUCT_OFFSET (ShellGConfClass, changed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
/**
* shell_gconf_get_default:
*
* Gets the default #ShellGConf
*
* Return value: (transfer none): the default #ShellGConf
*/
ShellGConf *
shell_gconf_get_default (void)
{
static ShellGConf *gconf = NULL;
if (!gconf)
gconf = g_object_new (SHELL_TYPE_GCONF, NULL);
return gconf;
}
/**
* shell_gconf_watch_directory:
* @gconf: a #ShellGConf
* @directory: the path of a GConf directory to watch for changes in
*
* Adds @directory to the list of directories to watch; you must call
* this before connecting to #ShellGConf::changed for a key outside of
* the gnome-shell GConf tree.
*/
void
shell_gconf_watch_directory (ShellGConf *gconf, const char *directory)
{
gconf_client_add_dir (gconf->client, directory,
GCONF_CLIENT_PRELOAD_NONE, NULL);
}
static void
gconf_value_changed (GConfClient *client, const char *key,
GConfValue *new_value, gpointer user_data)
{
ShellGConf *gconf = user_data;
GQuark detail;
if (g_str_has_prefix (key, SHELL_GCONF_DIR "/"))
key += strlen (SHELL_GCONF_DIR "/");
/* This will create a lot of junk quarks, but it's the best we
* can do with gjs's current callback support.
*/
detail = g_quark_from_string (key);
g_signal_emit (gconf, shell_gconf_signals[CHANGED], detail);
}
static char *
resolve_key (const char *key)
{
if (*key == '/')
return g_strdup (key);
else
return g_build_filename (SHELL_GCONF_DIR, key, NULL);
}
#define SIMPLE_GETTER(NAME, TYPE, GCONF_GETTER) \
TYPE \
NAME (ShellGConf *gconf, const char *key, GError **error) \
{ \
char *get_key = resolve_key (key); \
TYPE value; \
\
value = GCONF_GETTER (gconf->client, get_key, error); \
g_free (get_key); \
return value; \
}
#define LIST_GETTER(NAME, ELEMENT_TYPE) \
GSList * \
NAME (ShellGConf *gconf, const char *key, GError **error) \
{ \
char *get_key = resolve_key (key); \
GSList *value; \
\
value = gconf_client_get_list (gconf->client, get_key, \
ELEMENT_TYPE, error); \
g_free (get_key); \
return value; \
}
/**
* shell_gconf_get_boolean:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @error: a #GError, which will be set on error
*
* Gets the value of @key, which must be boolean-valued.
*
* Return value: @key's value. If an error occurs, @error will be set
* and the return value is undefined.
**/
SIMPLE_GETTER(shell_gconf_get_boolean, gboolean, gconf_client_get_bool)
/**
* shell_gconf_get_int:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @error: a #GError, which will be set on error
*
* Gets the value of @key, which must be integer-valued.
*
* Return value: @key's value. If an error occurs, @error will be set
* and the return value is undefined.
**/
SIMPLE_GETTER(shell_gconf_get_int, int, gconf_client_get_int)
/**
* shell_gconf_get_float:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @error: a #GError, which will be set on error
*
* Gets the value of @key, which must be float-valued.
*
* Return value: @key's value. If an error occurs, @error will be set
* and the return value is undefined.
**/
SIMPLE_GETTER(shell_gconf_get_float, float, gconf_client_get_float)
/**
* shell_gconf_get_string:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @error: a #GError, which will be set on error
*
* Gets the value of @key, which must be string-valued.
*
* Return value: (transfer full): @key's value, or %NULL if an error
* occurs.
**/
SIMPLE_GETTER(shell_gconf_get_string, char *, gconf_client_get_string)
/**
* shell_gconf_get_boolean_list:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @error: a #GError, which will be set on error
*
* Gets the value of @key, which must be boolean-list-valued.
*
* Return value: (element-type gboolean) (transfer full): @key's
* value, or %NULL if an error occurs.
**/
LIST_GETTER(shell_gconf_get_boolean_list, GCONF_VALUE_BOOL)
/**
* shell_gconf_get_int_list:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @error: a #GError, which will be set on error
*
* Gets the value of @key, which must be integer-list-valued.
*
* Return value: (element-type int) (transfer full): @key's
* value, or %NULL if an error occurs.
**/
LIST_GETTER(shell_gconf_get_int_list, GCONF_VALUE_INT)
/**
* shell_gconf_get_float_list:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @error: a #GError, which will be set on error
*
* Gets the value of @key, which must be float-list-valued.
*
* Return value: (element-type float) (transfer full): @key's
* value, or %NULL if an error occurs.
**/
LIST_GETTER(shell_gconf_get_float_list, GCONF_VALUE_FLOAT)
/**
* shell_gconf_get_string_list:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @error: a #GError, which will be set on error
*
* Gets the value of @key, which must be string-list-valued.
*
* Return value: (element-type utf8) (transfer full): @key's
* value, or %NULL if an error occurs.
**/
LIST_GETTER(shell_gconf_get_string_list, GCONF_VALUE_STRING)
#define SIMPLE_SETTER(NAME, TYPE, GCONF_SETTER) \
void \
NAME (ShellGConf *gconf, const char *key, TYPE value, GError **error) \
{ \
char *set_key = resolve_key (key); \
\
GCONF_SETTER (gconf->client, set_key, value, error); \
g_free (set_key); \
}
#define LIST_SETTER(NAME, ELEMENT_TYPE) \
void \
NAME (ShellGConf *gconf, const char *key, \
GSList *value, GError **error) \
{ \
char *set_key = resolve_key (key); \
\
gconf_client_set_list (gconf->client, set_key, ELEMENT_TYPE, \
value, error); \
g_free (set_key); \
}
/**
* shell_gconf_set_boolean:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @value: value to set @key to
* @error: a #GError, which will be set on error
*
* Sets the value of @key to @value.
**/
SIMPLE_SETTER(shell_gconf_set_boolean, gboolean, gconf_client_set_bool)
/**
* shell_gconf_set_int:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @value: value to set @key to
* @error: a #GError, which will be set on error
*
* Sets the value of @key to @value.
**/
SIMPLE_SETTER(shell_gconf_set_int, int, gconf_client_set_int)
/**
* shell_gconf_set_float:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @value: value to set @key to
* @error: a #GError, which will be set on error
*
* Sets the value of @key to @value.
**/
SIMPLE_SETTER(shell_gconf_set_float, float, gconf_client_set_float)
/**
* shell_gconf_set_string:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @value: value to set @key to
* @error: a #GError, which will be set on error
*
* Sets the value of @key to @value.
**/
SIMPLE_SETTER(shell_gconf_set_string, const char *, gconf_client_set_string)
/**
* shell_gconf_set_boolean_list:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @value: (transfer none): value to set @key to
* @error: a #GError, which will be set on error
*
* Sets the value of @key to @value.
**/
LIST_SETTER(shell_gconf_set_boolean_list, GCONF_VALUE_BOOL)
/**
* shell_gconf_set_int_list:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @value: (transfer none): value to set @key to
* @error: a #GError, which will be set on error
*
* Sets the value of @key to @value.
**/
LIST_SETTER(shell_gconf_set_int_list, GCONF_VALUE_INT)
/**
* shell_gconf_set_float_list:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @value: (transfer none): value to set @key to
* @error: a #GError, which will be set on error
*
* Sets the value of @key to @value.
**/
LIST_SETTER(shell_gconf_set_float_list, GCONF_VALUE_FLOAT)
/**
* shell_gconf_set_string_list:
* @gconf: a #ShellGConf
* @key: a GConf key (as described in the #ShellGConf docs)
* @value: (transfer none): value to set @key to
* @error: a #GError, which will be set on error
*
* Sets the value of @key to @value.
**/
LIST_SETTER(shell_gconf_set_string_list, GCONF_VALUE_STRING)

95
src/shell-gconf.h Normal file
View File

@ -0,0 +1,95 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef SHELL_GCONF_H
#define SHELL_GCONF_H
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _ShellGConf ShellGConf;
typedef struct _ShellGConfClass ShellGConfClass;
#define SHELL_TYPE_GCONF (shell_gconf_get_type ())
#define SHELL_GCONF(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_GCONF, ShellGConf))
#define SHELL_GCONF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_GCONF, ShellGConfClass))
#define SHELL_IS_GCONF(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_GCONF))
#define SHELL_IS_GCONF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_GCONF))
#define SHELL_GCONF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_GCONF, ShellGConfClass))
struct _ShellGConfClass
{
GObjectClass parent_class;
/* signals */
void (*changed) (ShellGConf *gconf);
};
#define SHELL_GCONF_DIR "/desktop/gnome/shell"
GType shell_gconf_get_type (void) G_GNUC_CONST;
ShellGConf *shell_gconf_get_default (void);
void shell_gconf_watch_directory (ShellGConf *gconf,
const char *directory);
gboolean shell_gconf_get_boolean (ShellGConf *gconf,
const char *key,
GError **error);
int shell_gconf_get_int (ShellGConf *gconf,
const char *key,
GError **error);
float shell_gconf_get_float (ShellGConf *gconf,
const char *key,
GError **error);
char *shell_gconf_get_string (ShellGConf *gconf,
const char *key,
GError **error);
GSList *shell_gconf_get_boolean_list (ShellGConf *gconf,
const char *key,
GError **error);
GSList *shell_gconf_get_int_list (ShellGConf *gconf,
const char *key,
GError **error);
GSList *shell_gconf_get_float_list (ShellGConf *gconf,
const char *key,
GError **error);
GSList *shell_gconf_get_string_list (ShellGConf *gconf,
const char *key,
GError **error);
void shell_gconf_set_boolean (ShellGConf *gconf,
const char *key,
gboolean value,
GError **error);
void shell_gconf_set_int (ShellGConf *gconf,
const char *key,
int value,
GError **error);
void shell_gconf_set_float (ShellGConf *gconf,
const char *key,
float value,
GError **error);
void shell_gconf_set_string (ShellGConf *gconf,
const char *key,
const char *value,
GError **error);
void shell_gconf_set_boolean_list (ShellGConf *gconf,
const char *key,
GSList *value,
GError **error);
void shell_gconf_set_int_list (ShellGConf *gconf,
const char *key,
GSList *value,
GError **error);
void shell_gconf_set_float_list (ShellGConf *gconf,
const char *key,
GSList *value,
GError **error);
void shell_gconf_set_string_list (ShellGConf *gconf,
const char *key,
GSList *value,
GError **error);
#endif

View File

@ -0,0 +1,240 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* SECTION:shell-generic-container
* @short_description: A container class with signals for allocation
*
* #ShellGenericContainer is mainly a workaround for the current
* lack of GObject subclassing + vfunc overrides in gjs. We
* implement the container interface, but proxy the virtual functions
* into signals, which gjs can catch.
*/
/* Example implementation of a horzontal box with PACK_EXPAND for all,
vertically and horizontally centering.
function TestFixedBox() {
this._init();
}
TestFixedBox.prototype = {
_init : function () {
this.actor = new Shell.GenericContainer();
this.spacing = 4;
this.actor.connect('get-preferred-width', Lang.bind(this, function (actor, for_height, alloc) {
let children = this.actor.get_children();
let max_child_min = 0;
let max_child_nat = 0;
for (let i = 0; i < children.length; i++) {
let spacing = i > 0 && i < children.length-1 ? this.spacing : 0;
let [child_min, child_nat] = children[i].get_preferred_width(for_height);
if (child_min > max_child_min)
max_child_min = child_min;
if (child_nat > max_child_nat)
max_child_nat = child_nat;
}
let totalSpacing = this.spacing * Math.abs(children.length - 1);
alloc.min_size = children.length * max_child_min + totalSpacing;
alloc.nat_size = children.length * max_child_nat + totalSpacing;
}));
this.actor.connect('get-preferred-height', Lang.bind(this, function (actor, for_width, alloc) {
let children = this.actor.get_children();
let max_child_min = 0;
let max_child_nat = 0;
for (let i = 0; i < children.length; i++) {
let [child_min, child_nat] = children[i].get_preferred_height(for_width);
if (child_min > max_child_min)
max_child_min = child_min;
if (child_nat > max_child_nat)
max_child_nat = child_nat;
}
alloc.min_size = max_child_min;
alloc.nat_size = max_child_nat;
}));
this.actor.connect('allocate', Lang.bind(this, function (actor, box, flags) {
let children = this.actor.get_children();
let totalSpacing = (this.spacing * Math.abs(children.length - 1));
let child_width = (box.x2 - box.x1 - totalSpacing) / (children.length);
let child_height = box.y2 - box.y1;
let x = box.x1;
for (let i = 0; i < children.length; i++) {
let [child_min, child_nat] = children[i].get_preferred_height(child_width);
let vSpacing = Math.abs(child_height - child_nat) / 2;
let childBox = new Clutter.ActorBox();
childBox.x1 = x;
childBox.y1 = vSpacing;
childBox.x2 = x+child_width;
childBox.y2 = child_height - vSpacing;
children[i].allocate(childBox, flags);
x += this.spacing + child_width;
}
}));
}
}
function runTestFixedBox() {
let testBox = new TestFixedBox();
let c = new Clutter.Color();
c.from_pixel(0xff0000a0);
let r = new Clutter.Rectangle({ width: 50, height: 100, color: c });
testBox.actor.add_actor(r);
r = new Clutter.Rectangle({ width: 90, height: 70, color: c });
testBox.actor.add_actor(r);
r = new Clutter.Rectangle({ width: 90, height: 70, color: c });
testBox.actor.add_actor(r);
r = new Clutter.Rectangle({ width: 30, height: 10, color: c });
testBox.actor.add_actor(r);
c.from_pixel(0x00ff00a0);
let borderBox = new Big.Box({ border: 1, border_color: c });
borderBox.set_position(100, 100);
borderBox.append(testBox.actor, Big.BoxPackFlags.NONE);
Shell.Global.get().stage.add_actor(borderBox);
}
*/
#include "shell-generic-container.h"
#include <clutter/clutter.h>
#include <gtk/gtk.h>
#include <girepository.h>
G_DEFINE_TYPE(ShellGenericContainer, shell_generic_container, CLUTTER_TYPE_GROUP);
struct _ShellGenericContainerPrivate {
gpointer dummy;
};
/* Signals */
enum
{
GET_PREFERRED_WIDTH,
GET_PREFERRED_HEIGHT,
ALLOCATE,
LAST_SIGNAL
};
static guint shell_generic_container_signals [LAST_SIGNAL] = { 0 };
static gpointer
shell_generic_container_allocation_ref (ShellGenericContainerAllocation *alloc)
{
alloc->_refcount++;
return alloc;
}
static void
shell_generic_container_allocation_unref (ShellGenericContainerAllocation *alloc)
{
if (--alloc->_refcount == 0)
{
g_slice_free1 (sizeof (ShellGenericContainerAllocation), alloc);
}
}
static void
shell_generic_container_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
/* chain up to set actor->allocation */
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (self, box, flags);
g_signal_emit (G_OBJECT (self), shell_generic_container_signals[ALLOCATE], 0,
box, flags);
}
static void
shell_generic_container_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ShellGenericContainerAllocation *alloc = g_slice_alloc0 (sizeof (ShellGenericContainerAllocation));
alloc->_refcount = 1;
g_signal_emit (G_OBJECT (actor), shell_generic_container_signals[GET_PREFERRED_WIDTH], 0,
for_height, alloc);
if (min_width_p)
*min_width_p = alloc->min_size;
if (natural_width_p)
*natural_width_p = alloc->natural_size;
shell_generic_container_allocation_unref (alloc);
}
static void
shell_generic_container_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ShellGenericContainerAllocation *alloc = g_slice_alloc0 (sizeof (ShellGenericContainerAllocation));
alloc->_refcount = 1;
g_signal_emit (G_OBJECT (actor), shell_generic_container_signals[GET_PREFERRED_HEIGHT], 0,
for_width, alloc);
if (min_height_p)
*min_height_p = alloc->min_size;
if (natural_height_p)
*natural_height_p = alloc->natural_size;
shell_generic_container_allocation_unref (alloc);
}
static void
shell_generic_container_class_init (ShellGenericContainerClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->get_preferred_width = shell_generic_container_get_preferred_width;
actor_class->get_preferred_height = shell_generic_container_get_preferred_height;
actor_class->allocate = shell_generic_container_allocate;
shell_generic_container_signals[GET_PREFERRED_WIDTH] =
g_signal_new ("get-preferred-width",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
gi_cclosure_marshal_generic,
G_TYPE_NONE, 2, G_TYPE_FLOAT, SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION);
shell_generic_container_signals[GET_PREFERRED_HEIGHT] =
g_signal_new ("get-preferred-height",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
gi_cclosure_marshal_generic,
G_TYPE_NONE, 2, G_TYPE_FLOAT, SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION);
shell_generic_container_signals[ALLOCATE] =
g_signal_new ("allocate",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
gi_cclosure_marshal_generic,
G_TYPE_NONE, 2, CLUTTER_TYPE_ACTOR_BOX, CLUTTER_TYPE_ALLOCATION_FLAGS);
g_type_class_add_private (gobject_class, sizeof (ShellGenericContainerPrivate));
}
static void
shell_generic_container_init (ShellGenericContainer *area)
{
area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, SHELL_TYPE_GENERIC_CONTAINER,
ShellGenericContainerPrivate);
}
GType shell_generic_container_allocation_get_type (void)
{
static GType gtype = G_TYPE_INVALID;
if (gtype == G_TYPE_INVALID)
{
gtype = g_boxed_type_register_static ("ShellGenericContainerAllocation",
(GBoxedCopyFunc)shell_generic_container_allocation_ref,
(GBoxedFreeFunc)shell_generic_container_allocation_unref);
}
return gtype;
}

View File

@ -0,0 +1,44 @@
#ifndef __SHELL_GENERIC_CONTAINER_H__
#define __SHELL_GENERIC_CONTAINER_H__
#include <clutter/clutter.h>
#include <gtk/gtk.h>
#define SHELL_TYPE_GENERIC_CONTAINER (shell_generic_container_get_type ())
#define SHELL_GENERIC_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_GENERIC_CONTAINER, ShellGenericContainer))
#define SHELL_GENERIC_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_GENERIC_CONTAINER, ShellGenericContainerClass))
#define SHELL_IS_GENERIC_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_GENERIC_CONTAINER))
#define SHELL_IS_GENERIC_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_GENERIC_CONTAINER))
#define SHELL_GENERIC_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_GENERIC_CONTAINER, ShellGenericContainerClass))
typedef struct {
float min_size;
float natural_size;
/* <private> */
guint _refcount;
} ShellGenericContainerAllocation;
#define SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION (shell_generic_container_allocation_get_type ())
GType shell_generic_container_allocation_get_type (void);
typedef struct _ShellGenericContainer ShellGenericContainer;
typedef struct _ShellGenericContainerClass ShellGenericContainerClass;
typedef struct _ShellGenericContainerPrivate ShellGenericContainerPrivate;
struct _ShellGenericContainer
{
ClutterGroup parent;
ShellGenericContainerPrivate *priv;
};
struct _ShellGenericContainerClass
{
ClutterGroupClass parent_class;
};
GType shell_generic_container_get_type (void) G_GNUC_CONST;
#endif /* __SHELL_GENERIC_CONTAINER_H__ */

View File

@ -14,7 +14,8 @@
#include <string.h>
#include <unistd.h>
#include <dbus/dbus-glib.h>
#include <libgnomeui/gnome-thumbnail.h>
#include <gio/gio.h>
#include <glib/gi18n-lib.h>
#include <math.h>
#include <X11/extensions/Xfixes.h>
@ -39,7 +40,6 @@ struct _ShellGlobal {
MutterPlugin *plugin;
ShellWM *wm;
gboolean keyboard_grabbed;
const char *imagedir;
const char *configdir;
@ -101,7 +101,7 @@ shell_global_get_property(GObject *object,
g_value_set_object (value, mutter_plugin_get_overlay_group (global->plugin));
break;
case PROP_SCREEN:
g_value_set_object (value, mutter_plugin_get_screen (global->plugin));
g_value_set_object (value, shell_global_get_screen (global));
break;
case PROP_SCREEN_WIDTH:
{
@ -270,49 +270,6 @@ shell_global_class_init (ShellGlobalClass *klass)
G_PARAM_READABLE));
}
/**
* search_path_init:
*
* search_path_init and get_applications_search_path below were copied from glib/gio/gdesktopappinfo.c
* copyright Red Hat, Inc., written by Alex Larsson, licensed under the LGPL
*
* Return value: location of an array with user and system application directories.
*/
static gpointer
search_path_init (gpointer data)
{
char **args = NULL;
const char * const *data_dirs;
const char *user_data_dir;
int i, length, j;
data_dirs = g_get_system_data_dirs ();
length = g_strv_length ((char **)data_dirs);
args = g_new (char *, length + 2);
j = 0;
user_data_dir = g_get_user_data_dir ();
args[j++] = g_build_filename (user_data_dir, "applications", NULL);
for (i = 0; i < length; i++)
args[j++] = g_build_filename (data_dirs[i],
"applications", NULL);
args[j++] = NULL;
return args;
}
/**
* get_applications_search_path:
*
* Return value: location of an array with user and system application directories.
*/
static const char * const *
get_applications_search_path (void)
{
static GOnce once_init = G_ONCE_INIT;
return g_once (&once_init, search_path_init, NULL);
}
/**
* shell_clutter_texture_set_from_pixbuf:
* texture: #ClutterTexture to be modified
@ -338,176 +295,6 @@ shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
0, NULL);
}
static GnomeThumbnailFactory *thumbnail_factory;
/**
* shell_get_thumbnail:
*
* @uri: URI of the file to thumbnail
*
* @mime_type: Mime-Type of the file to thumbnail
*
* Return value: #GdkPixbuf containing a thumbnail for file @uri
* if the thumbnail exists or can be generated, %NULL otherwise
*/
GdkPixbuf *
shell_get_thumbnail(const gchar *uri,
const gchar *mime_type)
{
char *existing_thumbnail;
GdkPixbuf *pixbuf = NULL;
GError *error = NULL;
GFile *file = NULL;
GFileInfo *file_info = NULL;
GTimeVal mtime_g;
time_t mtime = 0;
file = g_file_new_for_uri (uri);
file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
g_object_unref (file);
if (file_info) {
g_file_info_get_modification_time (file_info, &mtime_g);
g_object_unref (file_info);
mtime = (time_t) mtime_g.tv_sec;
}
if (thumbnail_factory == NULL)
thumbnail_factory = gnome_thumbnail_factory_new (GNOME_THUMBNAIL_SIZE_NORMAL);
existing_thumbnail = gnome_thumbnail_factory_lookup (thumbnail_factory, uri, mtime);
if (existing_thumbnail != NULL)
{
pixbuf = gdk_pixbuf_new_from_file(existing_thumbnail, &error);
if (error != NULL)
{
g_warning("Could not generate a pixbuf from file %s: %s", existing_thumbnail, error->message);
g_clear_error (&error);
}
}
else if (gnome_thumbnail_factory_has_valid_failed_thumbnail (thumbnail_factory, uri, mtime))
return NULL;
else if (gnome_thumbnail_factory_can_thumbnail (thumbnail_factory, uri, mime_type, mtime))
{
pixbuf = gnome_thumbnail_factory_generate_thumbnail (thumbnail_factory, uri, mime_type);
if (pixbuf)
{
// we need to save the thumbnail so that we don't need to generate it again in the future
gnome_thumbnail_factory_save_thumbnail (thumbnail_factory, pixbuf, uri, mtime);
}
else
{
g_warning ("Could not generate thumbnail for %s", uri);
gnome_thumbnail_factory_create_failed_thumbnail (thumbnail_factory, uri, mtime);
}
}
return pixbuf;
}
/**
* shell_get_categories_for_desktop_file:
*
* @desktop_file_name: name of the desktop file for which to retrieve categories
*
* Return value: (element-type char*) (transfer full): List of categories
*
*/
GSList *
shell_get_categories_for_desktop_file(const char *desktop_file_name)
{
GKeyFile *key_file;
const char * const *search_dirs;
char **categories = NULL;
GSList *categories_list = NULL;
GError *error = NULL;
gsize len;
int i;
key_file = g_key_file_new ();
search_dirs = get_applications_search_path();
g_key_file_load_from_dirs (key_file, desktop_file_name, (const char **)search_dirs, NULL, 0, &error);
if (error != NULL)
{
g_warning ("Error when loading a key file for %s: %s", desktop_file_name, error->message);
g_clear_error (&error);
}
else
{
categories = g_key_file_get_string_list (key_file,
"Desktop Entry",
"Categories",
&len,
&error);
if (error != NULL)
{
// "Categories" is not a required key in the desktop files, so it's ok if we didn't find it
g_clear_error (&error);
}
}
g_key_file_free (key_file);
if (categories == NULL)
return NULL;
// gjs currently does not support returning arrays (other than a NULL value for an array), so we need
// to convert the array we are returning to GSList, returning which gjs supports.
// See http://bugzilla.gnome.org/show_bug.cgi?id=560567 for more info on gjs array support.
for (i = 0; categories[i]; i++)
{
categories_list = g_slist_prepend (categories_list, g_strdup (categories[i]));
}
g_strfreev (categories);
return categories_list;
}
/**
* shell_get_event_key_symbol:
*
* Return value: Clutter key value for the key press and release events,
* as specified in clutter-keysyms.h
*/
guint16
shell_get_event_key_symbol(ClutterEvent *event)
{
g_return_val_if_fail(event->type == CLUTTER_KEY_PRESS ||
event->type == CLUTTER_KEY_RELEASE, 0);
return event->key.keyval;
}
/**
* shell_get_button_event_click_count:
*
* Return value: click count for button press and release events
*/
guint16
shell_get_button_event_click_count(ClutterEvent *event)
{
g_return_val_if_fail(event->type == CLUTTER_BUTTON_PRESS ||
event->type == CLUTTER_BUTTON_RELEASE, 0);
return event->button.click_count;
}
/**
* shell_get_event_related:
*
* Return value: (transfer none): related actor
*/
ClutterActor *
shell_get_event_related (ClutterEvent *event)
{
g_return_val_if_fail (event->type == CLUTTER_ENTER ||
event->type == CLUTTER_LEAVE, NULL);
return event->crossing.related;
}
/**
* shell_global_get:
*
@ -608,6 +395,17 @@ shell_global_set_stage_input_region (ShellGlobal *global,
shell_global_set_stage_input_mode (global, global->input_mode);
}
/**
* shell_global_get_screen:
*
* Return value: (transfer none): The default #MetaScreen
*/
MetaScreen *
shell_global_get_screen (ShellGlobal *global)
{
return mutter_plugin_get_screen (global->plugin);
}
/**
* shell_global_get_windows:
*
@ -635,66 +433,66 @@ _shell_global_set_plugin (ShellGlobal *global,
}
/**
* shell_global_grab_keyboard:
* shell_global_begin_modal:
* @global: a #ShellGlobal
*
* Grab the keyboard to the stage window. The stage will receive
* all keyboard events until shell_global_ungrab_keyboard() is called.
* This is appropriate to do when the desktop goes into a special
* mode where no normal global key shortcuts or application keyboard
* processing should happen.
* Grabs the keyboard and mouse to the stage window. The stage will
* receive all keyboard and mouse events until shell_global_end_modal()
* is called. This is used to implement "modes" for the shell, such as the
* overview mode or the "looking glass" debug overlay, that block
* application and normal key shortcuts.
*
* Returns value: %TRUE if we succesfully entered the mode. %FALSE if we couldn't
* enter the mode. Failure may occur because an application has the pointer
* or keyboard grabbed, because Mutter is in a mode itself like moving a
* window or alt-Tab window selection, or because shell_global_begin_modal()
* was previouly called.
*/
gboolean
shell_global_grab_keyboard (ShellGlobal *global)
shell_global_begin_modal (ShellGlobal *global,
guint32 timestamp)
{
MetaScreen *screen = mutter_plugin_get_screen (global->plugin);
MetaDisplay *display = meta_screen_get_display (screen);
Display *xdisplay = meta_display_get_xdisplay (display);
ClutterStage *stage = CLUTTER_STAGE (mutter_plugin_get_stage (global->plugin));
Window stagewin = clutter_x11_get_stage_window (stage);
/* FIXME: we need to coordinate with the rest of Metacity or we
* may grab the keyboard away from other portions of Metacity
* and leave Metacity in a confused state. An X client is allowed
* to overgrab itself, though not allowed to grab they keyboard
* away from another applications.
*/
if (global->keyboard_grabbed)
return FALSE;
if (XGrabKeyboard (xdisplay, stagewin,
False, /* owner_events - steal events from the rest of metacity */
GrabModeAsync, GrabModeAsync,
CurrentTime) != Success)
return FALSE; /* probably AlreadyGrabbed, some other app has a keyboard grab */
global->keyboard_grabbed = TRUE;
return TRUE;
return mutter_plugin_begin_modal (global->plugin, stagewin, None, 0, timestamp);
}
/**
* shell_global_ungrab_keyboard:
* shell_global_end_modal:
* @global: a #ShellGlobal
*
* Undoes the effect of shell_global_grab_keyboard
* Undoes the effect of shell_global_begin_modal().
*/
void
shell_global_ungrab_keyboard (ShellGlobal *global)
shell_global_end_modal (ShellGlobal *global,
guint32 timestamp)
{
MetaScreen *screen;
MetaDisplay *display;
Display *xdisplay;
mutter_plugin_end_modal (global->plugin, timestamp);
}
g_return_if_fail (global->keyboard_grabbed);
/**
* shell_global_display_is_grabbed
* @global: a #ShellGlobal
*
* Determines whether Mutter currently has a grab (keyboard or mouse or
* both) on the display. This could be the result of a current window
* management operation like a window move, or could be from
* shell_global_begin_modal().
*
* This function is useful to for ad-hoc checks to avoid over-grabbing
* the Mutter grab a grab from GTK+. Longer-term we might instead want a
* mechanism to make Mutter use GDK grabs instead of raw XGrabPointer().
*
* Return value: %TRUE if Mutter has a grab on the display
*/
gboolean
shell_global_display_is_grabbed (ShellGlobal *global)
{
MetaScreen *screen = mutter_plugin_get_screen (global->plugin);
MetaDisplay *display = meta_screen_get_display (screen);
screen = mutter_plugin_get_screen (global->plugin);
display = meta_screen_get_display (screen);
xdisplay = meta_display_get_xdisplay (display);
XUngrabKeyboard (xdisplay, CurrentTime);
global->keyboard_grabbed = FALSE;
return meta_display_get_grab_op (display) != META_GRAB_OP_NONE;
}
/* Code to close all file descriptors before we exec; copied from gspawn.c in GLib.
@ -858,21 +656,23 @@ shell_global_grab_dbus_service (ShellGlobal *global)
exit (0);
}
g_object_unref (bus);
}
void
shell_global_start_task_panel (ShellGlobal *global)
{
const char* panel_args[] = {"gnomeshell-taskpanel", SHELL_DBUS_SERVICE, NULL};
GError *error = NULL;
if (!g_spawn_async (NULL, (char**)panel_args, NULL, G_SPAWN_SEARCH_PATH, NULL,
NULL, NULL, &error))
/* Also grab org.gnome.Panel to replace any existing panel process,
* unless a special environment variable is passed. The environment
* variable is used by the gnome-shell (no --replace) launcher in
* Xephyr */
if (!g_getenv ("GNOME_SHELL_NO_REPLACE_PANEL"))
{
g_critical ("failed to execute %s: %s", panel_args[0], error->message);
g_clear_error (&error);
if (!dbus_g_proxy_call (bus, "RequestName", &error, G_TYPE_STRING,
"org.gnome.Panel", G_TYPE_UINT,
DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE,
G_TYPE_INVALID, G_TYPE_UINT,
&request_name_result, G_TYPE_INVALID))
{
g_print ("failed to acquire org.gnome.Panel: %s\n", error->message);
exit (1);
}
}
g_object_unref (bus);
}
static void
@ -886,53 +686,6 @@ grab_notify (GtkWidget *widget, gboolean was_grabbed, gpointer user_data)
shell_global_set_stage_input_mode (global, global->input_mode);
}
/**
* shell_global_create_vertical_gradient:
* @top: the color at the top
* @bottom: the color at the bottom
*
* Creates a vertical gradient actor.
*
* Return value: (transfer none): a #ClutterCairoTexture actor with the
* gradient. The texture actor is floating, hence (transfer none).
*/
ClutterCairoTexture *
shell_global_create_vertical_gradient (ClutterColor *top,
ClutterColor *bottom)
{
ClutterCairoTexture *texture;
cairo_t *cr;
cairo_pattern_t *pattern;
/* Draw the gradient on an 8x8 pixel texture. Because the gradient is drawn
* from the uppermost to the lowermost row, after stretching 1/16 of the
* texture height has the top color and 1/16 has the bottom color. The 8
* pixel width is chosen for reasons related to graphics hardware internals.
*/
texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (8, 8));
cr = clutter_cairo_texture_create (texture);
pattern = cairo_pattern_create_linear (0, 0, 0, 8);
cairo_pattern_add_color_stop_rgba (pattern, 0,
top->red / 255.,
top->green / 255.,
top->blue / 255.,
top->alpha / 255.);
cairo_pattern_add_color_stop_rgba (pattern, 1,
bottom->red / 255.,
bottom->green / 255.,
bottom->blue / 255.,
bottom->alpha / 255.);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
cairo_destroy (cr);
return texture;
}
/*
* Updates the global->root_pixmap actor with the root window's pixmap or fails
* with a warning.
@ -1020,6 +773,46 @@ root_pixmap_destroy (GObject *sender, gpointer data)
global->root_pixmap = NULL;
}
/**
* shell_global_format_time_relative_pretty:
* @global:
* @delta: Time in seconds since the current time
* @text: (out): Relative human-consumption-only time string
* @next_update: (out): Time in seconds until we should redisplay the time
*
* Format a time value for human consumption only. The passed time
* value is a delta in terms of seconds from the current time.
* This function needs to be in C because of its use of ngettext() which
* is not accessible from JavaScript.
*/
void
shell_global_format_time_relative_pretty (ShellGlobal *global,
guint delta,
char **text,
guint *next_update)
{
#define MINUTE (60)
#define HOUR (MINUTE*60)
#define DAY (HOUR*24)
#define WEEK (DAY*7)
if (delta < MINUTE) {
*text = g_strdup (_("Less than a minute ago"));
*next_update = MINUTE - delta;
} else if (delta < HOUR) {
*text = g_strdup_printf (ngettext ("%d minute ago", "%d minutes ago", delta / MINUTE), delta / MINUTE);
*next_update = MINUTE - (delta % MINUTE);
} else if (delta < DAY) {
*text = g_strdup_printf (ngettext ("%d hour ago", "%d hours ago", delta / HOUR), delta / HOUR);
*next_update = HOUR - (delta % HOUR);
} else if (delta < WEEK) {
*text = g_strdup_printf (ngettext ("%d day ago", "%d days ago", delta / DAY), delta / DAY);
*next_update = DAY - (delta % DAY);
} else {
*text = g_strdup_printf (ngettext ("%d week ago", "%d weeks ago", delta / WEEK), delta / WEEK);
*next_update = WEEK - (delta % WEEK);
}
}
/**
* shell_global_create_root_pixmap_actor:
* @global: a #ShellGlobal
@ -1076,50 +869,3 @@ shell_global_create_root_pixmap_actor (ShellGlobal *global)
return clutter_clone_new (global->root_pixmap);
}
void
shell_global_clutter_cairo_texture_draw_clock (ClutterCairoTexture *texture,
int hour,
int minute)
{
cairo_t *cr;
guint width, height;
double xc, yc, radius, hour_radius, minute_radius;
double angle;
clutter_cairo_texture_get_surface_size (texture, &width, &height);
xc = (double)width / 2;
yc = (double)height / 2;
radius = (double)(MIN(width, height)) / 2 - 2;
minute_radius = radius - 3;
hour_radius = radius / 2;
clutter_cairo_texture_clear (texture);
cr = clutter_cairo_texture_create (texture);
cairo_set_line_width (cr, 1.0);
/* Outline */
cairo_arc (cr, xc, yc, radius, 0.0, 2.0 * M_PI);
cairo_stroke (cr);
/* Hour hand. (We add a fraction to @hour for the minutes, then
* convert to radians, and then subtract pi/2 because cairo's origin
* is at 3:00, not 12:00.)
*/
angle = ((hour + minute / 60.0) / 12.0) * 2.0 * M_PI - M_PI / 2.0;
cairo_move_to (cr, xc, yc);
cairo_line_to (cr,
xc + hour_radius * cos (angle),
yc + hour_radius * sin (angle));
cairo_stroke (cr);
/* Minute hand */
angle = (minute / 60.0) * 2.0 * M_PI - M_PI / 2.0;
cairo_move_to (cr, xc, yc);
cairo_line_to (cr,
xc + minute_radius * cos (angle),
yc + minute_radius * sin (angle));
cairo_stroke (cr);
cairo_destroy (cr);
}

View File

@ -36,21 +36,13 @@ GType shell_global_get_type (void) G_GNUC_CONST;
gboolean shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
GdkPixbuf *pixbuf);
GdkPixbuf *shell_get_thumbnail(const gchar *uri, const gchar *mime_type);
GSList *shell_get_categories_for_desktop_file(const char *desktop_file_name);
guint16 shell_get_event_key_symbol(ClutterEvent *event);
guint16 shell_get_button_event_click_count(ClutterEvent *event);
ClutterActor *shell_get_event_related(ClutterEvent *event);
ShellGlobal *shell_global_get (void);
void shell_global_grab_dbus_service (ShellGlobal *global);
MetaScreen *shell_global_get_screen (ShellGlobal *global);
void shell_global_start_task_panel (ShellGlobal *global);
void shell_global_grab_dbus_service (ShellGlobal *global);
typedef enum {
SHELL_STAGE_INPUT_MODE_NONREACTIVE,
@ -68,20 +60,19 @@ GList *shell_global_get_windows (ShellGlobal *global);
void _shell_global_set_plugin (ShellGlobal *global,
MutterPlugin *plugin);
gboolean shell_global_grab_keyboard (ShellGlobal *global);
void shell_global_ungrab_keyboard (ShellGlobal *global);
gboolean shell_global_begin_modal (ShellGlobal *global,
guint32 timestamp);
void shell_global_end_modal (ShellGlobal *global,
guint32 timestamp);
gboolean shell_global_display_is_grabbed (ShellGlobal *global);
void shell_global_reexec_self (ShellGlobal *global);
ClutterCairoTexture *shell_global_create_vertical_gradient (ClutterColor *top,
ClutterColor *bottom);
void shell_global_format_time_relative_pretty (ShellGlobal *global, guint delta, char **text, guint *update_time);
ClutterActor *shell_global_create_root_pixmap_actor (ShellGlobal *global);
void shell_global_clutter_cairo_texture_draw_clock (ClutterCairoTexture *texture,
int hour,
int minute);
G_END_DECLS
#endif /* __SHELL_GLOBAL_H__ */

View File

@ -1,2 +1,4 @@
VOID:INT,INT,INT
VOID:OBJECT,INT,INT,INT,INT
VOID:BOXED
VOID:BOXED,OBJECT

335
src/shell-menu.c Normal file
View File

@ -0,0 +1,335 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* SECTION:shell-menu
* @short_description: A box which acts like a popup menu
*
* A #BigBox subclass which adds methods and signals useful for implementing
* popup-menu like actors.
*/
#include "shell-menu.h"
G_DEFINE_TYPE(ShellMenu, shell_menu, BIG_TYPE_BOX);
struct _ShellMenuPrivate {
gboolean popped_up;
gboolean have_grab;
gboolean released_on_source;
ClutterActor *source_actor;
ClutterActor *selected;
};
/* Signals */
enum
{
UNSELECTED,
SELECTED,
ACTIVATE,
CANCELLED,
LAST_SIGNAL
};
static guint shell_menu_signals [LAST_SIGNAL] = { 0 };
static gboolean
container_contains (ClutterContainer *container,
ClutterActor *actor)
{
while (actor != NULL && actor != (ClutterActor*)container)
{
actor = clutter_actor_get_parent (actor);
}
return actor != NULL;
}
static void
shell_menu_popdown_nosignal (ShellMenu *box)
{
box->priv->popped_up = FALSE;
if (box->priv->have_grab)
clutter_ungrab_pointer ();
clutter_actor_hide (CLUTTER_ACTOR (box));
}
static void
on_selected_destroy (ClutterActor *actor,
ShellMenu *box)
{
box->priv->selected = NULL;
}
static void
set_selected (ShellMenu *box,
ClutterActor *actor)
{
if (actor == box->priv->selected)
return;
if (box->priv->selected)
{
g_signal_handlers_disconnect_by_func (box->priv->selected, G_CALLBACK(on_selected_destroy), box);
g_signal_emit (G_OBJECT (box), shell_menu_signals[UNSELECTED], 0, box->priv->selected);
}
box->priv->selected = actor;
if (box->priv->selected)
{
g_signal_connect (box->priv->selected, "destroy", G_CALLBACK(on_selected_destroy), box);
g_signal_emit (G_OBJECT (box), shell_menu_signals[SELECTED], 0, box->priv->selected);
}
}
static gboolean
shell_menu_enter_event (ClutterActor *actor,
ClutterCrossingEvent *event)
{
ShellMenu *box = SHELL_MENU (actor);
if (!container_contains (CLUTTER_CONTAINER (box), event->source))
return TRUE;
if (event->source == (ClutterActor*)box)
return TRUE;
if (g_object_get_data (G_OBJECT (event->source), "shell-is-separator"))
return TRUE;
set_selected (box, event->source);
return TRUE;
}
static gboolean
shell_menu_leave_event (ClutterActor *actor,
ClutterCrossingEvent *event)
{
ShellMenu *box = SHELL_MENU (actor);
set_selected (box, NULL);
return TRUE;
}
static gboolean
shell_menu_button_release_event (ClutterActor *actor,
ClutterButtonEvent *event)
{
ShellMenu *box = SHELL_MENU (actor);
if (event->button != 1)
return FALSE;
if (box->priv->source_actor && !box->priv->released_on_source)
{
if (box->priv->source_actor == event->source ||
(CLUTTER_IS_CONTAINER (box->priv->source_actor) &&
container_contains (CLUTTER_CONTAINER (box->priv->source_actor), event->source)))
{
/* On the next release, we want to pop down the menu regardless */
box->priv->released_on_source = TRUE;
return TRUE;
}
}
shell_menu_popdown_nosignal (box);
if (!container_contains (CLUTTER_CONTAINER (box), event->source))
{
g_signal_emit (G_OBJECT (box), shell_menu_signals[CANCELLED], 0);
return FALSE;
}
if (box->priv->selected == NULL)
{
g_signal_emit (G_OBJECT (box), shell_menu_signals[CANCELLED], 0);
return FALSE;
}
g_signal_emit (G_OBJECT (box), shell_menu_signals[ACTIVATE], 0, box->priv->selected);
return TRUE;
}
void
shell_menu_popup (ShellMenu *box,
guint button,
guint32 activate_time)
{
if (box->priv->popped_up)
return;
box->priv->popped_up = TRUE;
box->priv->have_grab = TRUE;
box->priv->released_on_source = FALSE;
clutter_grab_pointer (CLUTTER_ACTOR (box));
}
/**
* shell_menu_popdown:
* @box:
*
* If the menu is currently active, hide it, emitting the 'cancelled' signal.
*/
void
shell_menu_popdown (ShellMenu *box)
{
if (!box->priv->popped_up)
return;
shell_menu_popdown_nosignal (box);
g_signal_emit (G_OBJECT (box), shell_menu_signals[CANCELLED], 0);
}
static void
on_source_destroyed (ClutterActor *actor,
ShellMenu *box)
{
box->priv->source_actor = NULL;
}
/**
* shell_menu_set_persistent_source:
* @box:
* @source: Actor to use as menu origin
*
* This function changes the menu behavior on button release. Normally
* when the mouse is released anywhere, the menu "pops down"; when this
* function is called, if the mouse is released over the source actor,
* the menu stays.
*
* The given @source actor must be reactive for this function to work.
*/
void
shell_menu_set_persistent_source (ShellMenu *box,
ClutterActor *source)
{
if (box->priv->source_actor)
{
g_signal_handlers_disconnect_by_func (G_OBJECT (box->priv->source_actor),
G_CALLBACK (on_source_destroyed),
box);
}
box->priv->source_actor = source;
if (box->priv->source_actor)
{
g_signal_connect (G_OBJECT (box->priv->source_actor),
"destroy",
G_CALLBACK (on_source_destroyed),
box);
}
}
/**
* shell_menu_append_separator:
* @box:
* @separator: An actor which functions as a menu separator
* @flags: Packing flags
*
* Actors added to the menu with default functions are treated like
* menu items; this function will add an actor that should instead
* be treated like a menu separator. The current practical effect
* is that the separators will not be selectable.
*/
void
shell_menu_append_separator (ShellMenu *box,
ClutterActor *separator,
BigBoxPackFlags flags)
{
g_object_set_data (G_OBJECT (separator), "shell-is-separator", GUINT_TO_POINTER(TRUE));
big_box_append (BIG_BOX (box), separator, flags);
}
static void
shell_menu_dispose (GObject *gobject)
{
ShellMenu *self = SHELL_MENU (gobject);
shell_menu_set_persistent_source (self, NULL);
G_OBJECT_CLASS (shell_menu_parent_class)->dispose (gobject);
}
static void
shell_menu_class_init (ShellMenuClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->dispose = shell_menu_dispose;
actor_class->enter_event = shell_menu_enter_event;
actor_class->leave_event = shell_menu_leave_event;
actor_class->button_release_event = shell_menu_button_release_event;
/**
* ShellMenu::unselected
* @box: The #ShellMenu
* @actor: The previously hovered-over menu item
*
* This signal is emitted when a menu item transitions to
* an unselected state.
*/
shell_menu_signals[UNSELECTED] =
g_signal_new ("unselected",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
/**
* ShellMenu::selected
* @box: The #ShellMenu
* @actor: The hovered-over menu item
*
* This signal is emitted when a menu item is in a selected state.
*/
shell_menu_signals[SELECTED] =
g_signal_new ("selected",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
/**
* ShellMenu::activate
* @box: The #ShellMenu
* @actor: The clicked menu item
*
* This signal is emitted when a menu item is selected.
*/
shell_menu_signals[ACTIVATE] =
g_signal_new ("activate",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
/**
* ShellMenu::cancelled
* @box: The #ShellMenu
*
* This signal is emitted when the menu is closed without an option selected.
*/
shell_menu_signals[CANCELLED] =
g_signal_new ("cancelled",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 0);
g_type_class_add_private (gobject_class, sizeof (ShellMenuPrivate));
}
static void
shell_menu_init (ShellMenu *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SHELL_TYPE_MENU,
ShellMenuPrivate);
}

41
src/shell-menu.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef __SHELL_MENU_H__
#define __SHELL_MENU_H__
#include <clutter/clutter.h>
#include "big/box.h"
#define SHELL_TYPE_MENU (shell_menu_get_type ())
#define SHELL_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_MENU, ShellMenu))
#define SHELL_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_MENU, ShellMenuClass))
#define SHELL_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_MENU))
#define SHELL_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_MENU))
#define SHELL_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_MENU, ShellMenuClass))
typedef struct _ShellMenu ShellMenu;
typedef struct _ShellMenuClass ShellMenuClass;
typedef struct _ShellMenuPrivate ShellMenuPrivate;
struct _ShellMenu
{
BigBox parent;
ShellMenuPrivate *priv;
};
struct _ShellMenuClass
{
BigBoxClass parent_class;
};
GType shell_menu_get_type (void) G_GNUC_CONST;
void shell_menu_popup (ShellMenu *behavior, guint button, guint32 activate_time);
void shell_menu_set_persistent_source (ShellMenu *behavior, ClutterActor *source);
void shell_menu_append_separator (ShellMenu *behavior, ClutterActor *separator, BigBoxPackFlags flags);
void shell_menu_popdown (ShellMenu *behavior);
#endif /* __SHELL_MENU_H__ */

426
src/shell-overflow-list.c Normal file
View File

@ -0,0 +1,426 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include "shell-overflow-list.h"
G_DEFINE_TYPE (ShellOverflowList,
shell_overflow_list,
CLUTTER_TYPE_GROUP);
enum {
PROP_0,
PROP_SPACING,
PROP_ITEM_HEIGHT,
PROP_DISPLAYED_COUNT,
PROP_PAGE,
PROP_N_PAGES
};
struct _ShellOverflowListPrivate {
guint item_height;
guint spacing;
guint page;
guint n_pages;
guint items_per_page;
guint displayed_count;
};
static void
recalc_displayed_count (ShellOverflowList *self)
{
GList *children;
int n_children;
int displayed_count;
int page, n_pages;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
n_children = g_list_length (children);
g_list_free (children);
page = self->priv->page;
n_pages = self->priv->n_pages;
if (page < n_pages-1)
displayed_count = self->priv->items_per_page;
else if (n_pages > 0)
displayed_count = n_children - (self->priv->items_per_page * (n_pages-1));
else
displayed_count = 0;
if (displayed_count != self->priv->displayed_count)
{
self->priv->displayed_count = displayed_count;
g_object_notify (G_OBJECT (self), "displayed-count");
}
}
static void
shell_overflow_list_set_property(GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (object);
ShellOverflowListPrivate *priv = self->priv;
switch (prop_id)
{
case PROP_SPACING:
priv->spacing = g_value_get_float (value);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
break;
case PROP_ITEM_HEIGHT:
priv->item_height = g_value_get_float (value);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
break;
case PROP_PAGE:
priv->page = g_value_get_uint (value);
recalc_displayed_count (self);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
shell_overflow_list_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (object);
ShellOverflowListPrivate *priv = self->priv;
switch (prop_id)
{
case PROP_SPACING:
g_value_set_float (value, priv->spacing);
break;
case PROP_ITEM_HEIGHT:
g_value_set_float (value, priv->spacing);
break;
case PROP_DISPLAYED_COUNT:
g_value_set_uint (value, priv->displayed_count);
break;
case PROP_PAGE:
g_value_set_uint (value, priv->page);
break;
case PROP_N_PAGES:
g_value_set_uint (value, priv->n_pages);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
shell_overflow_list_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
ShellOverflowListPrivate *priv = self->priv;
GList *children, *iter;
int n_pages;
int n_children;
int n_fits;
float width;
float curheight;
float avail_height;
gboolean overflow;
/* chain up to set actor->allocation */
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (actor, box, flags);
width = box->x2 - box->x1;
curheight = 0;
avail_height = box->y2 - box->y1;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
n_children = g_list_length (children);
n_fits = 0;
n_pages = 1;
overflow = FALSE;
for (iter = children; iter; iter = iter->next)
{
ClutterActor *actor = CLUTTER_ACTOR (iter->data);
ClutterActorBox child_box;
if (iter != children)
curheight += priv->spacing;
if ((curheight + priv->item_height) > avail_height)
{
overflow = TRUE;
curheight = 0;
n_pages++;
}
else if (!overflow)
n_fits++;
child_box.x1 = 0;
child_box.x2 = width;
child_box.y1 = curheight;
child_box.y2 = child_box.y1 + priv->item_height;
clutter_actor_allocate (actor, &child_box, flags);
curheight += priv->item_height;
}
priv->items_per_page = n_fits;
if (n_pages != priv->n_pages)
{
priv->n_pages = n_pages;
g_object_notify (G_OBJECT (self), "n-pages");
}
recalc_displayed_count (self);
g_list_free (children);
}
static void
shell_overflow_list_paint (ClutterActor *actor)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
ShellOverflowListPrivate *priv = self->priv;
GList *children, *iter;
int i;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
if (children == NULL)
return;
iter = g_list_nth (children, (priv->page) * priv->items_per_page);
i = 0;
for (;iter && i < priv->items_per_page; iter = iter->next, i++)
{
ClutterActor *actor = CLUTTER_ACTOR (iter->data);
clutter_actor_paint (actor);
}
g_list_free (children);
}
static void
shell_overflow_list_pick (ClutterActor *actor,
const ClutterColor *color)
{
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->pick (actor, color);
shell_overflow_list_paint (actor);
}
static void
shell_overflow_list_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
ShellOverflowListPrivate *priv = self->priv;
GList *children;
if (min_height_p)
*min_height_p = 0;
if (natural_height_p)
{
int n_children;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
n_children = g_list_length (children);
if (n_children == 0)
*natural_height_p = 0;
else
*natural_height_p = (n_children - 1) * (priv->item_height + priv->spacing) + priv->item_height;
g_list_free (children);
}
}
static void
shell_overflow_list_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
gboolean first = TRUE;
float min = 0, natural = 0;
GList *iter;
GList *children;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
for (iter = children; iter; iter = iter->next)
{
ClutterActor *child = iter->data;
float child_min, child_natural;
clutter_actor_get_preferred_width (child,
for_height,
&child_min,
&child_natural);
if (first)
{
first = FALSE;
min = child_min;
natural = child_natural;
}
else
{
if (child_min > min)
min = child_min;
if (child_natural > natural)
natural = child_natural;
}
}
if (min_width_p)
*min_width_p = min;
if (natural_width_p)
*natural_width_p = natural;
g_list_free (children);
}
static void
shell_overflow_list_class_init (ShellOverflowListClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->get_property = shell_overflow_list_get_property;
gobject_class->set_property = shell_overflow_list_set_property;
actor_class->get_preferred_width = shell_overflow_list_get_preferred_width;
actor_class->get_preferred_height = shell_overflow_list_get_preferred_height;
actor_class->allocate = shell_overflow_list_allocate;
actor_class->paint = shell_overflow_list_paint;
actor_class->pick = shell_overflow_list_pick;
g_object_class_install_property (gobject_class,
PROP_SPACING,
g_param_spec_float ("spacing",
"Spacing",
"Space between items",
0.0, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_ITEM_HEIGHT,
g_param_spec_float ("item-height",
"Item height",
"Fixed item height value",
0.0, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_DISPLAYED_COUNT,
g_param_spec_uint ("displayed-count",
"Displayed count",
"Number of items displayed on current page",
0, G_MAXUINT, 0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_PAGE,
g_param_spec_uint ("page",
"Page number",
"Page number",
0, G_MAXUINT, 0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_N_PAGES,
g_param_spec_uint ("n-pages",
"Number of pages",
"Number of pages",
0, G_MAXUINT, 0,
G_PARAM_READABLE));
g_type_class_add_private (gobject_class, sizeof (ShellOverflowListPrivate));
}
static void
shell_overflow_list_init (ShellOverflowList *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
SHELL_TYPE_OVERFLOW_LIST,
ShellOverflowListPrivate);
self->priv->n_pages = 1;
self->priv->page = 0;
}
/**
* shell_overflow_list_get_displayed_actor:
* @self:
* @index: 0-based index for displayed list
*
* Returns the actor at the given index on the current page.
*
* Return value: (transfer none): #ClutterActor at index
*/
ClutterActor *
shell_overflow_list_get_displayed_actor (ShellOverflowList *self,
guint index)
{
GList *children, *iter;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
if (children == NULL)
return NULL;
iter = g_list_nth (children, index + (self->priv->page * self->priv->items_per_page));
if (!iter)
return NULL;
return iter->data;
}
/**
* shell_overflow_list_get_actor_index:
* @self:
* @actor: a child of the list
*
* Returns the index on the current page of the given actor.
*
* Return value: index of @actor in
* the currently visible page
*/
int
shell_overflow_list_get_actor_index (ShellOverflowList *self,
ClutterActor *actor)
{
GList *children, *iter;
int i;
int result;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
if (children == NULL)
return -1;
iter = g_list_nth (children, (self->priv->page) * self->priv->items_per_page);
result = -1;
for (i = 0; iter; iter = iter->next, i++)
if (iter->data == actor)
{
result = i;
break;
}
g_list_free (children);
return result;
}

44
src/shell-overflow-list.h Normal file
View File

@ -0,0 +1,44 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef __SHELL_OVERFLOW_LIST_H__
#define __SHELL_OVERFLOW_LIST_H__
#include <glib-object.h>
#include <glib.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
typedef struct _ShellOverflowList ShellOverflowList;
typedef struct _ShellOverflowListClass ShellOverflowListClass;
typedef struct _ShellOverflowListPrivate ShellOverflowListPrivate;
#define SHELL_TYPE_OVERFLOW_LIST (shell_overflow_list_get_type ())
#define SHELL_OVERFLOW_LIST(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_OVERFLOW_LIST, ShellOverflowList))
#define SHELL_OVERFLOW_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_OVERFLOW_LIST, ShellOverflowListClass))
#define SHELL_IS_OVERFLOW_LIST(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_OVERFLOW_LIST))
#define SHELL_IS_OVERFLOW_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_OVERFLOW_LIST))
#define SHELL_OVERFLOW_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_OVERFLOW_LIST, ShellOverflowListClass))
struct _ShellOverflowList
{
ClutterGroup parent_instance;
ShellOverflowListPrivate *priv;
};
struct _ShellOverflowListClass
{
ClutterGroupClass parent_class;
ShellOverflowListPrivate *priv;
};
GType shell_overflow_list_get_type (void) G_GNUC_CONST;
ClutterActor *shell_overflow_list_get_displayed_actor (ShellOverflowList *list, guint index);
int shell_overflow_list_get_actor_index (ShellOverflowList *list, ClutterActor *actor);
G_END_DECLS
#endif /* __SHELL_OVERFLOW_LIST_H__ */

View File

@ -52,8 +52,6 @@ static void shell_process_init (ShellProcess *self)
static void shell_process_dispose (GObject *object)
{
ShellProcess *self = (ShellProcess*)object;
G_OBJECT_CLASS (shell_process_parent_class)->dispose(object);
}

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