Compare commits

...

228 Commits

Author SHA1 Message Date
ea3b2a5707 Update versions for 2.31.2
Update the GNOME Shell version to 2.31.2, and make corresponding
updates to dependencies:

 clutter => 1.2.8
 mutter => 2.31.2
 gobject-introspection => 0.6.11
 gjs => 0.7
2010-05-25 15:22:42 -04:00
25eaf2a294 Updated Spanish translation 2010-05-25 18:31:50 +02:00
7bf748c579 [StTable] Align children to integral positions
Like the other St widgets, ensure we position children at integrals.

https://bugzilla.gnome.org/show_bug.cgi?id=619623
2010-05-25 11:21:34 -04:00
04f33e8dc7 [StTable] Clamp children to integral positions 2010-05-25 11:00:50 -04:00
01c493565f [panel] Ellipsize long application titles, don't push clock around
First, simply set the ellipsize flag on the application menu labels.
Next, rework how we lay out the panel components so that the center
box is always centered and constrains the left and right, rather
than pushing it around.

Previously, as part of making the shell not obviously explode if
one had a lot of tray icons, we allowed them to push the clock over.
Instead, go back to just failing in this case; we need to exile legacy
tray icons, not be slightly less ugly.

https://bugzilla.gnome.org/show_bug.cgi?id=592640
2010-05-25 10:40:15 -04:00
f1e3104128 Do not fail if json Python module is not available
Fallback to old simplejson module if present, and options that require
the json module (create extension and performance) if absent.

https://bugzilla.gnome.org/show_bug.cgi?id=619580
2010-05-25 16:32:56 +02:00
2ace472100 updating for punjabi 2010-05-25 19:32:44 +05:30
fff04d51b7 [panel] fix alignment of app menu label
we were aligning the top of the shadow with the top of the other labels,
rather than aligning the label itself

https://bugzilla.gnome.org/show_bug.cgi?id=618793
2010-05-25 09:34:01 -04:00
a1bfaac5a2 [appSwitcher] Remove unneeded workaround
SwitcherList.actor is no longer a St.BoxLayout but a
GenericContainer now, so the hack in AppSwitcher._getPreferredHeight is no
longer needed (it is called with the correct width now).

https://bugzilla.gnome.org/show_bug.cgi?id=613194
2010-05-24 16:52:38 +02:00
d80c1af1a3 Updated Norwegian bokmål translation 2010-05-24 16:29:32 +02:00
cbde065a01 [perf] Fix factor of ten in seconds => microseconds conversion
Typo: 10000000 instead of 1000000 for a million. Also, use
G_INT64_CONSTANT instead of LL for a 64-bit constant, to avoid
extraneous 128-bit arithmetic on 64-bit machines.
2010-05-24 00:09:40 -04:00
0b1c7320ab Fix "make distcheck" - add missing reference for scripting.js - properly add js/perf/*
https://bugzilla.gnome.org/show_bug.cgi?id=619276
2010-05-22 18:02:52 +02:00
ce3f003e46 Call shell_global_maybe_gc() when no work is being done
Call shell_global_maybe_gc when idle when no other work is ongoing to free
up memory and improve performance by preventing the GC to kick in at less
convenient times.

See: https://developer.mozilla.org/en/SpiderMonkey/JSAPI_Reference/JS_MaybeGC

https://bugzilla.gnome.org/show_bug.cgi?id=614725
2010-05-21 23:47:41 +02:00
9fca747ef4 shell-global: Add shell_global_maybe_gc
Add a method to call JS_MaybeGC, see
https://developer.mozilla.org/en/SpiderMonkey/JSAPI_Reference/JS_MaybeGC

https://bugzilla.gnome.org/show_bug.cgi?id=614725
2010-05-21 23:47:25 +02:00
9455554453 Updated Slovenian translation 2010-05-21 20:03:38 +02:00
4859eb63c4 [perf] Add --perf-upload option to gnome-shell
Add a command line option to upload the generated performance report
to a web service. The options for the upload (url, system name, secret
key) are read from ~/.config/gnome-shell/perf.ini.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 12:34:22 -04:00
e7220591ba [perf] Include monitor layout in performance reports
Add extra key, 'monitors' to performance reports which is an
array of strings:

 *<width>x<height>+<x>+<y>

Where * marks the primary monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 12:34:10 -04:00
20d579e7d8 Add units to metrics definitions
Switch from having separate METRICS and METRIC_DESCRIPTIONS objects
in a perf module to a single METRICS array. This is done so the
perf module can define the units for each metric.

In addition to improving the output in the web interface, the purpose
of having units is to give some clue about how to pick from multiple
values from different runs. In particular, with the assumption that
"noise" on the system will increase run times, for time values we want
to pick the smallest values, while for "rate" values, we want to pick
the largest value.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 00:18:45 -04:00
52a68eb24a Add an option to dump a complete performance report
Add --perf-output=<filename> option to gnome-shell that combines
the reports written for each run by the C/Javascript code into
a complete report.

If this option is not specified, a brief human-readable summary
is printed to stdout instead.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 00:18:45 -04:00
bc57574094 Dump a complete report from a performance run, as JSON
When SHELL_PERF_OUTPUT is set, instead of just dumping out the metrics, dump
a more complete report with:

 - Event descriptions
 - Metric descriptions and value
 - Event log

Helper functions shell_perf_log_dump_events() and shell_perf_log_dump_log()
are added to ShellPerfLog to support this. The gnome-shell wrapper is adapted
to deal with the changed report format.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 00:18:45 -04:00
e4e92a2b38 Add shell_write_string_to_stream()
Add a helper function to write a string as UTF-8 to a GOutputStream.
The signature of GOutputStream:

 gboolean g_output_stream_write_all (GOutputStream *stream,
                                     const void *buffer,
                                     gsize count,
                                     gsize *bytes_written,
                                     GCancellable *cancellable,
                                     GError **error);

Can't currently be handled by GJS.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 00:18:45 -04:00
023a274e41 Allow running multiple iterations of a performance test
Add gnome-shell options:

  --perf-iters=ITERS"
    Numbers of iterations of performance module to run
  --perf-warmup
    Run a dry run before performance tests

Make a successful run of a performance test return 0 not non-zero,
and handle the difference between that and a 0-exit in normal
usage (meaning replaced) in the wrapper.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 00:18:45 -04:00
5d0536d732 Move shell-running machinery to a function
Move the code that starts gnome-shell and waits for it to exit
to a function in preparation for running it multiple times when
doing iterations of a performance test.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 00:18:45 -04:00
08b8b39a5d Add simple malloc statistics and metrics
Add some basic statistics for allocated memory based on mallinfo(),
and use that to define two metrics:

 usedAfterOverview: bytes used after the overview is shown once
 leakedAfterOverview: additional bytes used when the overview is
   shown a second time.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 00:18:45 -04:00
c972ff3ab4 Add "statistics" functionality to ShellPerfLog
Add a facility for defining and recording numeric statistics
as performance events

 shell_perf_log_define_statistic()
   Define a statistic and the corresponding event type
 shell_perf_log_update_statistic_[ix]() -
   Update the stored statistic value
 shell_perf_log_add_statistics_callback()
   Add a function called before collecting statistics
 shell_perf_collect_statistics()
   Update statistics and record events for them

In addition to the explicit collection, statistics are
recorded at a periodic interval (currently 5s)

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-21 00:18:40 -04:00
98c2247c1b Add a facility for automated performance measurement
We want to be able to summarize the behavior of the shell's
performance in a series of "metrics", like the latency between
clicking on the Activities button and seeing a response.

This patch adds the ability to create a script under perf/
in a special format that automates a series of actions in the
shell, writing events to the performance log, then collects
statistics as the log as replayed and turns them into a set
of metrics.

The script is then executed by running as gnome-shell
--perf=<script>.

The 'core' script which is added here will be the primary
performance measurement script that we use for shell performance
regression testing; right now it has a couple of placeholder
metrics.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-20 23:41:47 -04:00
a97b8c1947 Add events before and after stage paint
Add performance events:

 clutter.stagePageStart
 clutter.stagePageDone

to track frame repaints.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-20 23:41:46 -04:00
1dd2f2c6bc Add ShellPerfLog
ShellPerfLog provides a way for different parts of the code to
record information for subsequent analysis and interactive
exploration. Events exist of a timestamp, an event ID, and
arguments to the event.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-20 23:41:40 -04:00
a9a513c621 Add "leisure function" capability
To support scheduling performance-measurement scripts that want to run
a number of actions in series, add shell_global_run_at_leisure() to run
a callback when all work is finished.

The initial implementation of this is not that accurate: we track
business in Tweener.js via new shell_global_begin_work(),
shell_global_end_work() functions, and we also handle the case
where the main loop is continually busy.

https://bugzilla.gnome.org/show_bug.cgi?id=618189
2010-05-20 23:21:44 -04:00
2ce746e7dd [ShellAppSystem] Don't crash if the menu system is empty
This is a bit pathological, but if your menu tree is empty, we
shouldn't crash.
2010-05-20 17:06:30 -04:00
11cde53108 [main] Explicitly require the Clutter and Gtk versions we want
By default introspection will use "latest", which blows up with
Gtk3.
2010-05-20 17:03:43 -04:00
fe542f8732 Add a hack to block calls to certain introspected functions
This is useful for keeping people from using methods that only fail in
certain circumstances, by making them fail in all circumstances
instead.

https://bugzilla.gnome.org/show_bug.cgi?id=618918
2010-05-20 15:49:16 -04:00
91319d5da2 changed 'y_fill' of '_clockButton' in panel to false
The clock appeared to high compared to the activities button
or the login name. Might be just me though.

https://bugzilla.gnome.org/show_bug.cgi?id=619144
2010-05-20 13:01:45 -04:00
5bd7b0dc31 [panel] fix button corners: they should only be rounded on the top 2010-05-20 12:05:22 -04:00
c8f4adde7f [panel] fix nested-queue_relayout warning in menus
We don't need to reposition the menu every time its button is
allocated; we can just stick it in the right place when we pop it up
(which is guaranteed to not be during a layout cycle).

(This means that now we won't reposition the menu if the button
moves/resizes while the menu is already popped up, but it's not clear
that we'd want it to anyway, since that could easily result in the
user selecting the wrong item, etc.)

Also, we don't need to override the menu's width any more, so remove
that.

https://bugzilla.gnome.org/show_bug.cgi?id=619113
2010-05-19 17:06:35 -04:00
b6a47cdf76 [telepathy] fix a bug in a last-second fix to the notification changes
https://bugzilla.gnome.org/show_bug.cgi?id=619044
2010-05-19 16:54:33 -04:00
8b242dd4bd minor js cleanups
add missing semicolons pointed out by js2-mode, add missing emacs
modelines, fix a few tabs that crept in via cut+paste
2010-05-19 13:26:41 -04:00
9b3e16595b [panel] add keyboard navigation of menus
https://bugzilla.gnome.org/show_bug.cgi?id=619008
2010-05-19 13:16:22 -04:00
2179f5836e [panel] separate "active" state from hover state in PanelBaseMenuItem
When doing keyboard navigation, the active menu item may not be the
one under the mouse.

https://bugzilla.gnome.org/show_bug.cgi?id=619008
2010-05-19 13:15:46 -04:00
320adb316d [panel] split out a PanelBaseMenuItem class
Make the existing PanelMenuItem, PanelSeparatorMenuItem,
PanelImageMenuItem inherit from it.

https://bugzilla.gnome.org/show_bug.cgi?id=619008
2010-05-19 13:15:46 -04:00
db36a90c48 Combination of updates to match design suggestions
* Align the icons inside text
* Add application name to Quit
* Fade in/out the menu
* Drop some padding around the edges
* Add padding around the separators
* Use a gradient for separators

https://bugzilla.gnome.org/show_bug.cgi?id=618460
2010-05-19 12:31:19 -04:00
5cfd72ff8b Updated German translation 2010-05-18 22:08:28 +02:00
1d721c9080 [panel] add some missing semicolons 2010-05-18 13:16:24 -04:00
5de1a15d98 magnifier: use global.get_pointer instead of gdk_window_get_pointer
(qv https://bugzilla.gnome.org/show_bug.cgi?id=597292)

https://bugzilla.gnome.org/show_bug.cgi?id=618915
2010-05-17 14:46:26 -04:00
b02089c435 Updated French translation 2010-05-17 20:24:47 +02:00
ccdc6264da Remove markup from translatable strings 2010-05-17 20:24:33 +02:00
b736f52037 Rework compare to take into account closed windows
The API docs for ShellApp claimed it sorted by the last time the
user interacted with the app, but if one closed a window, then
we would fall back to comparing against a possibly much older
timestamp from another window.  Fix this by just keeping a
user time per app.

Also clean up the comparison function to explicitly check the state
instead of deferring to the window list.

https://bugzilla.gnome.org/show_bug.cgi?id=618378
2010-05-17 13:37:13 -04:00
1af392b5f0 Allow selection of individual windows
Per design discussion, change things back so that when choosing
an individual window, we raise only that window.  However
when we select an application, raise all windows.

A behavioral change required to clearly differentiate these
is that when the window thumbnail list is popped up, it no
longer has the first window selected by default.  Therefore
the user has to explicitly press the down arrow or use the
mouse to enter individual window selection mode.

https://bugzilla.gnome.org/show_bug.cgi?id=617959
2010-05-17 13:17:56 -04:00
84716bccd4 Create ShellGlobal later to avoid connecting to X during build
The ShellGlobal initialization performs several actions like connecting
to the X server, ensuring directories exist, etc., that are problematic
because we were creating the object even when running the binary for
introspection scanning.  During compilation we may not even have X11
available in e.g. autobuilder type environments, and it's just a
bad idea to connect even if we do.

Avoid this by deferring creation of the ShellGlobal object
until the plugin is actually started.

Now that we're initializing things later, remove the connection to
screen changes, and initialize cached ShellGlobal state at the point
when the plugin is set.  The root pixmap actor is now sized initially
on creation too.  Instead of relying on screen-size-changed being
emitted on startup, explicitly invoke _relayout().

https://bugzilla.gnome.org/show_bug.cgi?id=618371
2010-05-17 13:04:38 -04:00
f438ccfc53 TelepathyClient: show notifications for presence changes
Fetch the names of the user's "subscribed" contacts, and use the
SimplePresence interface to watch for available/away/busy/etc messages
and create notifications for them.

Currently we display notifications when switching between "available"
and "offline"/"extended away", but when switching between "available"
and "away"/"busy" we just add the information to the chat window
without popping up a notification, to avoid spamming the user with
"Bob's screensaver activated" messages.

https://bugzilla.gnome.org/show_bug.cgi?id=611613
2010-05-17 09:58:36 -04:00
fdd819e9f6 TelepathyClient: track added/removed accounts
(prep work for presence tracking)

https://bugzilla.gnome.org/show_bug.cgi?id=611613
2010-05-17 09:55:31 -04:00
a3a09e6b2e TelepathyClient: rename AvatarManager to ContactManager
and belated rename info.token to info.tokens

https://bugzilla.gnome.org/show_bug.cgi?id=611613
2010-05-17 09:48:09 -04:00
7160e8a137 TelepathyClient: Simplify the channel filter specifications
https://bugzilla.gnome.org/show_bug.cgi?id=611613
2010-05-17 09:48:09 -04:00
016ad69550 [lookingGlass] Remove Properties tab, replace with popup object inspector
Make inspecting objects more dynamic by turning them into links which
pops up a dialog, rather than the more clunky tab interaction.
2010-05-17 09:30:55 -04:00
42e9b21b24 Updated German translation 2010-05-16 21:05:05 +02:00
b6e3bf198d Updated Spanish translation 2010-05-16 11:00:38 +02:00
5e3eb5e8c3 [po] Add type annotation to GtkBuilder files
Due to missing intltool support, translatable strings in the
clock preferences dialog are not added to the pot file.
2010-05-16 00:55:04 +02:00
ed1dc4649b Updated Arabic translation 2010-05-15 23:40:19 +03:00
5b586fdf3e Updated Slovenian translation 2010-05-14 21:53:53 +02:00
703b21cef0 Don't use double quotes for things that don't need to be translated
This is our convention.

The only exceptions are double quotes for words in comments that give
them a special meaning (though beware that these quotes are not truly
necessary most of the time) and double quotes that need to be a part
of the output string.
2010-05-13 16:00:38 -04:00
c7ec84eb33 Updated Spanish translation 2010-05-13 21:14:48 +02:00
4ce2620b68 Don't add a new workspace when the maximum workspaces limit is reached
It was previously possible to add a workspace above the maximum workspaces
limit by dragging an item to the "add workspace" button or using the middle
mouse button click.

Provide the user with feedback in the info bar when it is not possible to create
a new workspace or remove the current workspace.

https://bugzilla.gnome.org/show_bug.cgi?id=591645
2010-05-13 14:30:52 -04:00
ec6bc8f216 Make the workspace added on the middle mouse button click active
This ensures that we launch the new instance of an application on the newly
added workspace in the grid view, in which we don't make the newly added
workspace active by default.

https://bugzilla.gnome.org/show_bug.cgi?id=591645
2010-05-13 14:30:52 -04:00
47a92e7fc0 Don't treat min-width and min-height as a fixed size
I have no idea why there existed code that if we saw e.g. min-width
without a width, we assigned min-width to ->width, thus effectively
treating it as a maximum.

Just delete that bit.

https://bugzilla.gnome.org/show_bug.cgi?id=618482
2010-05-13 13:15:39 -04:00
e835cd2c2d [panel] PanelImageMenuItem should follow gtk-menu-show-images
Update statusMenu to always show images for the presence items only.

https://bugzilla.gnome.org/show_bug.cgi?id=618438
2010-05-12 17:25:51 -04:00
6098dca0f8 Always hide the info bar after a short timeout
We no longer want to keep the info bar showing for as long as the user is
in the overview. We also want a shorter timeout.
2010-05-12 16:44:49 -04:00
21ff050a40 Add a new way to open an application on a new workspace
Allow using the middle mouse button to open a new instance of an
application on a new workspace. The middle mouse button function
can be achieved by clicking the left and right mouse buttons
together with a two buttons mouse or holding Ctrl while clicking
with a single button mouse.

https://bugzilla.gnome.org/show_bug.cgi?id=591645
2010-05-12 20:30:00 +02:00
508001bfde Updated Slovenian translation 2010-05-12 14:36:55 +02:00
410dfb2da3 Use gdk_screen_get_primary_monitor on gtk-2.20.1+
Starting with gtk-2.20.0 there is a gdk_screen_get_primary_monitor,
which supports querying the primary monitor from xrandr.

But due to a sorting bug and lack of heuristics in the fallback path,
it isn't really useable.

Those bugs are fixed in gtk-2.20.1, so use it when building with
gtk-2.20.1+.

https://bugzilla.gnome.org/show_bug.cgi?id=608647
2010-05-12 09:35:32 +02:00
74ccdbf3a9 St: fix allocation to not use both wfh and hfw
Passing an explicit width in the wfh case or a height in the hfw case
messes up the request caching, and confuses actors that assume they
won't be called with an explicit width/height unless they're being
allocated along the other axis.

https://bugzilla.gnome.org/show_bug.cgi?id=618295
2010-05-11 15:58:54 -04:00
80fc55b8ea Add shell-xfixes-cursor.[ch]
Also missing somehow from the magnification commit.
2010-05-11 15:03:11 -04:00
dc424280a1 Add missing magnifier files from the last commit
Also, this patch differs from the one in Bugzilla
in that we start/stop tracking the mouse depending
on whether the magnifier is active.
2010-05-11 15:00:07 -04:00
7b7c34a399 Adds magnifier functionality to gnome-shell.
Adds the ability to create one or more zoom regions that show magnified or
enhanced views of the desktop.  The magnifier provides options for:
* magnification factor,
* four mouse tracking modes common to screen magnifiers,
* positioning the magnified view in one of four screen location, or full screen,
* crosshairs to accentuate the position of the mouse,
* user preferences persistence via GConf (schemas in
  .../data/gnome-shell.schemas).
* a DBus API to allow other processes to drive the magnifier as a service.

https://bugzilla.gnome.org/show_bug.cgi?id=595507
2010-05-11 14:52:25 -04:00
865976cfe7 Updated Spanish translation 2010-05-11 20:44:28 +02:00
81a497b476 Add boxpointer.js to Makefile.am 2010-05-11 20:36:13 +02:00
dc1a6c746d [statusMenu] Update callback prototype for activate signal
When porting, we now have an 'event' arg.
2010-05-11 14:20:01 -04:00
27bcce0888 [panel] Port user status menu to panel menu
https://bugzilla.gnome.org/show_bug.cgi?id=613804
2010-05-11 14:10:36 -04:00
fdcb73d93e Make panel more menu-like, initial application menu
Change the panel into a menu-like actor, where elements can
add menu items.

Implement the initial application menu.

https://bugzilla.gnome.org/show_bug.cgi?id=613804
2010-05-11 14:10:36 -04:00
47dae0832b New widget: BoxPointer
Implement a rounded box with an arrow pointer.

https://bugzilla.gnome.org/show_bug.cgi?id=613804
2010-05-11 14:10:35 -04:00
78e3126f97 [ShellApp] Add quit method
Closes the app, will be used for the panel app menu.  Note
this is just a very primitive implementation.

https://bugzilla.gnome.org/show_bug.cgi?id=613804
2010-05-11 14:10:35 -04:00
12e45f275b Updated Norwegian bokmål translation 2010-05-11 19:51:08 +02:00
7b32888322 Updated Spanish translation 2010-05-10 23:06:16 +02:00
44c2027b40 linearView: Cancel workspace scrolling when the user stops dragging
Currently there is no way for the user to cancel a workspace drag action,
which means the user has to complete the drag action before and move back
to the other workspace manually afterwards.
So cancel the drag action when the user stops.

https://bugzilla.gnome.org/show_bug.cgi?id=618062
2010-05-10 21:28:26 +02:00
a90c81b2c7 Add missing gtk_widget_get_allocation()
In the change from widget->allocation to gtk_widget_get_allocation(),
one addition of gtk_widget_get_allocation() was missed. Add it.
2010-05-10 14:29:44 -04:00
8a25d49319 [SearchEntry] Add a glow effect when activated
(Ab)use -st-shadow to add a glow effect to the activated search entry,
matching the latest mockups.

https://bugzilla.gnome.org/show_bug.cgi?id=611095
2010-05-10 20:17:28 +02:00
014ac2d388 Support -st-shadow for all background properties
Extend the existing support for -st-shadow to apply to the background,
background-gradient and border properties in addition to background-image.

https://bugzilla.gnome.org/show_bug.cgi?id=613832
2010-05-10 20:17:20 +02:00
1e3bf0ea7e Add StGroup container
Currently if we want a stylable fixed-layout container, we use either
a Clutter.Group inside an St.Bin, or we abuse St.BoxLayout.

https://bugzilla.gnome.org/show_bug.cgi?id=613907
2010-05-10 19:59:28 +02:00
54d11b65a1 Move shared container methods from st-private to a common base class
Add StContainer, which implements the ClutterContainer interface based
on the container methods in st-private and make the existing containers
subclass it.

https://bugzilla.gnome.org/show_bug.cgi?id=613907
2010-05-10 19:00:07 +02:00
6318c8e95b Add compatibility with GTK+ 2.18
To replace all calls to deprecated code, GTK+ 2.20 is required - add
some basic compatibility code, so that is still possible to build the
shell with GTK+ 2.18 when not using -DGSEAL_ENABLE.

https://bugzilla.gnome.org/show_bug.cgi?id=618258
2010-05-10 18:31:51 +02:00
8c5bb8655d Use accessor functions instead of direct access
With the transition to GTK+ 3.0, direct access to struct members
will no longer be possible.
This bumps the required minimum version of GTK+ to 2.20.

https://bugzilla.gnome.org/show_bug.cgi?id=618258
2010-05-10 18:31:51 +02:00
75b52d36f2 Do something reasonable for width-for-height sizing
The StTable code only supports height-for-width. When called in
width-for-height sizing mode, instead of treating the -1 flag
value of 'for_width' as a real width, and requesting all the
children at 1 pixel wide, use the natural width of the table
as the width for determing the height.

Since we can't rewrap in width-for-height mode, we then report
the natural width also as the minimum width of the table.

https://bugzilla.gnome.org/show_bug.cgi?id=618104
2010-05-10 11:41:23 -04:00
5111edb80b Use a St.Bin rather than a St.BoxLayout for calendar popup
Using a horizontal St.BoxLayout for calendar container forces
width-for-height layout on the St.Table child. Since St.Table
is naturally width-for-height, this can trigger bugs and is,
at best, a bit ineffecient. Use a St.Bin instead since we don't
need any BoxLayout features.

https://bugzilla.gnome.org/show_bug.cgi?id=618104
2010-05-09 16:37:08 -04:00
c4406d4ace Make getting the environment from gnome-session more robust
readlink() on /proc/<pid>/exe can have results like:

 /usr/bin/gnome-keyring-daemon.#prelink#.5DFZsF (deleted)
 /usr/bin/gnome-session (deleted)

To find gnome-session in a more robust way, read /proc/<pid>/cmdline
instead.

https://bugzilla.gnome.org/show_bug.cgi?id=616706
2010-05-09 16:35:34 -04:00
3bd2f75866 Updated Slovenian translation 2010-05-09 21:02:33 +02:00
6360d8bba6 Updated Slovenian translation 2010-05-09 20:59:54 +02:00
f104a329b0 Fix distcheck for clock-preferences
- Add new files to POTFILES.in/POTFILES.skip
- Mark clock-preferences.ui as dist_pkgdata_DATA
2010-05-09 09:47:49 -04:00
0e9c47bd56 [overview] Fix positioning of single small windows
A single window that does not need to be scaled down, should be centered
and not placed at the bottom.

To avoid blurryness window positions should be pixel aligned.

https://bugzilla.gnome.org/show_bug.cgi?id=617827
2010-05-09 14:18:42 +02:00
2ca1fe3254 [workspacesView] Animate showing/hiding of controls
Some of the workspace view controls are hidden when the number of
workspaces is one (view toggle button, scroll bar in single view).
Use a fade effect instead of showing/hiding the control abruptly.

https://bugzilla.gnome.org/show_bug.cgi?id=613456
2010-05-09 10:46:32 +02:00
88211ed4bb [linearView] Animate scroll bar size changes
When adding/removing workspaces in linear view, both workspaces and
scrollbar movement are animated, but the size of the scrollbar handle
changes abruptly. It is more consistent to animate the size change
as well.

https://bugzilla.gnome.org/show_bug.cgi?id=613456
2010-05-09 01:48:23 +02:00
266a0fb7d6 Add a simple preference dialog for the clock
Port the 'General' preferences tab of the panel's clock applet to
javascript and add it to the build system.

https://bugzilla.gnome.org/show_bug.cgi?id=600276
2010-05-09 01:07:47 +02:00
e6b91414de [panel] Make clock configurable via gconf
Add keys for customizing the panel clock to the gconf schema and make
the clock use them. The settings are copied from gnome-panel's clock
applet, excluding all location/weather/appointment/... keys. In addition,
'internet' is no longer a supported value for the format key.

https://bugzilla.gnome.org/show_bug.cgi?id=600276
2010-05-09 01:07:40 +02:00
62afd2ffa3 Reorganize stage in terms of a UI Group actor and everything else
In preparation for adding magnification, "uiGroup.patch", organizes the stage
along the following lines:

Stage
  *Magnifier
  UI group
    Window group
    Chrome group
    Overlay group
    Alt tab
    App display
    Chrome
    ...

This allows a magnifier actor to clone and magnify the UI group.  The magnifier
is a sibling of the UI Group in this stage oraganization -- see the next patch,
"Magnifier.patch".
2010-05-06 17:18:10 -04:00
37692513cf [altTab] Update for renamed ShellApp method 2010-05-06 12:15:08 -04:00
35bf6b0d36 [altTab] Raise all windows for an app
https://bugzilla.gnome.org/show_bug.cgi?id=616051
2010-05-06 11:19:44 -04:00
0d1ac8cb5b [ShellApp] Add method to focus an app (all windows), make _activate do this
The design calls for raising all windows for a given app in
certain circumstances; implement this.  The new _focus method
raises all windows for the app if it's running.

We further change the _activate method (which a lot of the shell
UI calls now) to invoke _focus for the running case, which means
that e.g. the application well will now raise all app windows.

https://bugzilla.gnome.org/show_bug.cgi?id=616051
2010-05-06 11:19:44 -04:00
b09b30616d Fix userdata directory creation
When creating the directory to store user data, XDG_DATA_HOME is
not guaranteed to exist. Also, the standard mandates permissions
of 0700 for the directory.

https://bugzilla.gnome.org/show_bug.cgi?id=617555
2010-05-06 13:47:00 +02:00
daf133dca8 [workspaces] Split out workspace indicator into separate class
Also fix Clutter warnings.
https://bugzilla.gnome.org/show_bug.cgi?id=614905
2010-05-06 12:16:05 +04:00
ae7f30483d [linearView] Activate workspace on window drop
When a dropped window is accepted by a workspace in linear view, it
is moved to the new workspace. After that, the view zooms back in on
the original workspace, resulting in the moved window disappearing
from the user's sight.
Change this rather unexpected behavior, so that a successful drop
triggers a switch to the new workspace. This also improves consistency
with drops on the (+) area.

https://bugzilla.gnome.org/show_bug.cgi?id=617785
2010-05-06 00:19:46 +02:00
d6fc2cc36f [StEntry] Use hover support from StWidget
As StEntry handles hover differently depending on whether it is
activated or not, the generic hover support in StWidget is
insufficient. Nevertheless it makes sense to set the hover status
using StWidget methods instead of setting the pseudo class directly.
2010-05-05 21:20:32 +02:00
082a15bbc5 [linearView] Cleanup workspace scrolling and zooming
Centralize the update of actor visibilities (overlays, shadows,
off-screen workspaces). Adjust the way scrolling is handled so
that it works correctly with removed workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=610191
2010-05-05 21:20:29 +02:00
2bd64b6cab telepathyClient: improve Empathy interaction
Activate empathy when clicking on a chat icon by asking the
ChannelDispatcher to open the conversation in the default handler.

Also, remove the Approver and Handler for now, since until
telepathy-logger is stable, this means Empathy won't see (and log)
those conversations. This means that empathy's blinky status icon is
back; we'll have to do something else about that.

https://bugzilla.gnome.org/show_bug.cgi?id=611610
2010-05-05 14:53:35 -04:00
b1486f54c8 [ShellGlobal] Change location for user files to XDG_DATA_HOME
While the extension system already uses an XDG location (XDG_CONFIG_HOME),
other components use the deprecated $HOME/.gnome2 directory.
Replace both with XDG_DATA_HOME - the existing data (app usage stats,
looking glass history and extensions) is not migrated to the new location.

https://bugzilla.gnome.org/show_bug.cgi?id=617555
2010-05-05 20:36:52 +02:00
39a24b9a6d [dash] Make the style for places and recent items similar to apps
Change the style rules so that the style for places and recent
items matches the style for applications in a couple of aspects:

 * Use a gradient on hover
 * Use consistent padding and spacing

https://bugzilla.gnome.org/show_bug.cgi?id=610393
2010-05-05 11:43:39 -04:00
6e2ec7291e [gnome-shell.in] Move running environment inheritance earlier
We also want to use it for --eval, so that works over
ssh logins too.
2010-05-05 09:30:29 -04:00
b0ba40f812 Pick up system settings for font rendering
The appearance capplet has a tab for font settings, which we currently
ignore - pick up the settings for resolution, antialiasing and hint style.

https://bugzilla.gnome.org/show_bug.cgi?id=599713
2010-05-04 01:08:20 +02:00
50c453c54d [StShadow] Add support for spread radius
The (optional) spread radius allows to make the shadow bigger without
enlarging the blur value. Mozilla supports this parameter for the
-moz-box-shadow property.

https://bugzilla.gnome.org/show_bug.cgi?id=613832
2010-05-03 19:38:07 +02:00
b71afe55d8 [GnomeSession] split out the gnome-session presence D-Bus interface
Split this out of js/ui/statusMenu.js

https://bugzilla.gnome.org/show_bug.cgi?id=608667
2010-05-03 12:51:34 -04:00
dd0882aa8b [Chrome] add "visibleInFullscreen" property
Chrome elements with this flag set will be visible even when a
fullscreen window is present.

https://bugzilla.gnome.org/show_bug.cgi?id=608667
2010-05-03 12:51:31 -04:00
31914ab23b [Chrome] redo using ShellGenericContainer
Previously we used a ClutterGroup containing a second ClutterGroup for
the non-visibleInOverview actors. Redo it using a single
ShellGenericContainer, and use set_skip_paint() to hide the
non-overview chrome when the overview is visible.

Also fix up the default values for trackActor().

https://bugzilla.gnome.org/show_bug.cgi?id=608667
2010-05-03 12:51:22 -04:00
1816a6339d [ShellGenericContainer] add _get_skip_paint()
https://bugzilla.gnome.org/show_bug.cgi?id=608667
2010-05-03 12:51:13 -04:00
e9e2786fa3 [Params] always return a new object from Params.parse
Rather than returning a modified copy of the input params/defaults,
always return a new object, copying the appropriate values into it.

https://bugzilla.gnome.org/show_bug.cgi?id=608667
2010-05-03 12:51:09 -04:00
024ab39c6d [MessageTray] don't time out the tray if the user is mousing towards it
If a notification is about to hide, but the user has moved the mouse
towards it, let it stick around for another second (and so on, until
the mouse either reaches the tray and causes it to be pinned, or stops
moving the mouse toward it).

https://bugzilla.gnome.org/show_bug.cgi?id=610071
2010-05-03 12:09:53 -04:00
1210a78193 Updated Norwegian bokmål translation 2010-05-02 19:33:35 +02:00
c55dbd5fbd [css] remove a workaround for an old bug 2010-04-30 12:05:56 -04:00
263261cc86 [MessageTray] handle "urgent" notifications specially
Urgent notifications jump to the front of the tray's notification
queue, and come up pre-expanded.

https://bugzilla.gnome.org/show_bug.cgi?id=611612
2010-04-30 11:54:06 -04:00
077f0c56f1 [MessageTray] fix clutter warnings
Figure out if the banner is too long to fit as soon as the
notification's style is set, rather than waiting until allocation
time, since it's bad to add new table rows during allocation.

https://bugzilla.gnome.org/show_bug.cgi?id=611612
2010-04-30 11:54:03 -04:00
e83656969e telepathyClient: cache avatar images
Cache avatars to avoid having to re-download them every session.

We use a cache format that is compatible with empathy's, but we don't
actually use empathy's. This could be changed if we wanted.

https://bugzilla.gnome.org/show_bug.cgi?id=614974
2010-04-29 14:04:07 -04:00
7d7ed7ce7a [panel] y_fill the calendar button 2010-04-27 13:07:31 -04:00
929073882f [panel] Remove border bottom
This line just looks poor - it's probably a leftover from when the
panel was a gradient.  We didn't quite see it before because of
a different bug where we were over-allocating the panel to 27
pixels.
2010-04-27 13:04:48 -04:00
0513297029 [panel] Remove vertical padding for panel-button
This fixes the status menu requesting 27 pixels, which causes
the slicer for the icon to overdraw.

https://bugzilla.gnome.org/show_bug.cgi?id=616951
2010-04-27 12:53:01 -04:00
704354be2c [panel] Remove hardcoded uses of PANEL_HEIGHT
It's cleaner to just y_fill.

https://bugzilla.gnome.org/show_bug.cgi?id=616951
2010-04-27 12:52:57 -04:00
3715109ebe [panel] Fix allocation positioning for boxes
This change doesn't actually affect anything visibly, but
using the absolute coordinates of our allocation box in allocate()
is wrong; we should be positioning our children at 0,0 and using
width/height as a reference.

https://bugzilla.gnome.org/show_bug.cgi?id=616951
2010-04-27 10:37:17 -04:00
9d21b2cb25 Updated Slovenian translation 2010-04-25 10:31:55 +02:00
7f56d06546 known_vendor_prefixes should be NULL terminated
https://bugzilla.gnome.org/show_bug.cgi?id=616574
2010-04-23 18:47:23 +04:00
cf0664fcc6 [lookingGlass] Replace "Hierarchy" with the far more useful "Windows"
I debug the window list a lot more often than I debug actors.
2010-04-20 14:57:31 -04:00
26c8227df5 [ShellWindowTracker] Add a signal to notify when tracked windows change 2010-04-20 14:47:45 -04:00
df43352441 Fix Clutter warnings
https://bugzilla.gnome.org/show_bug.cgi?id=614905
2010-04-19 01:16:49 +04:00
7d705d4de3 Updated Brazilian Portuguese translation 2010-04-17 14:03:16 -03:00
4a0fbf03a8 [workspaces] Only allow mouse clicks to swich for empty workspaces
Allowing it in the case of 1 window is weird - it makes it feel
like a bug when you go from 1 to 2.
2010-04-16 17:24:54 -04:00
54168fcd31 Update visibility of controls on view change.
https://bugzilla.gnome.org/show_bug.cgi?id=610191
2010-04-16 17:40:04 +04:00
5012d64580 telepathyClient: fix summaryNotification to grow properly on updates
When adding more lines to the notification, we need to move it up as
well, or else the new lines will end up underneath the summary or
offscreen.

https://bugzilla.gnome.org/show_bug.cgi?id=615004
2010-04-15 10:12:21 -04:00
10ac42d6ad messageTray: don't show the same notification in both locations
If a notification is already being viewed from the summary area, and
it re-emits 'notify', don't show it a second time in the notification
area.

https://bugzilla.gnome.org/show_bug.cgi?id=614975
2010-04-15 10:04:33 -04:00
a277dfa9ce telepathyClient: only show single-user chats, not chat rooms
eg, for IRC, show private messages, but not channel messages

https://bugzilla.gnome.org/show_bug.cgi?id=614972
2010-04-15 10:03:59 -04:00
3d6c12121f src/Makefile.am: add stamp-shell-enum-types.h to CLEANFILES 2010-04-14 10:49:34 -04:00
98a093a279 Remove icon and menu from titlebar
To avoid visual duplication with the application menu, eliminate
the window menu button. (The window menu can still be accessed by
right-clicking on the title bar, or Alt-right-clicking anywhere on the
window.)

This is implemented using the new Mutter facility for GConf key
redirection; we add separate key for 'button_layout' with a default
that omits the menu button.

https://bugzilla.gnome.org/show_bug.cgi?id=591390
2010-04-13 13:58:42 -04:00
7467e9e3a5 Adapt to new Mutter plugin initialization method
With the changes from bug 615586, Mutter now expects a separate start()
method which is called after construction. Move our initialization from
constructed() to start() so it can access the MetaScreen.

https://bugzilla.gnome.org/show_bug.cgi?id=615592
2010-04-13 13:57:52 -04:00
a7cd294403 notificationDaemon: fix remove-source-on-app-focus code
Previously when no app was focused it would accidentally remove all
sources that had no assocated app (such as telepathy-based sources).

https://bugzilla.gnome.org/show_bug.cgi?id=614978
2010-04-13 11:50:53 -04:00
29d89467b9 Remove a stray bit of user data
We don't need to pass a user_data argument to Meta.later_add() any
more, so remove a stray 'null'.

https://bugzilla.gnome.org/show_bug.cgi?id=615590
2010-04-13 11:10:33 -04:00
dc5dcc6139 Distribute shell-enum-types.h.in and shell-enum-types.c.in
These new files need to be in EXTRA_DIST

Based on a patch by Rico Tzschichholz
https://bugzilla.gnome.org/show_bug.cgi?id=615621
2010-04-13 07:19:15 -04:00
6aaf4b87d5 Major ShellApp API cleanup, startup notification, window focus handling
This patch combines several high level changes which are conceptually
independent but in practice rather intertwined.

* Add a "state" property to ShellApp which reflects whether it's
  stopped, starting, or started.  This will allow us to later clean
  up all the callers that are using ".get_windows().length > 0" as
  a proxy for this property
* Replace shell_app_launch with shell_app_activate and shell_app_open_new_window
  A lot of code was calling .launch, but it's signficantly clearer
  if we call this ".open_new_window()", and later if we gain the ability
  to call into an application's menu, we can implement this correctly rather
  than trying to update all .launch callers.
* Because ShellApp now has a "starting" state, rebase panel.js on top of
  this so that when we get a startup-notification sequence for an app
  and transition it to starting, it becomes the focus app, and panel.js
  cleanly just tracks the focus app, rather than bouncing between SN
  sequences.  This removes display of non-app startup sequences, which
  I consider an acceptable action in light of the committed changes
  to startup-notification and GTK+.

https://bugzilla.gnome.org/show_bug.cgi?id=614755
2010-04-12 16:32:21 -04:00
4392516713 Create GTypes for Shell namespace
https://bugzilla.gnome.org/show_bug.cgi?id=614755
2010-04-12 16:01:54 -04:00
a9aa89e858 [lightbox] Fix Clutter warning by doing reallocation in a Meta.later_add
Based on an original fix by Maxim Ermilov <zaspire@rambler.ru>

https://bugzilla.gnome.org/show_bug.cgi?id=614905
2010-04-09 16:46:35 -04:00
58c0abe600 Updated Galician translations 2010-04-09 19:41:22 +02:00
d42263c1bc Change shell_global_get_modifier_keys to shell_global_get_pointer.
We can't use gdk_display_get_pointer/gdk_window_get_pointer from gjs
when XKB is active. We already had a wrapper that did the
get-modifier-state part of that, but some places also need the
get-pointer-location part of it. So update our wrapper to return both,
and update js code to use it.

https://bugzilla.gnome.org/show_bug.cgi?id=613428
2010-04-08 14:51:45 -04:00
1d2f0e0e15 workspace.js: remove some dead code
The original window dnd code needed to track whether or not the
pointer was in the clone. Some later rewrite made this unnecessary,
but we were still keeping track anyway.
2010-04-08 14:51:45 -04:00
752c25bb7d messageTray: Don't use gravity for notificationBin
When the notificaionBin has an odd width this could result into
loosing pixel aligment (and ugly looking font).

As the notification is already reactive make it non reactive and
remove the use of garvity.

https://bugzilla.gnome.org/show_bug.cgi?id=614702
2010-04-08 20:41:41 +02:00
df09e199b0 Updated Italian translation 2010-04-06 22:52:44 +02:00
ab75c8cacc [chrome] Fix fullscreen check for broken apps
Document fullscreen checks and add a third case to catch apps like
flash who position there windows sightly offscreen to hide there decorations.

https://bugzilla.gnome.org/show_bug.cgi?id=614509
2010-04-06 21:14:54 +02:00
e94d54bffb Add support for chatting directly from IM notifications
Also reorganizes the notification layout to use an StScrollView; very
tall notifications are now scrolled instead of just taking up more and
more of the screen.

https://bugzilla.gnome.org/show_bug.cgi?id=608999
2010-04-06 09:20:50 -04:00
5bce103a40 Use Telepathy for IM notifications
And suppress libnotify-based notifications from Empathy

https://bugzilla.gnome.org/show_bug.cgi?id=608999
2010-04-06 09:16:00 -04:00
5ab852bfa3 Revert "Special-handle Empathy to have multiple sources and to queue notifications"
This reverts commit bb0a977edc.

https://bugzilla.gnome.org/show_bug.cgi?id=608999
2010-04-06 09:16:00 -04:00
439203349d Remove Big, which is no longer used
https://bugzilla.gnome.org/show_bug.cgi?id=614516
2010-04-06 09:13:51 -04:00
2320c393c9 Replace all remaining BigBoxes with StBoxLayouts or StBins
Also, remove a lot of cruft from genericDisplay.js leftover from
previous St-ifications, and remove the pre-gtk-2.16 hacks from the
status tray in panel.js (which are much less needed with the
nearly-all-black panel anyway).

https://bugzilla.gnome.org/show_bug.cgi?id=614516
2010-04-06 09:13:51 -04:00
887f0f554b [genericDisplay] Fix variable typo 2010-04-06 09:03:46 -04:00
46c210c314 [ShellMenu] port from BigBox to StBoxLayout
The actual changes to shell-menu.[ch] are pretty minimal; most of the
changes there are just style/spacing/indentation.

Also, removed shell_menu_append_separator() since it wasn't needed;
the separators would already have been behaving as intended just
because they were non-reactive.

https://bugzilla.gnome.org/show_bug.cgi?id=614516
2010-04-06 08:25:34 -04:00
b4c3ab6726 [StDrawingArea] further CSS-ify StDrawingArea users
Make shell_draw_box_pointer() use CSS colors, and set the app well
menu arrow width based on its own CSS rather than its parent's.

https://bugzilla.gnome.org/show_bug.cgi?id=614516
2010-04-06 08:22:10 -04:00
95a6353dee [StWidget] respect CSS sizing in default size request
Most subclasses override get_preferred_width/height, but if they don't
(eg, StDrawingArea), then make sure they still take CSS-specified
sizes into account.

https://bugzilla.gnome.org/show_bug.cgi?id=614516
2010-04-06 08:19:35 -04:00
cfea0649d8 remove some Big references from places that don't need them any more
https://bugzilla.gnome.org/show_bug.cgi?id=614516
2010-04-06 08:17:33 -04:00
045faf3f12 Fix appIcon menu arrows
We were looking up the wrong property for the width, and then only
setting the foreground color if a void function returned TRUE.

https://bugzilla.gnome.org/show_bug.cgi?id=614516
2010-04-06 08:17:32 -04:00
44ede8c942 Squash epic memory leak
StThemeNode holds a reference to its parent, but we never released
that reference.  This could cause us to hold onto whole chains
of theme nodes with rather dire memory usage implications.

Also move the other g_object_unref into _dispose.

https://bugzilla.gnome.org/show_bug.cgi?id=614660
2010-04-05 21:10:19 -04:00
1ddb775d59 [gnome-shell.modules] Add json-glib to jhbuild
We want to have Clutter built with the external json-glib, with
introspection support.  Clutter's build breaks if we compile
it with introspection but the system install doesn't have it,
and anyways the internal copy is buggy and unmaintained.
2010-04-05 14:08:28 -04:00
cbcbd11ba0 [ShellGlobal] Fix double-free in get_primary_monitor 2010-04-05 11:39:37 -04:00
bae07700a1 shell_global_get_primary_monitor: Use variable to store number of monitors
See https://bugzilla.gnome.org/show_bug.cgi?id=608647#c5
(forgot to add it before commiting).
2010-04-04 18:13:28 +02:00
ca13cec01c Rework shell_global_get_primary_monitor
Currently shell_global_get_primary_monitor just returns the first screen,
in the list as primary.

This is not always correct as the first screen reported by mutter isn't always,
the first one listed by RANDR.

Use gdk_screen_* to query the monitor information and add a heuristic to prefer
LVDS displays (similar like in done for gnome-panel) to prefer the laptop's
internal screen over external displays.

https://bugzilla.gnome.org/show_bug.cgi?id=608647
2010-04-04 18:06:56 +02:00
f2af295867 Updated Dutch translation 2010-04-02 22:19:09 +02:00
0dffec661a Remove the non-existing widget.js from POTFILES.in 2010-04-02 22:00:05 +02:00
bab5a006d8 windowManager: Fix up map effect
Update comment and set the opacity rather than scaling in _mapWindowDone,
 also as we don't have to move the anchor point's gravity for this effect.
2010-04-02 20:30:10 +02:00
f89b95c2aa windowManager: Fade windows on map
Fade in new windows instead of scaling them up from 0 to 1.
2010-04-02 19:51:16 +02:00
f262473a3f Fix fullscreen behaviour
The check in _windowsRestacked checks for
windows[i].x >= primary.x
and
windows[i].x <= primary.x + primary.width
(likewise for y).

This is wrong because a fullscreen window on the secondary screen is likely
to have windows[i].x == primary.x + primary.width which means that the checks
for _both_ screens would be valid, but the first one would win due to
the "break;" statement.

But here the window isn't really on the primary but on the secondary one.

Fix that by using < instead of <= for those checks.

https://bugzilla.gnome.org/show_bug.cgi?id=614509
2010-04-01 16:53:21 +02:00
b571ad0760 Added Ukrainian translation 2010-04-01 15:50:35 +03:00
750672061a placesDisplay: Prevent bookmarks from being cut off
Moving to St.Table introduced a regression that resulted in the height
of Places section to only depend on the height of the left column.

This could result into some bookmarks not being displayed at all because
there are not enough items in the left column to allocate the needed height.

Fix this by removing the St.BoxLayout actors and add the items directly to
the table.

https://bugzilla.gnome.org/show_bug.cgi?id=614144
2010-03-31 17:08:51 +02:00
2ca5cfd6f5 StTable: Update row and column count in st_table_remove_actor
Adjust the table size when removing an actor in st_table_remove_actor.

https://bugzilla.gnome.org/show_bug.cgi?id=614144
2010-03-31 16:55:14 +02:00
8dd572d1cc ShellGenericContainer: adjust requested height/width for border/padding
https://bugzilla.gnome.org/show_bug.cgi?id=614293
2010-03-31 10:10:14 -04:00
b8647cc00e Remove sidebar 2010-03-31 10:08:18 -04:00
a9bdffc9e6 runDialog: Accept Enter (keypad) key in addition to Return. 2010-03-31 15:29:11 +02:00
68723f191c notificationDaemon.js: don't call setApp() if app couldn't be determined
Notify() was calling setApp() unconditionally after attempting to
determine an application. However, determining the application can
fail (for example, when notify-send is used) and resulted in an exception
being printed.
2010-03-31 15:21:54 +02:00
5eafb29332 completed Punjabi Translation by A S Alam 2010-03-31 07:46:39 +05:30
c92ce5983d Consume startup-notification APPLICATION_ID
This patch ensures we're showing the correct data when doing
startup-notification.

https://bugzilla.gnome.org/show_bug.cgi?id=612833
2010-03-30 17:36:05 -04:00
fe52a9e1a1 Add shell_app_system_get_app_for_path
Allows looking up an app given an absolute path to its
desktop file; will be used for startup-notification.

https://bugzilla.gnome.org/show_bug.cgi?id=612833
2010-03-30 17:36:04 -04:00
1a25cd98ea Move focus change handling out of a meta_later
Ok, there admittedly wasn't a strong rationale for having it in a
later, and by performing this immediately we reduce race conditions
for our focus_app versus startup_notification handling.

https://bugzilla.gnome.org/show_bug.cgi?id=612833
2010-03-30 17:36:03 -04:00
611ca3c161 MessageTray: tweak how allocation works to fix the reactive area
Rather than having the notificationBin, summaryBin, and
summaryNotificationBin span the whole width of the screen and just
align their children to the right spot, set their anchor_gravity
appropriately, set their anchor point correctly, and let their width
vary with the width of their child.

Fixes the fact that the area to the left and right of an expanded
notification was reactive, because the notificationBin was invisibly
covering it.

https://bugzilla.gnome.org/show_bug.cgi?id=612072
2010-03-29 14:36:36 -04:00
1dd4c7140e StBoxLayout: remove an incorrect drawing optimization
Paint/pick all children, regardless of whether or not they lie within
the content_box. The previous behavior was that a child that was 99%
outside the box would be fully visible, but a child that was 100%
outside the box would be fully hidden. This is somewhat odd, and
doesn't match the behavior of the other St container classes, and at
any rate, the use of clutter_actor_get_allocation_box() for this
optimization was incorrect since it doesn't take into account
transformations (anchor point, rotation, etc) that might cause the
child to be drawn within the content_box anyway.

(For scrolled StBoxLayouts, drawing is still clipped to the
content_box, as before, but will now properly take transformations
into account as well.)

https://bugzilla.gnome.org/show_bug.cgi?id=614047
2010-03-29 14:36:36 -04:00
b9e58947cc Adjust theme of recent-items and places sections
Add a border to items which highlights on hover, just like the style
of (non-running) app-well items. For removable items in the places
section, this has the additional benefit of making clear to which
item the unmount button belongs.

https://bugzilla.gnome.org/show_bug.cgi?id=610385
2010-03-29 17:46:07 +02:00
73ab59f1d6 [placesDisplay] Add spacing between actions and devices
By moving the elements directly into the enclosing table the spacing
between them got lost.

https://bugzilla.gnome.org/show_bug.cgi?id=610385
2010-03-29 17:46:07 +02:00
df8b03398f [docDisplay] Port DashDocDisplayItem to CSS
Replace Big.Box with St.Clickable similar to the code in placesDisplay.
Adjust spacing and padding to match the places section.

https://bugzilla.gnome.org/show_bug.cgi?id=610385
2010-03-29 17:46:06 +02:00
feaaefd8ba [appDisplay,placeDisplay] Remove manual dnd mode
As the special handling for St.Clickable moved into dnd, it is no
longer necessary to use manual mode in these cases.

https://bugzilla.gnome.org/show_bug.cgi?id=610385
2010-03-29 17:46:05 +02:00
04200a4281 [dnd] Special-case St.Clickable
Currently manual dnd mode is used with St.Clickable to avoid messing
up its internal state with a pointer grab. To avoid code duplication,
move this special handling into dnd.

https://bugzilla.gnome.org/show_bug.cgi?id=610385
2010-03-29 17:45:57 +02:00
c6f84cfa59 Update Czech translation 2010-03-29 00:50:15 +02:00
103d0cba20 Updated Greek translation 2010-03-28 10:53:38 +03:00
095e15fc11 [placesDisplay] Replace remaining Big.Boxes with St.Widgets
While most of the code already is CSS stylable, the two-colum setup
is still done using Big.Box with hard coded spacings. Port those
remaining parts to St.Widget, so that all spacings can be adjusted
by the theme.

https://bugzilla.gnome.org/show_bug.cgi?id=610385
2010-03-27 19:45:10 +01:00
ca2a11c57d [workspacesView] Use add_style_class_name() to set style class
Previously Single/Mosaic view just overwrote the style class set
by the parent.
2010-03-26 23:39:43 +01:00
9423d2c9ac [build] Link against -lm
Fedora 13 uses --no-add-needed, so if we use -lm, we have
to explicitly specify it.

More information: http://fedoraproject.org/wiki/Features/ChangeInImplicitDSOLinking
2010-03-26 17:10:18 -04:00
6461db9df6 AppSwitcher: Make sure we always get the correct icon position
Call stage.get_actor_at_pos before calling icon.get_transformed_position.
2010-03-26 18:13:18 +01:00
5ff609ed49 AppSwitcher: Use CSS instead of the hardcoded POPUP_LIST_SPACING constant
The POPUP_LIST_SPACING constant was used for the AltTabPopup.actor's padding,
AltTabPopup.actor's spacing and SwitcherList._list's spacing.

Switch to CSS and remove the constant.

https://bugzilla.gnome.org/show_bug.cgi?id=613195
2010-03-26 17:49:02 +01:00
4aa2473d18 initialize a variable that gcc warns about
https://bugzilla.gnome.org/show_bug.cgi?id=613749
2010-03-26 11:20:10 -04:00
3f5bb8f98d StScrollView: fix scrollbar allocation when one scrollbar isn't shown
https://bugzilla.gnome.org/show_bug.cgi?id=613964
2010-03-26 11:05:54 -04:00
0487630e03 Updated French translation 2010-03-26 11:05:25 +01:00
d173f9e19d shell-global: Fix get_focus_monitor returning the incorrect screen
When the window's top-left corner is the same as the monitor's top-left
corner the check in shell_global_get_focus_monitor fails to detect that.

Use <= rather than < to fix that.

https://bugzilla.gnome.org/show_bug.cgi?id=613944
2010-03-25 22:04:43 +01:00
f53bf17331 appSwitcher: Fix multiscreen positioning issues
We need to take the screens position into account when allocating.

https://bugzilla.gnome.org/show_bug.cgi?id=613944
2010-03-25 21:58:48 +01:00
ac54fed8d4 [MessageTray] pop out the last notification when mousing over the summary
https://bugzilla.gnome.org/show_bug.cgi?id=610726
2010-03-25 09:24:52 -04:00
6deee27d14 [StThemeNode] Fix gradient colors
CAIRO_FORMAT_ARGB32 matches COGL_PIXEL_FORMAT_BGRA_8888_PRE on
little Endian.
2010-03-24 23:39:43 +01:00
d9f43e27a0 [AppDisplay] Popup the menu on left-click/hold
Left-clicking an app icon and holding the button used to pop up the
app menu, but regressed when rewriting appDisplay.
Restore the previous behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=609013
2010-03-24 19:38:59 +01:00
d1a178301f [placeDisplay] Prefer eject over unmount when applicable
Clicking the eject button in the places display always triggers an
unmount action. In some cases like USB drives or DVDs, eject makes
more sense - it is also consistent with nautilus' behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=613405
2010-03-24 19:38:58 +01:00
8b3d4857aa [Overview] Postpone window repositioning while zooming
After closing a window, the remaining previews are repositioned
after a timeout; when it is called while the user zooms a preview,
the window positions get all messed up, so postpone the positioning
in this case until the zoom ends.

https://bugzilla.gnome.org/show_bug.cgi?id=613536
2010-03-24 19:38:57 +01:00
8d3abea6ef [StThemeNode] Fix build after rebase 2010-03-24 14:24:25 -04:00
5060081db5 Move rendering into st-theme-node-drawing.c
The idea behind this move is that we have a lot more control over
rendering if StWidget isn't a big pile of actors, and things are
more efficient.

https://bugzilla.gnome.org/show_bug.cgi?id=607500
2010-03-24 14:14:03 -04:00
a8fa8a498a Fix dragging of App Well and Places icons
The hover rewrite added a freeze/thaw_notify to
st_clickable_leave_event() (to match the one already in
st_clickable_enter_event()), which broke code in two places that
assumed "pressed" would still be TRUE when "hover" changed to FALSE.
Fix that by exposing the "held" property as well.
2010-03-24 13:48:29 -04:00
5635797cb9 runDialog: use Shell.get_event_state(e), not e.get_state() 2010-03-24 13:16:12 -04:00
468f30e4ab Fix build on x86_64
A pointer does not equal to an int on x86_64
(which results into pointer - pointer not being an int either),
fix that by casting the resulting value  to an int.

Breakage was introduced by commit 909b5ec43c
2010-03-24 17:37:56 +01:00
68b943d8ea [MessageTray] remove bottom rounded corners
https://bugzilla.gnome.org/show_bug.cgi?id=610726
2010-03-24 10:13:48 -04:00
994b4c0007 [MessageTray] Use #StWidget:track-hover
St.Widget's new "hover" property takes reactive children into account
when deciding whether or not the pointer has actually left the actor,
so it works better than the code that used to be here.

https://bugzilla.gnome.org/show_bug.cgi?id=610726
2010-03-24 10:13:36 -04:00
f9e4385e02 [StWidget] add (optional) hover tracking
If track-hover is set, update the hover property automatically, and
the "hover" pseudo class to match, as StClickable used to do. (Remove
the corresponding code in StClickable). Tweak the tooltip handling to
use track-hover, which also makes it slightly more reliable in the
presence of reactive children, etc.
2010-03-24 10:03:50 -04:00
909b5ec43c [StWidget] add list-like methods for style_class and pseudo_class
Since style_class and pseudo_class are space-separated lists of names,
add new methods to add and remove individual names rather than just
re-setting the entire name.

Update existing code to use the new pseudo-class methods where
appropriate. In some cases, this may result in actors having multiple
pseudoclasses where previously they only had one at a time, but there
don't seem to be any visible differences.

(There are some places that could usefully use the new style_class
methods as well, but this patch doesn't change them.)

Also, update test-theme.c to test the new methods.

https://bugzilla.gnome.org/show_bug.cgi?id=604943
2010-03-24 09:40:37 -04:00
7c37e94eda st-widget.h: fix spacing
https://bugzilla.gnome.org/show_bug.cgi?id=604943
2010-03-24 09:40:37 -04:00
874dd14ddc Updated Hungarian translation 2010-03-24 14:26:31 +01:00
d39d7b45e0 Updated Serbian translations 2010-03-24 01:45:46 +01:00
23e11175f8 St: minor gtk-doc fixage (%NULL, %TRUE, %FALSE, not #) 2010-03-23 19:56:10 -04:00
aefa8af60e [runDialog] Don't add duplicates to the history
When the user runs the same command as the last one saved there
is no need to save it again, otherwise we the history might end
up having lots of dupes which makes searching for an old command
harder.

https://bugzilla.gnome.org/show_bug.cgi?id=613731
2010-03-23 20:22:46 +01:00
151 changed files with 15871 additions and 11946 deletions

3
.gitignore vendored
View File

@ -18,6 +18,8 @@ config
configure
data/gnome-shell.desktop
data/gnome-shell.desktop.in
data/gnome-shell-clock-preferences.desktop
data/gnome-shell-clock-preferences.desktop.in
intltool-extract.in
intltool-merge.in
intltool-update.in
@ -38,6 +40,7 @@ src/Makefile
src/Makefile.in
src/gnomeshell-taskpanel
src/gnome-shell
src/gnome-shell-clock-preferences
src/test-recorder
src/test-recorder.ogg
src/test-theme

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[2.29.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[2.31.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c])
@ -55,13 +55,15 @@ fi
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.2.0
GOBJECT_INTROSPECTION_MIN_VERSION=0.6.9
GJS_MIN_VERSION=0.6
MUTTER_MIN_VERSION=2.29.1
CLUTTER_MIN_VERSION=1.2.8
GOBJECT_INTROSPECTION_MIN_VERSION=0.6.11
GJS_MIN_VERSION=0.7
MUTTER_MIN_VERSION=2.31.2
GTK_MIN_VERSION=2.18.0
# Collect more than 20 libraries for a prize!
PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-unix-2.0 gtk+-2.0 dbus-glib-1
PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-unix-2.0 dbus-glib-1
gtk+-2.0 >= $GTK_MIN_VERSION
mutter-plugins >= $MUTTER_MIN_VERSION
gjs-gi-1.0 >= $GJS_MIN_VERSION
libgnome-menu $recorder_modules gconf-2.0
@ -70,9 +72,19 @@ PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-unix-2.0 gtk+-2.0 dbus-glib-1
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
libstartup-notification-1.0
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION)
# This is for the newly added application id bits, we can replace this with
# a version check later
saved_CFLAGS=$CFLAGS
saved_LIBS=$LIBS
CFLAGS=$MUTTER_PLUGIN_CFLAGS
LIBS=$MUTTER_PLUGIN_LIBS
AC_CHECK_FUNCS(sn_startup_sequence_get_application_id)
CFLAGS=$saved_CFLAGS
LIBS=$saved_LIBS
PKG_CHECK_MODULES(TIDY, clutter-1.0)
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-2.0 libcroco-0.6 gnome-desktop-2.0 >= 2.26)
PKG_CHECK_MODULES(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)
@ -86,8 +98,10 @@ AC_SUBST(MUTTER_PLUGIN_DIR)
GJS_JS_DIR=`$PKG_CONFIG --variable=jsdir gjs-1.0`
GJS_JS_NATIVE_DIR=`$PKG_CONFIG --variable=jsnativedir gjs-1.0`
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
AC_SUBST(GJS_JS_DIR)
AC_SUBST(GJS_JS_NATIVE_DIR)
AC_SUBST(GJS_CONSOLE)
AC_CHECK_FUNCS(fdwalk)
AC_CHECK_HEADERS([sys/resource.h])
@ -141,6 +155,8 @@ AC_CONFIG_FILES([
js/Makefile
js/misc/Makefile
js/ui/Makefile
js/perf/Makefile
js/prefs/Makefile
src/Makefile
tests/Makefile
po/Makefile.in

View File

@ -1,17 +1,19 @@
desktopdir=$(datadir)/applications
desktop_DATA = gnome-shell.desktop
desktop_DATA = gnome-shell.desktop gnome-shell-clock-preferences.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
%.desktop.in:%.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
%.desktop:%.desktop.in
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
dist_pkgdata_DATA = clock-preferences.ui
imagesdir = $(pkgdatadir)/images
dist_images_DATA = \
close-black.svg \
@ -50,11 +52,13 @@ schema_DATA = gnome-shell.schemas
install-data-local:
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(schema_DATA)
EXTRA_DIST = \
gnome-shell.desktop.in.in \
EXTRA_DIST = \
gnome-shell.desktop.in.in \
gnome-shell-clock-preferences.desktop.in.in \
$(schema_DATA)
CLEANFILES = \
gnome-shell.desktop.in \
CLEANFILES = \
gnome-shell.desktop.in \
gnome-shell-clock-preferences.desktop.in \
$(desktop_DATA)

188
data/clock-preferences.ui Normal file
View File

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

View File

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

View File

@ -58,59 +58,86 @@
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/sidebar/visible</key>
<applyto>/desktop/gnome/shell/sidebar/visible</applyto>
<key>/schemas/desktop/gnome/shell/clock/format</key>
<applyto>/desktop/gnome/shell/clock/format</applyto>
<owner>gnome-shell</owner>
<type>string</type>
<default>
<!-- Translators:
This controls whether the GNOME panel clock should display time
in 24 hour mode or 12 hour mode by default. The only valid values
for this are "24-hour" and "12-hour".
If your locale uses 24 hour time notation, translate this to
"24-hour".
If your locale uses 12 hour time notation with am/pm, translate
this to "12-hour".
Do NOT translate this into anything else than "24-hour" or
"12-hour". For example, if you translate this to "24 sata" or
anything else that isn't "24-hour" or "12-hour", things will
not work.
-->
24-hour
</default>
<locale name="C">
<short>Hour format</short>
<long>
This key specifies the hour format used by the panel clock.
Possible values are "12-hour", "24-hour", "unix" and "custom".
If set to "unix", the clock will display time in seconds since Epoch,
i.e. 1970-01-01.
If set to "custom", the clock will display time according to the format
specified in the custom_format key.
Note that if set to either "unix" or "custom", the show_date and
show_seconds keys are ignored.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/clock/custom_format</key>
<applyto>/desktop/gnome/shell/clock/custom_format</applyto>
<owner>gnome-shell</owner>
<type>string</type>
<default></default>
<locale name="C">
<short>Custom format of the clock</short>
<long>
This key specifies the format used by the panel clock when the
format key is set to "custom". You can use conversion specifiers
understood by strftime() to obtain a specific format. See the
strftime() manual for more information.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/clock/show_seconds</key>
<applyto>/desktop/gnome/shell/clock/show_seconds</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Whether or not to display the sidebar</short>
<short>Show time with seconds</short>
<long>
Determines whether or not the sidebar is visible.
</long>
If true and format is either "12-hour" or "24-hour",
display seconds in time.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/sidebar/expanded</key>
<applyto>/desktop/gnome/shell/sidebar/expanded</applyto>
<key>/schemas/desktop/gnome/shell/clock/show_date</key>
<applyto>/desktop/gnome/shell/clock/show_date</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<default>false</default>
<locale name="C">
<short>Whether the sidebar should be in the expanded (wide) mode</short>
<short>Show date in clock</short>
<long>
Controls the expanded/collapsed state of the sidebar.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/sidebar/autohide</key>
<applyto>/desktop/gnome/shell/sidebar/autohide</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Whether the sidebar should automatically hide itself in compact mode</short>
<long>
Controls the autohide 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>
If true and format is either "12-hour" or "24-hour",
display date in the clock, in addition to time.
</long>
</locale>
</schema>
@ -191,6 +218,226 @@
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/shell/windows/button_layout</key>
<applyto>/desktop/gnome/shell/windows/button_layout</applyto>
<owner>gnome-shell</owner>
<type>string</type>
<default>:minimize,maximize,close</default>
<locale name="C">
<short>Arrangement of buttons on the titlebar</short>
<long>
Arrangement of buttons on the titlebar. The
value should be a string, such as
"menu:minimize,maximize,spacer,close"; the colon separates the
left corner of the window from the right corner, and
the button names are comma-separated. Duplicate buttons
are not allowed. Unknown button names are silently ignored
so that buttons can be added in future gnome-shell versions
without breaking older versions.
A special spacer tag can be used to insert some space between
two adjacent buttons.
This key overrides /apps/metacity/general/button_layout when
running GNOME Shell.
</long>
</locale>
</schema>
<!-- Magnifier -->
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/show_magnifier</key>
<applyto>/desktop/gnome/accessibility/magnifier/show_magnifier</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Show or hide the magnifier</short>
<long>
Show or hide the magnifier and all of its zoom regions.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/mouse_tracking</key>
<applyto>/desktop/gnome/accessibility/magnifier/mouse_tracking</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>1</default>
<locale name="C">
<short>Mouse Tracking Mode</short>
<long>
Determines the position of the magnified mouse image within
the magnified view and how it reacts to system mouse movement.
The values are 0 - none: no mouse tracking; 1 - centered: the
mouse image is displayed at the center of the zoom region
(which also represents the point under the system mouse) and the
magnified contents are scrolled as the system mouse moves; 2 -
proportional: the position of the magnified mouse in the zoom
region is proportionally the same as the position of the system
mouse on screen; or 3 - push: when the magnified mouse
intersects a boundary of the zoom region, the contents are
scrolled into view.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/screen_position</key>
<applyto>/desktop/gnome/accessibility/magnifier/screen_position</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>3</default>
<locale name="C">
<short>Screen position</short>
<long>
The magnified view either fills the entire screen (1), or
occupies the top-half (2), bottom-half (3), left-half (4), or
right-half (5) of the screen.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/mag_factor</key>
<applyto>/desktop/gnome/accessibility/magnifier/mag_factor</applyto>
<owner>gnome-shell</owner>
<type>float</type>
<default>2.0</default>
<locale name="C">
<short>Magnification factor</short>
<long>
The power of the magnification. A value of 1.0 means no
magnification. A value of 2.0 doubles the size.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/lens_mode</key>
<applyto>/desktop/gnome/accessibility/magnifier/lens_mode</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Enable lens mode</short>
<long>
Whether the magnified view should be centered over the location
of the system mouse and move with it.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/scroll_at_edges</key>
<applyto>/desktop/gnome/accessibility/magnifier/scroll_at_edges</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Scroll magnified contents beyond the edges of the desktop</short>
<long>
For centered mouse tracking, when the system pointer is at
or near the edge of the screen, the magnified contents continue
to scroll such that the screen edge moves into the magnified
view.
</long>
</locale>
</schema>
<!-- Magnifier: Crosshairs -->
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/show_cross_hairs</key>
<applyto>/desktop/gnome/accessibility/magnifier/show_cross_hairs</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Show or hide crosshairs</short>
<long>
Enables/disables display of crosshairs centered on the magnified mouse
sprite.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_thickness</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_thickness</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>8</default>
<locale name="C">
<short>Thickness of the crosshairs</short>
<long>
Width of the vertical and horizontal lines that make up the
crosshairs.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_color</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_color</applyto>
<owner>gnome-shell</owner>
<type>string</type>
<default>#ff0000</default>
<locale name="C">
<short>Color of the crosshairs</short>
<long>
The color of the the vertical and horizontal lines that make up
the crosshairs.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_opacity</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_opacity</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>169</default>
<locale name="C">
<short>Opacity of the crosshairs</short>
<long>
Determines the transparency of the crosshairs, from fully opaque
to fully transparent.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_length</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_length</applyto>
<owner>gnome-shell</owner>
<type>int</type>
<default>4096</default>
<locale name="C">
<short>Length of the crosshairs</short>
<long>
Determines the length of the vertical and horizontal lines that
make up the crosshairs.
</long>
</locale>
</schema>
<schema>
<key>/schemas/desktop/gnome/accessibility/magnifier/cross_hairs_clip</key>
<applyto>/desktop/gnome/accessibility/magnifier/cross_hairs_clip</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Clip the crosshairs at the center</short>
<long>
Determines whether the crosshairs intersect the magnified mouse
sprite, or are clipped such that the ends of the horizontal
and vertical lines surround the mouse image.
</long>
</locale>
</schema>
</schemalist>
</gconfschemafile>

View File

@ -99,7 +99,6 @@ StTooltip {
color: #ffffff;
font-size: 16px;
background-color: black;
border-bottom: 1px solid #1f1f1f;
}
#panelLeft, #panelCenter, #panelRight {
@ -115,11 +114,61 @@ StTooltip {
padding-left: 4px;
}
.panel-button:pressed {
background-color: rgba(50,76,111,0.98);
border-radius: 4px 4px 0px 0px;
}
.panel-menu-boxpointer {
-arrow-border-radius: 9px;
-arrow-background-color: rgba(0,0,0,0.9);
-arrow-border-width: 2px;
-arrow-border-color: #5f5f5f;
-arrow-base: 30px;
-arrow-rise: 15px;
}
.panel-menu {
color: #ffffff;
font-size: 16px;
min-width: 200px;
}
.panel-menu-content {
padding: 10px 0px;
}
.panel-menu-item {
padding: 6px 20px;
}
.panel-menu-item:active {
background-color: #4c4c4c;
}
.panel-image-menu-item {
spacing: 12px;
}
.panel-separator-menu-item {
-gradient-height: 2px;
-gradient-start: rgba(8,8,8,0);
-gradient-end: #333333;
-margin-horizontal: 30px;
height: 16px;
}
#appMenu {
spacing: 4px;
}
.app-menu-icon {
width: 24px;
height: 24px;
}
.panel-button {
padding: 4px 12px 3px;
padding: 0px 12px;
border-radius: 5px;
border-radius-bottomleft: 0px;
border-radius-bottomright: 0px;
@ -141,10 +190,18 @@ StTooltip {
border-radius-topright: 0px;
}
#statusMenu {
#panelStatusMenu {
spacing: 4px;
}
#statusTray {
spacing: 14px;
}
#statusTray:compact {
spacing: 8px;
}
/* Overview */
.overview {
@ -317,6 +374,7 @@ StTooltip {
border: 1px solid #3a3a3a;
background-color: #e8e8e8;
caret-color: #545454;
-st-shadow: 0px 0px 6px 2px rgba(255,255,255,0.9);
}
#searchEntry:hover {
@ -404,6 +462,10 @@ StTooltip {
background-color: #1e1e1e;
}
.dash-results-container {
spacing: 4px;
}
/* GenericDisplay */
.generic-display-container {
@ -489,6 +551,9 @@ StTooltip {
.app-well-app:hover {
border: 1px solid #666666;
background-gradient-direction: vertical;
background-gradient-start: rgba(61,61,61,0.8);
background-gradient-end: rgba(24,24,24,0.2);
}
.app-well-app:active {
@ -502,8 +567,13 @@ StTooltip {
padding: 4px;
background-color: rgba(0,0,0,0.9);
color: #ffffff;
-shell-arrow-width: 12px;
-shell-menu-spacing: 4px;
spacing: 4px;
}
.app-well-menu-arrow {
border-color: #5f5f5f;
color: rgba(0,0,0,0.9);
width: 12px;
}
.app-well-menu-item:hover {
@ -518,20 +588,49 @@ StTooltip {
/* Places */
.places-section {
spacing-columns: 4px;
spacing-rows: 4px;
}
.places-item-box {
spacing: 4px;
}
.places-item {
padding: 2px;
}
.places-actions {
spacing: 2px;
}
#placesDevices {
padding-top: 4px;
.places-item {
border-radius: 4px;
padding: 2px;
border: 1px solid #181818;
padding-left: 4px;
padding-right: 4px;
}
.places-item:hover {
border: 1px solid #666666;
background-gradient-direction: vertical;
background-gradient-start: rgba(61,61,61,0.8);
background-gradient-end: rgba(24,24,24,0.2);
}
/* Recent items */
.recent-docs-item-box {
spacing: 2px;
}
.recent-docs-item {
border-radius: 4px;
padding: 2px;
border: 1px solid #181818;
padding-left: 4px;
padding-right: 4px;
}
.recent-docs-item:hover {
border: 1px solid #666666;
background-gradient-direction: vertical;
background-gradient-start: rgba(61,61,61,0.8);
background-gradient-end: rgba(24,24,24,0.2);
}
/* LookingGlass */
@ -541,7 +640,7 @@ StTooltip {
background-color: rgba(0,0,0,0.85);
spacing: 4px;
padding: 4px;
border: 1px solid rgba(0,0,172,0.85);
border: 2px solid grey;
border-radius: 4px;
color: #88ff66;
@ -561,27 +660,69 @@ StTooltip {
padding: 2px;
}
#LookingGlassDialog .notebook-tab:hover {
color: #00ff00;
}
#LookingGlassDialog .notebook-tab:selected {
border: 1px solid #88ff66;
padding: 1px;
border-radius: 4px;
padding: 5px;
}
#LookingGlassDialog StLabel
#LookingGlassDialog .lg-inspector-title {
font-weight: bold;
padding-bottom: 8px;
}
.lg-dialog StLabel
{
color: #88ff66;
}
#LookingGlassDialog StEntry
.lg-dialog StEntry
{
color: #88ff66;
}
.lg-obj-inspector-title
{
spacing: 4px;
}
.lg-obj-inspector-button
{
border: 1px solid #88ff66;
padding: 4px;
border-radius: 4px;
}
.lg-obj-inspector-button:hover
{
border: 1px solid #00ff00;
}
.lg-dialog .shell-link
{
color: #88ff66;
}
.lg-dialog .shell-link:hover
{
color: #00ff00;
}
#LookingGlassDialog StBoxLayout#EvalBox
{
padding: 4px;
spacing: 4px;
}
#LookingGlassDialog StBoxLayout#ResultsArea
{
spacing: 4px;
}
#lookingGlassExtensions {
padding: 4px;
}
@ -605,6 +746,14 @@ StTooltip {
spacing: 6px;
}
#LookingGlassPropertyInspector {
background: rgba(0, 0, 0, 0.9);
border: 2px solid grey;
border-radius: 4px;
padding: 6px;
color: #88ff66;
}
/* Calendar popup */
#calendarPopup {
@ -662,7 +811,7 @@ StTooltip {
#notification {
font-size: 16px;
border-radius: 5px;
border-radius: 5px 5px 0px 0px;
background: rgba(0,0,0,0.9);
color: white;
padding: 2px 10px 10px 10px;
@ -671,6 +820,23 @@ StTooltip {
max-width: 40em;
}
#summary-notification-bin #notification {
/* message-tray.height + notification.padding-bottom */
padding-bottom: 38px;
}
#notification-scrollview {
max-height: 10em;
}
#notification-scrollview > .top-shadow, #notification-scrollview > .bottom-shadow {
height: 1em;
}
#notification-body {
spacing: 5px;
}
#notification-actions {
spacing: 5px;
}
@ -693,12 +859,52 @@ StTooltip {
background: #808080;
}
.chat-received {
background-gradient-direction: horizontal;
background-gradient-start: #606060;
background-gradient-end: #000000;
min-width: 20em;
}
.chat-sent {
background-gradient-direction: horizontal;
background-gradient-start: #000000;
background-gradient-end: #606060;
}
.chat-response {
border: 1px solid white;
}
/* The spacing and padding on the summary is tricky; we want to keep
* the icons from touching each other or the edges of the screen, but
* we also want them to be "Fitts"-y with respect to the edges, so the
* summary area's bottom and right padding must actually be part of
* the icons. However, we can't put *all* of the padding into the
* icons, because then the summary would be 0x0 when there were no
* icons in it, and so you wouldn't be able to hover over it to
* activate it.
*
* The padding-right on the non-rightmost icons is noticeable and
* slightly annoying. If StBoxLayout implemented the ":last-child"
* pseudo-class we could fix that...
*/
#summary-mode {
spacing: 10px;
padding: 2px 4px;
spacing: 6px;
padding: 2px 0px 0px 4px;
}
.summary-icon {
padding: 0px 4px 2px 0px;
}
/* App Switcher */
#altTabPopup {
padding: 8px;
spacing: 16px;
}
.switcher-list {
background: rgba(0,0,0,0.8);
border: 1px solid rgba(128,128,128,0.40);
@ -709,6 +915,10 @@ StTooltip {
color: white;
}
.switcher-list-item-container {
spacing: 8px;
}
.thumbnail-scroll-gradient-left {
background-gradient-direction: horizontal;
background-gradient-start: rgba(51, 51, 51, 1.0);
@ -762,6 +972,16 @@ StTooltip {
background-image: url("corner-ripple.png");
}
.switcher-arrow {
border-color: rgba(0,0,0,0);
color: #808080;
}
.switcher-arrow:highlighted {
border-color: rgba(0,0,0,0);
color: white;
}
/* Workspace Switcher */
.workspace-switcher-container {
background: rgba(0,0,0,0.8);
@ -835,3 +1055,13 @@ StTooltip {
.lightbox {
background-color: rgba(0, 0, 0, 0.27);
}
/* Magnifier */
.magnifier-zoom-region {
border: 2px solid rgba(128, 0, 0, 255);
}
.magnifier-zoom-region.full-screen {
border-width: 0px;
}

View File

@ -1 +1 @@
SUBDIRS = misc ui
SUBDIRS = misc ui perf prefs

View File

@ -3,4 +3,6 @@ jsmiscdir = $(pkgdatadir)/js/misc
dist_jsmisc_DATA = \
docInfo.js \
format.js \
params.js
gnomeSession.js \
params.js \
telepathy.js

View File

@ -148,6 +148,6 @@ DocManager.prototype = {
}
return multipleMatches.concat(prefixMatches.concat(substringMatches));
}
}
};
Signals.addSignalMethods(DocManager.prototype);

45
js/misc/gnomeSession.js Normal file
View File

@ -0,0 +1,45 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const DBus = imports.dbus;
const Lang = imports.lang;
const PresenceIface = {
name: 'org.gnome.SessionManager.Presence',
methods: [{ name: 'SetStatus',
inSignature: 'u' }],
properties: [{ name: 'status',
signature: 'u',
access: 'readwrite' }],
signals: [{ name: 'StatusChanged',
inSignature: 'u' }]
};
const PresenceStatus = {
AVAILABLE: 0,
INVISIBLE: 1,
BUSY: 2,
IDLE: 3
};
function Presence() {
this._init();
}
Presence.prototype = {
_init: function() {
DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager/Presence', this);
},
getStatus: function(callback) {
this.GetRemote('status', Lang.bind(this,
function(status, ex) {
if (!ex)
callback(this, status);
}));
},
setStatus: function(status) {
this.SetStatusRemote(status);
}
};
DBus.proxifyPrototype(Presence.prototype, PresenceIface);

View File

@ -2,7 +2,7 @@
// parse:
// @params: caller-provided parameter object, or %null
// @default: function-provided defaults object
// @defaults: function-provided defaults object
// @allowExtras: whether or not to allow properties not in @default
//
// Examines @params and fills in default values from @defaults for
@ -10,24 +10,26 @@
// @allowExtras is not %true, it will throw an error if @params
// contains any properties that aren't in @defaults.
//
// If @params is %null, this returns @defaults.
// If @params is %null, this returns the values from @defaults.
//
// Return value: the updated params
// Return value: a new object, containing the merged parameters from
// @params and @defaults
function parse(params, defaults, allowExtras) {
let ret = {}, prop;
if (!params)
return defaults;
params = {};
if (!allowExtras) {
for (let prop in params) {
if (!(prop in defaults))
throw new Error('Unrecognized parameter "' + prop + '"');
}
for (prop in params) {
if (!(prop in defaults) && !allowExtras)
throw new Error('Unrecognized parameter "' + prop + '"');
ret[prop] = params[prop];
}
for (let prop in defaults) {
for (prop in defaults) {
if (!(prop in params))
params[prop] = defaults[prop];
ret[prop] = defaults[prop];
}
return params;
return ret;
}

372
js/misc/telepathy.js Normal file
View File

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

4
js/perf/Makefile.am Normal file
View File

@ -0,0 +1,4 @@
jsperfdir = $(pkgdatadir)/js/perf
dist_jsperf_DATA = \
core.js

102
js/perf/core.js Normal file
View File

@ -0,0 +1,102 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Main = imports.ui.main;
const Scripting = imports.ui.scripting;
// This performance script measure the most important (core) performance
// metrics for the shell. By looking at the output metrics of this script
// someone should be able to get an idea of how well the shell is performing
// on a particular system.
let METRICS = {
overviewLatencyFirst:
{ description: "Time to first frame after triggering overview, first time",
units: "us" },
overviewFramesFirst:
{ description: "Frames displayed when going to overview, first time",
units: "frames" },
overviewLatencySubsequent:
{ description: "Time to first frame after triggering overview, second time",
units: "us"},
overviewFramesSubsequent:
{ description: "Frames displayed when going to overview, second time",
units: "us" },
usedAfterOverview:
{ description: "Malloc'ed bytes after the overview is shown once",
units: "B" },
leakedAfterOverview:
{ description: "Additional malloc'ed bytes the second time the overview is shown",
units: "B" }
};
function run() {
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview");
yield Scripting.sleep(1000);
yield Scripting.waitLeisure();
for (let i = 0; i < 2; i++) {
Scripting.scriptEvent('overviewShowStart');
Main.overview.show();
yield Scripting.waitLeisure();
Scripting.scriptEvent('overviewShowDone');
Main.overview.hide();
yield Scripting.waitLeisure();
global.gc();
yield Scripting.sleep(1000);
Scripting.collectStatistics();
Scripting.scriptEvent('afterShowHide');
}
}
let showingOverview = false;
let overviewShowStart;
let overviewFrames;
let overviewLatency;
let mallocUsedSize = 0;
let overviewShowCount = 0;
let firstOverviewUsedSize;
function script_overviewShowStart(time) {
showingOverview = true;
overviewShowStart = time;
overviewFrames = 0;
}
function script_overviewShowDone(time) {
showingOverview = false;
overviewShowCount++;
if (overviewShowCount == 1) {
METRICS.overviewLatencyFirst.value = overviewLatency;
METRICS.overviewFramesFirst.value = overviewFrames;
} else {
METRICS.overviewLatencySubsequent.value = overviewLatency;
METRICS.overviewFramesSubsequent.value = overviewFrames;
}
}
function script_afterShowHide(time) {
if (overviewShowCount == 1) {
METRICS.usedAfterOverview.value = mallocUsedSize;
} else {
METRICS.leakedAfterOverview.value = mallocUsedSize - METRICS.usedAfterOverview.value;
}
}
function malloc_usedSize(time, bytes) {
mallocUsedSize = bytes;
}
function clutter_stagePaintDone(time) {
if (showingOverview) {
if (overviewFrames == 0)
overviewLatency = time - overviewShowStart;
overviewFrames++;
}
}

4
js/prefs/Makefile.am Normal file
View File

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

View File

@ -0,0 +1,93 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const GConf = imports.gi.GConf;
const Lang = imports.lang;
const Signals = imports.signals;
const GCONF_DIR = '/desktop/gnome/shell/clock';
const FORMAT_KEY = GCONF_DIR + '/format';
const SHOW_DATE_KEY = GCONF_DIR + '/show_date';
const SHOW_SECONDS_KEY = GCONF_DIR + '/show_seconds';
function ClockPreferences(uiFile) {
this._init(uiFile);
};
ClockPreferences.prototype = {
_init: function(uiFile) {
let builder = new Gtk.Builder();
builder.add_from_file(uiFile);
this._dialog = builder.get_object('prefs-dialog');
this._dialog.connect('response', Lang.bind(this, this._onResponse));
this._12hrRadio = builder.get_object('12hr_radio');
this._24hrRadio = builder.get_object('24hr_radio');
this._dateCheck = builder.get_object('date_check');
this._secondsCheck = builder.get_object('seconds_check');
delete builder;
this._gconf = GConf.Client.get_default();
this._gconf.add_dir(GCONF_DIR, GConf.ClientPreloadType.PRELOAD_NONE);
this._notifyId = this._gconf.notify_add(GCONF_DIR,
Lang.bind(this,
this._updateDialog));
this._12hrRadio.connect('toggled', Lang.bind(this,
function() {
let format = this._12hrRadio.active ? '12-hour' : '24-hour';
this._gconf.set_string(FORMAT_KEY, format);
}));
this._dateCheck.connect('toggled', Lang.bind(this,
function() {
this._gconf.set_bool(SHOW_DATE_KEY, this._dateCheck.active);
}));
this._secondsCheck.connect('toggled', Lang.bind(this,
function() {
this._gconf.set_bool(SHOW_SECONDS_KEY,
this._secondsCheck.active);
}));
this._updateDialog();
},
show: function() {
this._dialog.show_all();
},
_updateDialog: function() {
let format = this._gconf.get_string(FORMAT_KEY);
this._12hrRadio.active = (format == "12-hour");
this._24hrRadio.active = (format == "24-hour");
this._dateCheck.active = this._gconf.get_bool(SHOW_DATE_KEY);
this._secondsCheck.active = this._gconf.get_bool(SHOW_SECONDS_KEY);
},
_onResponse: function() {
this._dialog.destroy();
this._gconf.notify_remove(this._notifyId);
this.emit('destroy');
}
};
Signals.addSignalMethods(ClockPreferences.prototype);
function main(params) {
if ('progName' in params)
GLib.set_prgname(params['progName']);
Gtk.init(null, null);
let clockPrefs = new ClockPreferences(params['uiFile']);
clockPrefs.connect('destroy',
function() {
Gtk.main_quit();
});
clockPrefs.show();
Gtk.main();
}

View File

@ -4,17 +4,20 @@ dist_jsui_DATA = \
altTab.js \
appDisplay.js \
appFavorites.js \
boxpointer.js \
calendar.js \
chrome.js \
dash.js \
dnd.js \
docDisplay.js \
environment.js \
extensionSystem.js \
extensionSystem.js \
genericDisplay.js \
lightbox.js \
link.js \
lookingGlass.js \
magnifier.js \
magnifierDBus.js \
main.js \
messageTray.js \
notificationDaemon.js \
@ -22,15 +25,14 @@ dist_jsui_DATA = \
panel.js \
placeDisplay.js \
runDialog.js \
search.js \
scripting.js \
search.js \
shellDBus.js \
sidebar.js \
statusMenu.js \
telepathyClient.js \
tweener.js \
widget.js \
widgetBox.js \
windowAttentionHandler.js \
windowAttentionHandler.js \
windowManager.js \
workspacesView.js \
workspaceSwitcherPopup.js \
workspaceSwitcherPopup.js \
workspace.js

View File

@ -1,6 +1,5 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Lang = imports.lang;
@ -14,15 +13,7 @@ const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const POPUP_ARROW_COLOR = new Clutter.Color();
POPUP_ARROW_COLOR.from_pixel(0xffffffff);
const POPUP_UNFOCUSED_ARROW_COLOR = new Clutter.Color();
POPUP_UNFOCUSED_ARROW_COLOR.from_pixel(0x808080ff);
const TRANSPARENT_COLOR = new Clutter.Color();
TRANSPARENT_COLOR.from_pixel(0x00000000);
const POPUP_APPICON_SIZE = 96;
const POPUP_LIST_SPACING = 8;
const POPUP_SCROLL_TIME = 0.10; // seconds
const DISABLE_HOVER_TIMEOUT = 500; // milliseconds
@ -43,7 +34,8 @@ function AltTabPopup() {
AltTabPopup.prototype = {
_init : function() {
this.actor = new Shell.GenericContainer({ reactive: true });
this.actor = new Shell.GenericContainer({ name: 'altTabPopup',
reactive: true });
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
@ -54,7 +46,7 @@ AltTabPopup.prototype = {
this._haveModal = false;
this._currentApp = 0;
this._currentWindow = 0;
this._currentWindow = -1;
this._thumbnailTimeoutId = 0;
this._motionTimeoutId = 0;
@ -62,7 +54,7 @@ AltTabPopup.prototype = {
// the switcher appears underneath the current pointer location
this._disableHover();
global.stage.add_actor(this.actor);
Main.uiGroup.add_actor(this.actor);
},
_getPreferredWidth: function (actor, forHeight, alloc) {
@ -79,12 +71,18 @@ AltTabPopup.prototype = {
let childBox = new Clutter.ActorBox();
let focus = global.get_focus_monitor();
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
let bottomPadding = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
let vPadding = this.actor.get_theme_node().get_vertical_padding();
let hPadding = leftPadding + rightPadding;
// Allocate the appSwitcher
// We select a size based on an icon size that does not overflow the screen
let [childMinHeight, childNaturalHeight] = this._appSwitcher.actor.get_preferred_height(focus.width - POPUP_LIST_SPACING * 2);
let [childMinHeight, childNaturalHeight] = this._appSwitcher.actor.get_preferred_height(focus.width - hPadding);
let [childMinWidth, childNaturalWidth] = this._appSwitcher.actor.get_preferred_width(childNaturalHeight);
childBox.x1 = Math.max(POPUP_LIST_SPACING, focus.x + Math.floor((focus.width - childNaturalWidth) / 2));
childBox.x2 = Math.min(childBox.x1 + focus.width - POPUP_LIST_SPACING * 2, childBox.x1 + childNaturalWidth);
childBox.x1 = Math.max(focus.x + leftPadding, focus.x + Math.floor((focus.width - childNaturalWidth) / 2));
childBox.x2 = Math.min(childBox.x1 + focus.width - hPadding, childBox.x1 + childNaturalWidth);
childBox.y1 = focus.y + Math.floor((focus.height - childNaturalHeight) / 2);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._appSwitcher.actor.allocate(childBox, flags);
@ -94,20 +92,26 @@ AltTabPopup.prototype = {
// those calculations
if (this._thumbnails) {
let icon = this._appIcons[this._currentApp].actor;
// Force a stage relayout to make sure we get the correct position
global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, 0, 0);
let [posX, posY] = icon.get_transformed_position();
let thumbnailCenter = posX + icon.width / 2;
let [childMinWidth, childNaturalWidth] = this._thumbnails.actor.get_preferred_width(-1);
childBox.x1 = Math.max(POPUP_LIST_SPACING, Math.floor(thumbnailCenter - childNaturalWidth / 2));
if (childBox.x1 + childNaturalWidth > focus.width - POPUP_LIST_SPACING * 2) {
let offset = childBox.x1 + childNaturalWidth - focus.width + POPUP_LIST_SPACING * 2;
childBox.x1 = Math.max(POPUP_LIST_SPACING, childBox.x1 - offset - POPUP_LIST_SPACING * 2);
childBox.x1 = Math.max(focus.x + leftPadding, Math.floor(thumbnailCenter - childNaturalWidth / 2));
if (childBox.x1 + childNaturalWidth > focus.x + focus.width - hPadding) {
let offset = childBox.x1 + childNaturalWidth - focus.width + hPadding;
childBox.x1 = Math.max(focus.x + leftPadding, childBox.x1 - offset - hPadding);
}
let [found, spacing] = this.actor.get_theme_node().get_length('spacing', false);
if (!found)
spacing = 0;
childBox.x2 = childBox.x1 + childNaturalWidth;
if (childBox.x2 > focus.width - POPUP_LIST_SPACING)
childBox.x2 = focus.width - POPUP_LIST_SPACING;
childBox.y1 = this._appSwitcher.actor.allocation.y2 + POPUP_LIST_SPACING * 2;
this._thumbnails.addClones(focus.height - POPUP_LIST_SPACING - childBox.y1);
if (childBox.x2 > focus.x + focus.width - rightPadding)
childBox.x2 = focus.x + focus.width - rightPadding;
childBox.y1 = this._appSwitcher.actor.allocation.y2 + spacing;
this._thumbnails.addClones(focus.height - bottomPadding - childBox.y1);
let [childMinHeight, childNaturalHeight] = this._thumbnails.actor.get_preferred_height(-1);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._thumbnails.actor.allocate(childBox, flags);
@ -116,7 +120,7 @@ AltTabPopup.prototype = {
show : function(backward) {
let tracker = Shell.WindowTracker.get_default();
let apps = tracker.get_running_apps ("");
let apps = tracker.get_running_apps ('');
if (!apps.length)
return false;
@ -160,8 +164,9 @@ AltTabPopup.prototype = {
this._select(0, 1, true);
else
this._select(1);
} else
} else {
this._select(1);
}
}
// There's a race condition; if the user released Alt before
@ -169,7 +174,7 @@ AltTabPopup.prototype = {
// https://bugzilla.gnome.org/show_bug.cgi?id=596695 for
// details.) So we check now. (Have to do this after updating
// selection.)
let mods = global.get_modifier_keys();
let [x, y, mods] = global.get_pointer();
if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
this._finish();
return false;
@ -186,10 +191,16 @@ AltTabPopup.prototype = {
},
_nextWindow : function() {
// We actually want the second window if we're in the unset state
if (this._currentWindow == -1)
this._currentWindow = 0;
return mod(this._currentWindow + 1,
this._appIcons[this._currentApp].cachedWindows.length);
},
_previousWindow : function() {
// Also assume second window here
if (this._currentWindow == -1)
this._currentWindow = 1;
return mod(this._currentWindow - 1,
this._appIcons[this._currentApp].cachedWindows.length);
},
@ -209,7 +220,7 @@ AltTabPopup.prototype = {
this.destroy();
else if (this._thumbnailsFocused) {
if (keysym == Clutter.Tab) {
if (shift && this._currentWindow == 0)
if (shift && (this._currentWindow == 0 || this._currentWindow == -1))
this._select(this._previousApp());
else if (!shift && this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1)
this._select(this._nextApp());
@ -229,7 +240,7 @@ AltTabPopup.prototype = {
else if (keysym == Clutter.Right || keysym == Clutter.d)
this._select(this._nextApp());
else if (keysym == Clutter.Down || keysym == Clutter.s)
this._select(this._currentApp, this._currentWindow);
this._select(this._currentApp, 0);
}
return true;
@ -248,7 +259,7 @@ AltTabPopup.prototype = {
let direction = event.get_scroll_direction();
if (direction == Clutter.ScrollDirection.UP) {
if (this._thumbnailsFocused) {
if (this._currentWindow == 0)
if (this._currentWindow == 0 || this._currentWindow == -1)
this._select(this._previousApp());
else
this._select(this._currentApp, this._previousWindow());
@ -282,10 +293,17 @@ AltTabPopup.prototype = {
_appActivated : function(appSwitcher, n) {
// If the user clicks on the selected app, activate the
// selected window; otherwise (eg, they click on an app while
// !mouseActive) activate the first window of the clicked-on
// app.
let window = (n == this._currentApp) ? this._currentWindow : 0;
Main.activateWindow(this._appIcons[n].cachedWindows[window]);
// !mouseActive) activate the the clicked-on app.
if (n == this._currentApp) {
let window;
if (this._currentWindow >= 0)
window = this._appIcons[this._currentApp].cachedWindows[this._currentWindow];
else
window = null;
this._appIcons[this._currentApp].app.activate_window(window, global.get_current_time());
} else {
this._appIcons[n].app.activate_window(null, global.get_current_time());
}
this.destroy();
},
@ -297,7 +315,8 @@ AltTabPopup.prototype = {
},
_windowActivated : function(thumbnailList, n) {
Main.activateWindow(this._appIcons[this._currentApp].cachedWindows[n]);
let appIcon = this._appIcons[this._currentApp];
Main.activateWindow(appIcon.cachedWindows[n]);
this.destroy();
},
@ -324,8 +343,11 @@ AltTabPopup.prototype = {
_finish : function() {
let app = this._appIcons[this._currentApp];
let window = app.cachedWindows[this._currentWindow];
Main.activateWindow(window);
if (this._currentWindow >= 0) {
Main.activateWindow(app.cachedWindows[this._currentWindow]);
} else {
app.app.activate_window(null, global.get_current_time());
}
this.destroy();
},
@ -390,7 +412,7 @@ AltTabPopup.prototype = {
this._thumbnailsFocused = (window != null) && !forceAppFocus;
this._currentApp = app;
this._currentWindow = window ? window : 0;
this._currentWindow = window ? window : -1;
this._appSwitcher.highlight(app, this._thumbnailsFocused);
if (window != null) {
@ -402,18 +424,23 @@ AltTabPopup.prototype = {
!forceAppFocus) {
this._thumbnailTimeoutId = Mainloop.timeout_add (
THUMBNAIL_POPUP_TIME,
Lang.bind(this, function () {
this._select(this._currentApp, 0, true);
return false;
}));
Lang.bind(this, this._timeoutPopupThumbnails));
}
},
_timeoutPopupThumbnails: function() {
if (!this._thumbnails)
this._createThumbnails();
this._thumbnailTimeoutId = 0;
this._thumbnailsFocused = false;
return false;
},
_destroyThumbnails : function() {
Tweener.addTween(this._thumbnails.actor,
{ opacity: 0,
time: THUMBNAIL_FADE_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: function() { this.destroy(); }
});
this._thumbnails = null;
@ -430,7 +457,7 @@ AltTabPopup.prototype = {
Tweener.addTween(this._thumbnails.actor,
{ opacity: 255,
time: THUMBNAIL_FADE_TIME,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
}
};
@ -441,12 +468,19 @@ function SwitcherList(squareItems) {
SwitcherList.prototype = {
_init : function(squareItems) {
this.actor = new St.BoxLayout({ style_class: 'switcher-list' });
this.actor = new Shell.GenericContainer({ style_class: 'switcher-list' });
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate', Lang.bind(this, this._allocateTop));
// Here we use a GenericContainer so that we can force all the
// children except the separator to have the same width.
this._list = new Shell.GenericContainer();
this._list.spacing = POPUP_LIST_SPACING;
this._list = new Shell.GenericContainer({ style_class: 'switcher-list-item-container' });
this._list.spacing = 0;
this._list.connect('style-changed', Lang.bind(this, function() {
let [found, spacing] = this._list.get_theme_node().get_length('spacing', false);
this._list.spacing = (found) ? spacing : 0;
}));
this._list.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this._list.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
@ -462,26 +496,72 @@ SwitcherList.prototype = {
this.actor.add_actor(this._rightGradient);
// Those arrows indicate whether scrolling in one direction is possible
this._leftArrow = new St.DrawingArea();
this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
pseudo_class: 'highlighted' });
this._leftArrow.connect('repaint', Lang.bind(this,
function (area) {
Shell.draw_box_pointer(area, Shell.PointerDirection.LEFT, TRANSPARENT_COLOR, POPUP_ARROW_COLOR);
Shell.draw_box_pointer(area, Shell.PointerDirection.LEFT);
}));
this._rightArrow = new St.DrawingArea();
this._rightArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
pseudo_class: 'highlighted' });
this._rightArrow.connect('repaint', Lang.bind(this,
function (area) {
Shell.draw_box_pointer(area, Shell.PointerDirection.RIGHT, TRANSPARENT_COLOR, POPUP_ARROW_COLOR);
Shell.draw_box_pointer(area, Shell.PointerDirection.RIGHT);
}));
this._leftGradient.add_actor(this._leftArrow);
this._rightGradient.add_actor(this._rightArrow);
this.actor.add_actor(this._leftArrow);
this.actor.add_actor(this._rightArrow);
this._items = [];
this._highlighted = -1;
this._separator = null;
this._squareItems = squareItems;
this._scrollable = false;
this._minSize = 0;
this._scrollableRight = true;
this._scrollableLeft = false;
},
_allocateTop: function(actor, box, flags) {
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
let childBox = new Clutter.ActorBox();
let scrollable = this._minSize > box.x2 - box.x1;
this._clipBin.allocate(box, flags);
childBox.x1 = 0;
childBox.y1 = 0;
childBox.x2 = this._leftGradient.width;
childBox.y2 = this.actor.height;
this._leftGradient.allocate(childBox, flags);
this._leftGradient.opacity = (this._scrollableLeft && scrollable) ? 255 : 0;
childBox.x1 = (this.actor.allocation.x2 - this.actor.allocation.x1) - this._rightGradient.width;
childBox.y1 = 0;
childBox.x2 = childBox.x1 + this._rightGradient.width;
childBox.y2 = this.actor.height;
this._rightGradient.allocate(childBox, flags);
this._rightGradient.opacity = (this._scrollableRight && scrollable) ? 255 : 0;
let arrowWidth = Math.floor(leftPadding / 3);
let arrowHeight = arrowWidth * 2;
childBox.x1 = leftPadding / 2;
childBox.y1 = this.actor.height / 2 - arrowWidth;
childBox.x2 = childBox.x1 + arrowWidth;
childBox.y2 = childBox.y1 + arrowHeight;
this._leftArrow.allocate(childBox, flags);
this._leftArrow.opacity = this._leftGradient.opacity;
arrowWidth = Math.floor(rightPadding / 3);
arrowHeight = arrowWidth * 2;
childBox.x1 = this.actor.width - arrowWidth - rightPadding / 2;
childBox.y1 = this.actor.height / 2 - arrowWidth;
childBox.x2 = childBox.x1 + arrowWidth;
childBox.y2 = childBox.y1 + arrowHeight;
this._rightArrow.allocate(childBox, flags);
this._rightArrow.opacity = this._rightGradient.opacity;
},
addItem : function(item) {
@ -525,8 +605,7 @@ SwitcherList.prototype = {
let itemSize = this._items[index].allocation.x2 - this._items[index].allocation.x1;
let [posX, posY] = this._items[index].get_transformed_position();
posX += this.actor.x;
if (posX + itemSize > monitor.width)
if (posX + itemSize > monitor.width + monitor.x)
this._scrollToRight();
else if (posX < 0)
this._scrollToLeft();
@ -535,28 +614,33 @@ SwitcherList.prototype = {
_scrollToLeft : function() {
let x = this._items[this._highlighted].allocation.x1;
this._rightGradient.show();
this._scrollableRight = true;
Tweener.addTween(this._list, { anchor_x: x,
time: POPUP_SCROLL_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () {
if (this._highlighted == 0)
this._leftGradient.hide();
if (this._highlighted == 0) {
this._scrollableLeft = false;
this.actor.queue_relayout();
}
})
});
},
_scrollToRight : function() {
this._scrollableLeft = true;
let monitor = global.get_focus_monitor();
let padding = this.actor.get_theme_node().get_horizontal_padding();
let x = this._items[this._highlighted].allocation.x2 - monitor.width + padding + POPUP_LIST_SPACING * 2;
this._leftGradient.show();
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
let x = this._items[this._highlighted].allocation.x2 - monitor.width + padding + parentPadding;
Tweener.addTween(this._list, { anchor_x: x,
time: POPUP_SCROLL_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () {
if (this._highlighted == this._items.length - 1)
this._rightGradient.hide();
if (this._highlighted == this._items.length - 1) {
this._scrollableRight = false;
this.actor.queue_relayout();
}
})
});
},
@ -600,6 +684,7 @@ SwitcherList.prototype = {
let totalSpacing = this._list.spacing * (this._items.length - 1);
alloc.min_size = this._items.length * maxChildMin + separatorWidth + totalSpacing;
alloc.natural_size = alloc.min_size;
this._minSize = alloc.min_size;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
@ -642,11 +727,14 @@ SwitcherList.prototype = {
let childBox = new Clutter.ActorBox();
let focus = global.get_focus_monitor();
if (this.actor.allocation.x2 == focus.width - POPUP_LIST_SPACING) {
let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
if (this.actor.allocation.x2 == focus.x + focus.width - parentRightPadding) {
if (this._squareItems)
childWidth = childHeight;
else
childWidth = children[0].get_preferred_width(childHeight)[0];
else {
let [childMin, childNat] = children[0].get_preferred_width(childHeight);
childWidth = childMin;
}
}
for (let i = 0; i < children.length; i++) {
@ -679,36 +767,6 @@ SwitcherList.prototype = {
let topPadding = this.actor.get_theme_node().get_padding(St.Side.TOP);
let bottomPadding = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
// Show the arrows and gradients when scrolling is needed
if (children[children.length - 1].allocation.x2 > this.actor.width - leftPadding - rightPadding && !this._scrollable) {
this._leftGradient.set_height(this.actor.height);
this._leftGradient.x = this.actor.x;
this._leftGradient.y = this.actor.y;
this._rightGradient.set_height(this.actor.height);
this._rightGradient.x = this.actor.x + (this.actor.allocation.x2 - this.actor.allocation.x1) - this._rightGradient.width;
this._rightGradient.y = this.actor.y;
let arrowWidth = Math.floor(leftPadding / 3);
let arrowHeight = arrowWidth * 2;
this._leftArrow.set_size(arrowWidth, arrowHeight);
this._leftArrow.set_position(POPUP_LIST_SPACING, this.actor.height / 2 - arrowWidth);
arrowWidth = Math.floor(rightPadding / 3);
arrowHeight = arrowWidth * 2;
this._rightArrow.set_size(arrowWidth, arrowHeight);
this._rightArrow.set_position(this._rightGradient.width - arrowHeight, this.actor.height / 2 - arrowWidth);
this._scrollable = true;
this._leftGradient.hide();
this._rightGradient.show();
}
else if (!this._scrollable){
this._leftGradient.hide();
this._rightGradient.hide();
}
// Clip the area for scrolling
this._clipBin.set_clip(0, -topPadding, (this.actor.allocation.x2 - this.actor.allocation.x1) - leftPadding - rightPadding, this.actor.height + bottomPadding);
}
@ -723,7 +781,7 @@ function AppIcon(app) {
AppIcon.prototype = {
_init: function(app) {
this.app = app;
this.actor = new St.BoxLayout({ style_class: "alt-tab-app",
this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
vertical: true });
this.icon = null;
this._iconBin = new St.Bin();
@ -783,6 +841,8 @@ AppSwitcher.prototype = {
_getPreferredHeight: function (actor, forWidth, alloc) {
let j = 0;
let height = 0;
while(this._items.length > 1 && this._items[j].style_class != 'item-box') {
j++;
}
@ -793,16 +853,11 @@ AppSwitcher.prototype = {
if (this._separator)
totalSpacing += this._separator.width + this._list.spacing;
// We just assume the whole screen here due to weirdness happing with the passed width
let focus = global.get_focus_monitor();
let availWidth = focus.width - POPUP_LIST_SPACING * 2 - this.actor.get_theme_node().get_horizontal_padding();
let height = 0;
for(let i = 0; i < iconSizes.length; i++) {
this._iconSize = iconSizes[i];
height = iconSizes[i] + iconSpacing;
let w = height * this._items.length + totalSpacing;
if (w <= availWidth)
if (w <= forWidth)
break;
}
@ -811,17 +866,17 @@ AppSwitcher.prototype = {
height = iconSizes[0] + iconSpacing;
}
alloc.min_size = height;
alloc.natural_size = height;
},
_allocate: function (actor, box, flags) {
for(let i = 0; i < this.icons.length; i++) {
if (this.icons[i].icon != null)
break;
this.icons[i].set_size(this._iconSize);
}
alloc.min_size = height;
alloc.natural_size = height;
},
_allocate: function (actor, box, flags) {
// Allocate the main list items
SwitcherList.prototype._allocate.call(this, actor, box, flags);
@ -846,16 +901,13 @@ AppSwitcher.prototype = {
// thumbnails are visible (ie, when the app icon is supposed to be
// in justOutline mode). Apps with multiple windows will normally
// show a dim arrow, but show a bright arrow when they are
// highlighted; their redraw handler will use the right color
// based on this._curApp; we just need to do a queue_relayout() to
// force it to redraw. (queue_redraw() doesn't work because
// ShellDrawingArea only redraws on allocate.)
// highlighted.
highlight : function(n, justOutline) {
if (this._curApp != -1) {
if (this.icons[this._curApp].cachedWindows.length == 1)
this._arrows[this._curApp].hide();
else
this._arrows[this._curApp].queue_relayout();
this._arrows[this._curApp].remove_style_pseudo_class('highlighted');
}
SwitcherList.prototype.highlight.call(this, n, justOutline);
@ -865,7 +917,7 @@ AppSwitcher.prototype = {
if (justOutline && this.icons[this._curApp].cachedWindows.length == 1)
this._arrows[this._curApp].show();
else
this._arrows[this._curApp].queue_relayout();
this._arrows[this._curApp].add_style_pseudo_class('highlighted');
}
},
@ -874,12 +926,10 @@ AppSwitcher.prototype = {
this.addItem(appIcon.actor);
let n = this._arrows.length;
let arrow = new St.DrawingArea();
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
arrow.connect('repaint', Lang.bind(this,
function (area) {
Shell.draw_box_pointer(area, Shell.PointerDirection.DOWN,
TRANSPARENT_COLOR,
this._curApp == n ? POPUP_ARROW_COLOR : POPUP_UNFOCUSED_ARROW_COLOR);
Shell.draw_box_pointer(area, Shell.PointerDirection.DOWN);
}));
this._list.add_actor(arrow);
this._arrows.push(arrow);
@ -914,7 +964,7 @@ ThumbnailList.prototype = {
let activeWorkspace = global.screen.get_active_workspace();
// We fake the value of "separatorAdded" when the app has no window
// We fake the value of 'separatorAdded' when the app has no window
// on the current workspace, to avoid displaying a useless separator in
// that case.
let separatorAdded = windows.length == 0 || windows[0].get_workspace() != activeWorkspace;
@ -930,10 +980,10 @@ ThumbnailList.prototype = {
separatorAdded = true;
}
let box = new St.BoxLayout({ style_class: "thumbnail-box",
let box = new St.BoxLayout({ style_class: 'thumbnail-box',
vertical: true });
let bin = new St.Bin({ style_class: "thumbnail" });
let bin = new St.Bin({ style_class: 'thumbnail' });
box.add_actor(bin);
this._thumbnailBins.push(bin);

View File

@ -1,6 +1,5 @@
/* -*- 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;
@ -23,6 +22,7 @@ const Workspace = imports.ui.workspace;
const APPICON_SIZE = 48;
const WELL_MAX_COLUMNS = 8;
const MENU_POPUP_TIMEOUT = 600;
function AllAppView() {
this._init();
@ -286,17 +286,12 @@ BaseAppSearchProvider.prototype = {
activateResult: function(id) {
let app = this._appSys.get_app(id);
let windows = app.get_windows();
if (windows.length > 0)
Main.activateWindow(windows[0]);
else
app.launch();
app.activate();
},
dragActivateResult: function(id) {
let app = this._appSys.get_app(id);
app.launch();
app.open_new_window();
}
};
@ -328,7 +323,7 @@ AppSearchProvider.prototype = {
},
expandSearch: function(terms) {
log("TODO expand search");
log('TODO expand search');
}
};
@ -391,7 +386,6 @@ function AppWellIcon(app) {
AppWellIcon.prototype = {
_init : function(app) {
this.app = app;
this._running = false;
this.actor = new St.Clickable({ style_class: 'app-well-app',
reactive: true,
x_fill: true,
@ -404,68 +398,73 @@ AppWellIcon.prototype = {
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this._menu = null;
this._draggable = DND.makeDraggable(this.actor,
{ manualMode: true });
this._dragStartX = null;
this._dragStartY = null;
this._draggable = DND.makeDraggable(this.actor);
this._draggable.connect('drag-begin', Lang.bind(this,
function () {
this._removeMenuTimeout();
}));
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('notify::hover', Lang.bind(this, this._onHoverChange));
this.actor.connect('show', Lang.bind(this, this._onShow));
this.actor.connect('hide', Lang.bind(this, this._onHideDestroy));
this.actor.connect('destroy', Lang.bind(this, this._onHideDestroy));
this._appWindowChangedId = 0;
this._stateChangedId = 0;
this._menuTimeoutId = 0;
},
_onShow: function() {
this._appWindowChangedId = this.app.connect('windows-changed',
Lang.bind(this,
this._updateStyleClass));
this._updateStyleClass();
this._stateChangedId = this.app.connect('notify::state',
Lang.bind(this,
this._onStateChanged));
this._onStateChanged();
},
_onHideDestroy: function() {
if (this._appWindowChangedId > 0)
this.app.disconnect(this._appWindowChangedId);
if (this._stateChangedId > 0)
this.app.disconnect(this._stateChangedId);
this._removeMenuTimeout();
},
_updateStyleClass: function() {
let windows = this.app.get_windows();
let running = windows.length > 0;
this._running = running;
let style = "app-well-app";
if (this._running)
style += " running";
if (this._selected)
style += " selected";
this.actor.style_class = style;
_removeMenuTimeout: function() {
if (this._menuTimeoutId > 0) {
Mainloop.source_remove(this._menuTimeoutId);
this._menuTimeoutId = 0;
}
},
_onStateChanged: function() {
if (this.app.state != Shell.AppState.STOPPED)
this.actor.add_style_class_name('running');
else
this.actor.remove_style_class_name('running');
},
_onButtonPress: function(actor, event) {
let [stageX, stageY] = event.get_coords();
this._dragStartX = stageX;
this._dragStartY = stageY;
},
_onHoverChange: function(actor) {
let hover = this.actor.hover;
if (!hover) {
if (this.actor.pressed && this._dragStartX != null) {
this.actor.fake_release();
this._draggable.startDrag(this._dragStartX, this._dragStartY,
global.get_current_time());
} else {
this._dragStartX = null;
this._dragStartY = null;
}
let button = event.get_button();
if (button == 1) {
this._removeMenuTimeout();
this._menuTimeoutId = Mainloop.timeout_add(MENU_POPUP_TIMEOUT,
Lang.bind(this, function() {
this.popupMenu(button);
}));
}
},
_onClicked: function(actor, event) {
this._removeMenuTimeout();
let button = event.get_button();
if (button == 1) {
this._onActivate(event);
} else if (button == 2) {
let newWorkspace = Main.overview.workspaces.addWorkspace();
if (newWorkspace != null) {
newWorkspace.activate(global.get_current_time());
this.emit('launching');
this.app.open_new_window();
Main.overview.hide();
}
} else if (button == 3) {
// Don't bind to the right click here; we want left click outside the
// area to deactivate as well.
@ -479,6 +478,9 @@ AppWellIcon.prototype = {
},
popupMenu: function(activatingButton) {
this._removeMenuTimeout();
this.actor.fake_release();
if (!this._menu) {
this._menu = new AppIconMenu(this);
this._menu.connect('highlight-window', Lang.bind(this, function (menu, window) {
@ -501,11 +503,6 @@ AppWellIcon.prototype = {
return false;
},
activateMostRecentWindow: function () {
let mostRecentWindow = this.app.get_windows()[0];
Main.activateWindow(mostRecentWindow);
},
highlightWindow: function(metaWindow) {
if (this._didActivateWindow)
return;
@ -518,13 +515,17 @@ AppWellIcon.prototype = {
if (metaWindow) {
this._didActivateWindow = true;
Main.activateWindow(metaWindow);
} else
} else {
Main.overview.hide();
}
},
setSelected: function (isSelected) {
this._selected = isSelected;
this._updateStyleClass();
if (this._selected)
this.actor.add_style_class_name('selected');
else
this.actor.remove_style_class_name('selected');
},
_onMenuPoppedUp: function() {
@ -536,6 +537,8 @@ AppWellIcon.prototype = {
},
_onMenuPoppedDown: function() {
this.actor.sync_hover();
if (this._didActivateWindow)
return;
if (!this._setWindowSelection)
@ -546,38 +549,24 @@ AppWellIcon.prototype = {
},
_getRunning: function() {
return this.app.get_windows().length > 0;
return this.app.state != Shell.AppState.STOPPED;
},
_onActivate: function (event) {
let running = this._getRunning();
this.emit('launching');
let modifiers = Shell.get_event_state(event);
if (!running) {
this.app.launch();
Main.overview.hide();
if (modifiers & Clutter.ModifierType.CONTROL_MASK
&& this.app.state == Shell.AppState.RUNNING) {
this.app.open_new_window();
} else {
let modifiers = Shell.get_event_state(event);
if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
this.app.launch();
Main.overview.hide();
} else {
this.activateMostRecentWindow();
}
this.app.activate();
}
Main.overview.hide();
},
shellWorkspaceLaunch : function() {
// Here we just always launch the application again, even if we know
// it was already running. For most applications this
// should have the effect of creating a new window, whether that's
// a second process (in the case of Calculator) or IPC to existing
// instance (Firefox). There are a few less-sensical cases such
// as say Pidgin, but ideally what we do there is have the app
// express to us that it doesn't do relaunch=new-window in the
// .desktop file.
this.app.launch();
this.app.open_new_window();
},
getDragActor: function() {
@ -600,26 +589,19 @@ AppIconMenu.prototype = {
_init: function(source) {
this._source = source;
this._arrowSize = 4; // CSS default
this._spacing = 0; // CSS default
this._dragStartX = 0;
this._dragStartY = 0;
this.actor = new Shell.GenericContainer({ reactive: true });
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate', Lang.bind(this, this._allocate));
this._windowContainerBox = new St.Bin({ style_class: 'app-well-menu' });
this._windowContainer = new Shell.Menu({ orientation: Big.BoxOrientation.VERTICAL,
width: Main.overview._dash.actor.width });
this._windowContainerBox.set_child(this._windowContainer);
this._windowContainer = new Shell.Menu({ style_class: 'app-well-menu',
vertical: true,
width: Main.overview._dash.actor.width });
this._windowContainer.connect('unselected', Lang.bind(this, this._onItemUnselected));
this._windowContainer.connect('selected', Lang.bind(this, this._onItemSelected));
this._windowContainer.connect('cancelled', Lang.bind(this, this._onWindowSelectionCancelled));
this._windowContainer.connect('activate', Lang.bind(this, this._onItemActivate));
this.actor.add_actor(this._windowContainerBox);
this.actor.add_actor(this._windowContainer);
// Stay popped up on release over application icon
this._windowContainer.set_persistent_source(this._source.actor);
@ -629,16 +611,9 @@ AppIconMenu.prototype = {
this._windowContainer.connect('leave-event', Lang.bind(this, this._onMenuLeave));
this._windowContainer.connect('button-release-event', Lang.bind(this, this._onMenuButtonRelease));
this._borderColor = new Clutter.Color();
this._backgroundColor = new Clutter.Color();
this._windowContainerBox.connect('style-changed', Lang.bind(this, this._onStyleChanged));
this._arrow = new St.DrawingArea();
this._arrow = new St.DrawingArea({ style_class: 'app-well-menu-arrow' });
this._arrow.connect('repaint', Lang.bind(this, function (area) {
Shell.draw_box_pointer(area,
Shell.PointerDirection.LEFT,
this._borderColor,
this._backgroundColor);
Shell.draw_box_pointer(area, Shell.PointerDirection.LEFT);
}));
this.actor.add_actor(this._arrow);
@ -649,43 +624,44 @@ AppIconMenu.prototype = {
}));
source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
global.stage.add_actor(this.actor);
Main.uiGroup.add_actor(this.actor);
},
_getPreferredWidth: function(actor, forHeight, alloc) {
let [min, natural] = this._windowContainerBox.get_preferred_width(forHeight);
min += this._arrowSize;
natural += this._arrowSize;
alloc.min_size = min;
alloc.natural_size = natural;
let [menuMin, menuNatural] = this._windowContainer.get_preferred_width(forHeight);
let [arrowMin, arrowNatural] = this._arrow.get_preferred_width(forHeight);
alloc.min_size = menuMin + arrowMin;
alloc.natural_size = menuNatural + arrowNatural;
},
_getPreferredHeight: function(actor, forWidth, alloc) {
let [min, natural] = this._windowContainerBox.get_preferred_height(forWidth);
let [min, natural] = this._windowContainer.get_preferred_height(forWidth);
alloc.min_size = min;
alloc.natural_size = natural;
},
_allocate: function(actor, box, flags) {
let childBox = new Clutter.ActorBox();
let themeNode = this._windowContainerBox.get_theme_node();
let themeNode = this._windowContainer.get_theme_node();
let width = box.x2 - box.x1;
let height = box.y2 - box.y1;
let [arrowMinWidth, arrowWidth] = this._arrow.get_preferred_width(height);
childBox.x1 = 0;
childBox.x2 = this._arrowSize;
childBox.y1 = Math.floor((height / 2) - (this._arrowSize / 2));
childBox.y2 = childBox.y1 + this._arrowSize;
childBox.x2 = arrowWidth;
childBox.y1 = Math.floor((height / 2) - (arrowWidth / 2));
childBox.y2 = childBox.y1 + arrowWidth;
this._arrow.allocate(childBox, flags);
// Ensure the arrow is above the border area
let border = themeNode.get_border_width(St.Side.LEFT);
childBox.x1 = this._arrowSize - border;
childBox.x1 = arrowWidth - border;
childBox.x2 = width;
childBox.y1 = 0;
childBox.y2 = height;
this._windowContainerBox.allocate(childBox, flags);
this._windowContainer.allocate(childBox, flags);
},
_redisplay: function() {
@ -737,8 +713,8 @@ AppIconMenu.prototype = {
},
_appendSeparator: function () {
let bin = new St.Bin({ style_class: "app-well-menu-separator" });
this._windowContainer.append_separator(bin, Big.BoxPackFlags.NONE);
let bin = new St.Bin({ style_class: 'app-well-menu-separator' });
this._windowContainer.add_actor(bin);
},
_appendMenuItem: function(labelText) {
@ -746,7 +722,7 @@ AppIconMenu.prototype = {
reactive: true });
let label = new St.Label({ text: labelText });
box.add(label);
this._windowContainer.append(box, Big.BoxPackFlags.NONE);
this._windowContainer.add_actor(box);
return box;
},
@ -797,12 +773,12 @@ AppIconMenu.prototype = {
_updateHighlight: function (item) {
if (this._highlightedItem) {
this._highlightedItem.set_style_pseudo_class(null);
this._highlightedItem.remove_style_pseudo_class('hover');
this.emit('highlight-window', null);
}
this._highlightedItem = item;
if (this._highlightedItem) {
item.set_style_pseudo_class('hover');
item.add_style_pseudo_class('hover');
let window = this._highlightedItem._window;
if (window)
this.emit('highlight-window', window);
@ -848,7 +824,7 @@ AppIconMenu.prototype = {
let metaWindow = child._window;
this.emit('activate-window', metaWindow);
} else if (child == this._newWindowMenuItem) {
this._source.app.launch();
this._source.app.open_new_window();
this.emit('activate-window', null);
} else if (child == this._toggleFavoriteMenuItem) {
let favs = AppFavorites.getAppFavorites();
@ -864,28 +840,6 @@ AppIconMenu.prototype = {
_onWindowSelectionCancelled: function () {
this.emit('highlight-window', null);
this.popdown();
},
_onStyleChanged: function() {
let themeNode = this._windowContainerBox.get_theme_node();
let [success, len] = themeNode.get_length('-shell-arrow-size', false);
if (success) {
this._arrowSize = len;
this.actor.queue_relayout();
}
[success, len] = themeNode.get_length('-shell-menu-spacing', false)
if (success) {
this._windowContainer.spacing = len;
}
let color = new Clutter.Color();
if (themeNode.get_background_color(color)) {
this._backgroundColor = color;
color = new Clutter.Color();
}
if (themeNode.get_border_color(St.Side.LEFT, color)) {
this._borderColor = color;
}
this._arrow.queue_repaint();
}
};
Signals.addSignalMethods(AppIconMenu.prototype);
@ -896,7 +850,7 @@ function WellGrid() {
WellGrid.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ name: "dashAppWell", vertical: true });
this.actor = new St.BoxLayout({ name: 'dashAppWell', vertical: true });
// Pulled from CSS, but hardcode some defaults here
this._spacing = 0;
this._item_size = 48;
@ -1027,15 +981,12 @@ AppWell.prototype = {
this._favorites = [];
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
x_align: Big.BoxAlignment.CENTER });
this._grid = new WellGrid();
this.actor = this._grid.actor;
this.actor._delegate = this;
this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
this._grid = new WellGrid();
this.actor.append(this._grid.actor, Big.BoxPackFlags.EXPAND);
this._tracker = Shell.WindowTracker.get_default();
this._appSystem = Shell.AppSystem.get_default();
@ -1061,7 +1012,7 @@ AppWell.prototype = {
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
/* hardcode here pending some design about how exactly desktop contexts behave */
let contextId = "";
let contextId = '';
let running = this._tracker.get_running_apps(contextId);
let runningIds = this._appIdListToHash(running);

164
js/ui/boxpointer.js Normal file
View File

@ -0,0 +1,164 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
/**
* BoxPointer:
* @side: A St.Side type; currently only St.Side.TOP is implemented
* @binProperties: Properties to set on contained bin
*
* An actor which displays a triangle "arrow" pointing to a given
* side. The .bin property is a container in which content can be
* placed. The arrow position may be controlled via setArrowOrigin().
*
*/
function BoxPointer(side, binProperties) {
this._init(side, binProperties);
}
BoxPointer.prototype = {
_init: function(arrowSide, binProperties) {
if (arrowSide != St.Side.TOP)
throw new Error('Not implemented');
this._arrowSide = arrowSide;
this._arrowOrigin = 0;
this.actor = new St.Bin({ x_fill: true,
y_fill: true });
this._container = new Shell.GenericContainer();
this.actor.set_child(this._container);
this._container.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this._container.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this._container.connect('allocate', Lang.bind(this, this._allocate));
this.bin = new St.Bin(binProperties);
this._container.add_actor(this.bin);
this._border = new St.DrawingArea();
this._border.connect('repaint', Lang.bind(this, this._drawBorder));
this._container.add_actor(this._border);
this.bin.raise(this._border);
},
_adjustAllocationForArrow: function(isWidth, alloc) {
let themeNode = this.actor.get_theme_node();
let found, borderWidth, base, rise;
[found, borderWidth] = themeNode.get_length('-arrow-border-width', false);
alloc.min_size += borderWidth * 2;
alloc.natural_size += borderWidth * 2;
if ((!isWidth && (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM))
|| (isWidth && (this._arrowSide == St.Side.LEFT || this._arrowSide == St.Side.RIGHT))) {
let [found, rise] = themeNode.get_length('-arrow-rise', false);
alloc.min_size += rise;
alloc.natural_size += rise;
}
},
_getPreferredWidth: function(actor, forHeight, alloc) {
let [minInternalSize, natInternalSize] = this.bin.get_preferred_width(forHeight);
alloc.min_size = minInternalSize;
alloc.natural_size = natInternalSize;
this._adjustAllocationForArrow(true, alloc);
},
_getPreferredHeight: function(actor, forWidth, alloc) {
let [minSize, naturalSize] = this.bin.get_preferred_height(forWidth);
alloc.min_size = minSize;
alloc.natural_size = naturalSize;
this._adjustAllocationForArrow(false, alloc);
},
_allocate: function(actor, box, flags) {
let themeNode = this.actor.get_theme_node();
let found, borderWidth, borderRadius, rise, base;
[found, borderWidth] = themeNode.get_length('-arrow-border-width', false);
[found, rise] = themeNode.get_length('-arrow-rise', false);
let childBox = new Clutter.ActorBox();
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
childBox.x1 = 0;
childBox.y1 = 0;
childBox.x2 = availWidth;
childBox.y2 = availHeight;
this._border.allocate(childBox, flags);
switch (this._arrowSide) {
case St.Side.TOP:
childBox.x1 = borderWidth;
childBox.y1 = rise + borderWidth;
childBox.x2 = availWidth - borderWidth;
childBox.y2 = availHeight - borderWidth;
break;
default:
break;
}
this.bin.allocate(childBox, flags);
},
_drawBorder: function(area) {
let themeNode = this.actor.get_theme_node();
let found, borderWidth, borderRadius, rise, base;
[found, borderWidth] = themeNode.get_length('-arrow-border-width', false);
[found, base] = themeNode.get_length('-arrow-base', false);
[found, rise] = themeNode.get_length('-arrow-rise', false);
[found, borderRadius] = themeNode.get_length('-arrow-border-radius', false);
let halfBorder = borderWidth / 2;
let borderColor = new Clutter.Color();
themeNode.get_color('-arrow-border-color', false, borderColor);
let backgroundColor = new Clutter.Color();
themeNode.get_color('-arrow-background-color', false, backgroundColor);
let [width, height] = area.get_surface_size();
let [boxWidth, boxHeight] = [width, height];
if (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM) {
boxHeight -= rise;
} else {
boxWidth -= rise;
}
let cr = area.get_context();
Clutter.cairo_set_source_color(cr, borderColor);
if (this._arrowSide == St.Side.TOP) {
cr.translate(0, rise);
}
cr.moveTo(borderRadius, halfBorder);
if (this._arrowSide == St.Side.TOP) {
cr.translate(0, -rise);
let halfBase = Math.floor(base/2);
cr.lineTo(this._arrowOrigin - halfBase, rise + halfBorder);
cr.lineTo(this._arrowOrigin, halfBorder);
cr.lineTo(this._arrowOrigin + halfBase, rise + halfBorder);
cr.translate(0, rise);
}
cr.lineTo(boxWidth - borderRadius, halfBorder);
cr.arc(boxWidth - borderRadius - halfBorder, borderRadius + halfBorder, borderRadius,
3*Math.PI/2, Math.PI*2);
cr.lineTo(boxWidth - halfBorder, boxHeight - borderRadius);
cr.arc(boxWidth - borderRadius - halfBorder, boxHeight - borderRadius - halfBorder, borderRadius,
0, Math.PI/2);
cr.lineTo(borderRadius, boxHeight - halfBorder);
cr.arc(borderRadius + halfBorder, boxHeight - borderRadius - halfBorder, borderRadius,
Math.PI/2, Math.PI);
cr.lineTo(halfBorder, borderRadius);
cr.arc(borderRadius + halfBorder, borderRadius + halfBorder, borderRadius,
Math.PI, 3*Math.PI/2);
Clutter.cairo_set_source_color(cr, backgroundColor);
cr.fillPreserve();
Clutter.cairo_set_source_color(cr, borderColor);
cr.setLineWidth(borderWidth);
cr.stroke();
},
// @origin: Coordinate specifying middle of the arrow, along
// the Y axis for St.Side.LEFT, St.Side.RIGHT from the top and X axis from
// the left for St.Side.TOP and St.Side.BOTTOM.
setArrowOrigin: function(origin) {
if (this._arrowOrigin != origin) {
this._arrowOrigin = origin;
this._border.queue_repaint();
}
}
};

View File

@ -24,27 +24,27 @@ Calendar.prototype = {
// GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
// should add a C function so we can do the full handling.
this._weekStart = NaN;
let weekStartString = Gettext_gtk20.gettext("calendar:week_start:0");
if (weekStartString.indexOf("calendar:week_start:") == 0) {
let weekStartString = Gettext_gtk20.gettext('calendar:week_start:0');
if (weekStartString.indexOf('calendar:week_start:') == 0) {
this._weekStart = parseInt(weekStartString.substring(20));
}
if (isNaN(this._weekStart) || this._weekStart < 0 || this._weekStart > 6) {
log("Translation of 'calendar:week_start:0' in GTK+ is not correct");
log('Translation of "calendar:week_start:0" in GTK+ is not correct');
this._weekStart = 0;
}
// Find the ordering for month/year in the calendar heading
switch (Gettext_gtk20.gettext("calendar:MY")) {
case "calendar:MY":
this._headerFormat = "%B %Y";
switch (Gettext_gtk20.gettext('calendar:MY')) {
case 'calendar:MY':
this._headerFormat = '%B %Y';
break;
case "calendar:YM":
this._headerFormat = "%Y %B";
case 'calendar:YM':
this._headerFormat = '%Y %B';
break;
default:
log("Translation of 'calendar:MY' in GTK+ is not correct");
this._headerFormat = "%B %Y";
log('Translation of "calendar:MY" in GTK+ is not correct');
this._headerFormat = '%B %Y';
break;
}
@ -52,7 +52,7 @@ Calendar.prototype = {
this.date = new Date();
this.actor = new St.Table({ homogeneous: false,
style_class: "calendar",
style_class: 'calendar',
reactive: true });
this.actor.connect('scroll-event',
@ -63,21 +63,21 @@ Calendar.prototype = {
this.actor.add(this._topBox,
{ row: 0, col: 0, col_span: 7 });
let [backlabel, forwardlabel] = ["&lt;", "&gt;"];
let [backlabel, forwardlabel] = ['&lt;', '&gt;'];
if (St.Widget.get_default_direction () == St.TextDirection.RTL) {
[backlabel, forwardlabel] = [forwardlabel, backlabel];
}
let back = new St.Button({ label: backlabel, style_class: 'calendar-change-month' });
this._topBox.add(back);
back.connect("clicked", Lang.bind(this, this._prevMonth));
back.connect('clicked', Lang.bind(this, this._prevMonth));
this._dateLabel = new St.Label();
this._topBox.add(this._dateLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
let forward = new St.Button({ label: forwardlabel, style_class: 'calendar-change-month' });
this._topBox.add(forward);
forward.connect("clicked", Lang.bind(this, this._nextMonth));
forward.connect('clicked', Lang.bind(this, this._nextMonth));
// We need to figure out the abbreviated localized names for the days of the week;
// we do this by just getting the next 7 days starting from right now and then putting
@ -86,7 +86,7 @@ Calendar.prototype = {
iter.setSeconds(0); // Leap second protection. Hah!
iter.setHours(12);
for (let i = 0; i < 7; i++) {
this.actor.add(new St.Label({ text: iter.toLocaleFormat("%a") }),
this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }),
{ row: 1,
col: (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.END });
@ -161,11 +161,11 @@ Calendar.prototype = {
while (true) {
let label = new St.Label({ text: iter.getDate().toString() });
if (_sameDay(now, iter))
label.style_class = "calendar-day calendar-today";
label.style_class = 'calendar-day calendar-today';
else if (iter.getMonth() != this.date.getMonth())
label.style_class = "calendar-day calendar-other-month-day";
label.style_class = 'calendar-day calendar-other-month-day';
else
label.style_class = "calendar-day";
label.style_class = 'calendar-day';
this.actor.add(label,
{ row: row, col: (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.END });

View File

@ -5,6 +5,7 @@ const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Main = imports.ui.main;
const Params = imports.misc.params;
@ -13,6 +14,19 @@ const Params = imports.misc.params;
// normal mode (ie, outside the Overview), that surrounds the main
// workspace content.
const Visibility = {
FULL: 1,
FULLSCREEN: 2,
OVERVIEW: 3
};
const defaultParams = {
visibleInOverview: false,
visibleInFullscreen: false,
affectsStruts: true,
affectsInputRegion: true
};
function Chrome() {
this._init();
}
@ -20,12 +34,13 @@ function Chrome() {
Chrome.prototype = {
_init: function() {
// 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.nonOverviewActor = new Clutter.Group();
this.actor.add_actor(this.nonOverviewActor);
this.actor = new Shell.GenericContainer({ width: 0, height: 0 });
Main.uiGroup.add_actor(this.actor);
this.actor.connect('allocate', Lang.bind(this, this._allocated));
this._obscuredByFullscreen = false;
this._inFullscreen = false;
this._inOverview = false;
this.visibility = Visibility.FULL;
this._trackedActors = [];
@ -44,6 +59,12 @@ Chrome.prototype = {
this._queueUpdateRegions();
},
_allocated: function(actor, box, flags) {
let children = this.actor.get_children();
for (let i = 0; i < children.length; i++)
children[i].allocate_preferred_size(flags);
},
_verifyAncestry: function(actor, ancestor) {
while (actor) {
if (actor == ancestor)
@ -67,19 +88,15 @@ Chrome.prototype = {
//
// If %visibleInOverview is %true in @params, @actor will remain
// visible when the overview is brought up. Otherwise it will
// automatically be hidden. If %affectsStruts or %affectsInputRegion
// is %false, the actor will not have the indicated effect.
// automatically be hidden. Likewise, if %visibleInFullscreen is
// %true, the actor will be visible even when a fullscreen window
// should be covering it.
//
// If %affectsStruts or %affectsInputRegion is %false, the actor
// will not have the indicated effect.
addActor: function(actor, params) {
params = Params.parse(params, { visibleInOverview: false,
affectsStruts: true,
affectsInputRegion: true });
if (params.visibleInOverview)
this.actor.add_actor(actor);
else
this.nonOverviewActor.add_actor(actor);
this._trackActor(actor, params.affectsInputRegion, params.affectsStruts);
this.actor.add_actor(actor);
this._trackActor(actor, params);
},
// trackActor:
@ -89,13 +106,32 @@ Chrome.prototype = {
// Tells the chrome to track @actor, which must be a descendant
// of an actor added via addActor(). This can be used to extend the
// struts or input region to cover specific children.
//
// @params can have any of the same values as in addActor(), though
// some possibilities don't make sense (eg, trying to have a
// %visibleInOverview child of a non-%visibleInOverview parent).
// By default, @actor has the same params as its chrome ancestor.
trackActor: function(actor, params) {
if (!this._verifyAncestry(actor, this.actor))
let ancestor = actor.get_parent();
let index = this._findActor(ancestor);
while (ancestor && index == -1) {
ancestor = ancestor.get_parent();
index = this._findActor(ancestor);
}
if (!ancestor)
throw new Error('actor is not a descendent of the chrome layer');
params = Params.parse(params, { affectsStruts: true,
affectsInputRegion: true });
this._trackActor(actor, params.affectsInputRegion, params.affectsStruts);
let ancestorData = this._trackedActors[index];
if (!params)
params = {};
// We can't use Params.parse here because we want to drop
// the extra values like ancestorData.actor
for (let prop in defaultParams) {
if (!params[prop])
params[prop] = ancestorData[prop];
}
this._trackActor(actor, params);
},
// untrackActor:
@ -111,10 +147,7 @@ Chrome.prototype = {
//
// Removes @actor from the chrome layer
removeActor: function(actor) {
if (actor.get_parent() == this.nonOverviewActor)
this.nonOverviewActor.remove_actor(actor);
else
this.actor.remove_actor(actor);
this.actor.remove_actor(actor);
this._untrackActor(actor);
},
@ -127,16 +160,12 @@ Chrome.prototype = {
return -1;
},
_trackActor: function(actor, inputRegion, strut) {
let actorData;
_trackActor: function(actor, params) {
if (this._findActor(actor) != -1)
throw new Error('trying to re-track existing chrome actor');
actorData = { actor: actor,
inputRegion: inputRegion,
strut: strut };
let actorData = Params.parse(params, defaultParams);
actorData.actor = actor;
actorData.visibleId = actor.connect('notify::visible',
Lang.bind(this, this._queueUpdateRegions));
actorData.allocationId = actor.connect('notify::allocation',
@ -170,16 +199,40 @@ Chrome.prototype = {
this._untrackActor(actor);
},
_updateVisibility: function() {
for (let i = 0; i < this._trackedActors.length; i++) {
let actorData = this._trackedActors[i];
if (this._inOverview && !actorData.visibleInOverview)
this.actor.set_skip_paint(actorData.actor, true);
else if (this._inFullscreen && !actorData.visibleInFullscreen)
this.actor.set_skip_paint(actorData.actor, true);
else
this.actor.set_skip_paint(actorData.actor, false);
}
let newVisibility;
if (this._inOverview)
newVisibility = Visibility.OVERVIEW;
else if (this._inFullscreen)
newVisibility = Visibility.FULLSCREEN;
else
newVisibility = Visibility.FULL;
if (newVisibility != this.visibility) {
this.visibility = newVisibility;
this.emit('visibility-changed', this.visibility);
}
},
_overviewShowing: function() {
this.actor.show();
this.nonOverviewActor.hide();
this._inOverview = true;
this._updateVisibility();
this._queueUpdateRegions();
},
_overviewHidden: function() {
if (this._obscuredByFullscreen)
this.actor.hide();
this.nonOverviewActor.show();
this._inOverview = false;
this._updateVisibility();
this._queueUpdateRegions();
},
@ -196,7 +249,7 @@ Chrome.prototype = {
// The chrome layer should be visible unless there is a window
// with layer FULLSCREEN, or a window with layer
// OVERRIDE_REDIRECT that covers the whole screen.
// ("override_redirect" is not actually a layer above all
// ('override_redirect' is not actually a layer above all
// other windows, but this seems to be how mutter treats it
// currently...) If we wanted to be extra clever, we could
// figure out when an OVERRIDE_REDIRECT window was trying to
@ -205,13 +258,23 @@ Chrome.prototype = {
// @windows is sorted bottom to top.
this._obscuredByFullscreen = false;
let wasInFullscreen = this._inFullscreen;
this._inFullscreen = false;
for (let i = windows.length - 1; i > -1; i--) {
let layer = windows[i].get_meta_window().get_layer();
// There are 3 cases we check here for:
// 1.) Monitor sized window
// 2.) Window with a position somewhere on the primary screen having the _NET_WM_FULLSCREEN flag set
// 3.) Window that is partly off screen (tries to hide its decorations) which might have negative coords
// We check for 1.) and 2.) by checking if the upper right corner is on the primary monitor, but avoid the case
// where it overlaps with the secondary screen (like window.x + window.width == primary.x + primary.width)
// For 3.) we just ignore negative values as they don't really make sense
if (layer == Meta.StackLayer.FULLSCREEN) {
if (windows[i].x >= primary.x && windows[i].x <= primary.x + primary.width &&
windows[i].y >= primary.y && windows[i].y <= primary.y + primary.height) {
this._obscuredByFullscreen = true;
if (Math.max(windows[i].x, 0) >= primary.x && Math.max(windows[i].x, 0) < primary.x + primary.width &&
Math.max(windows[i].y, 0) >= primary.y && Math.max(windows[i].y, 0) < primary.y + primary.height) {
this._inFullscreen = true;
break;
}
}
@ -220,16 +283,15 @@ Chrome.prototype = {
windows[i].x + windows[i].width >= primary.x + primary.width &&
windows[i].y <= primary.y &&
windows[i].y + windows[i].height >= primary.y + primary.height) {
this._obscuredByFullscreen = true;
this._inFullscreen = true;
break;
}
} else
break;
}
let shouldBeVisible = !this._obscuredByFullscreen || Main.overview.visible;
if (this.actor.visible != shouldBeVisible) {
this.actor.visible = shouldBeVisible;
if (this._inFullscreen != wasInFullscreen) {
this._updateVisibility();
this._queueUpdateRegions();
}
},
@ -241,7 +303,7 @@ Chrome.prototype = {
for (i = 0; i < this._trackedActors.length; i++) {
let actorData = this._trackedActors[i];
if (!actorData.inputRegion && !actorData.strut)
if (!actorData.affectsInputRegion && !actorData.affectsStruts)
continue;
let [x, y] = actorData.actor.get_transformed_position();
@ -252,10 +314,12 @@ Chrome.prototype = {
h = Math.round(h);
let rect = new Meta.Rectangle({ x: x, y: y, width: w, height: h});
if (actorData.inputRegion && actorData.actor.get_paint_visibility())
if (actorData.affectsInputRegion &&
actorData.actor.get_paint_visibility() &&
!this.actor.get_skip_paint(actorData.actor))
rects.push(rect);
if (!actorData.strut)
if (!actorData.affectsStruts)
continue;
// Metacity wants to know what side of the screen the
@ -307,3 +371,4 @@ Chrome.prototype = {
return false;
}
};
Signals.addSignalMethods(Chrome.prototype);

View File

@ -1,6 +1,5 @@
/* -*- 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;
@ -23,10 +22,8 @@ const Search = imports.ui.search;
// 25 search results (per result type) should be enough for everyone
const MAX_RENDERED_SEARCH_RESULTS = 25;
const DEFAULT_PADDING = 4;
const DOCS = "docs";
const PLACES = "places";
const DOCS = 'docs';
const PLACES = 'places';
/*
* Returns the index in an array of a given length that is obtained
@ -57,7 +54,7 @@ Pane.prototype = {
_init: function () {
this._open = false;
this.actor = new St.BoxLayout({ style_class: "dash-pane",
this.actor = new St.BoxLayout({ style_class: 'dash-pane',
vertical: true,
reactive: true });
this.actor.connect('button-press-event', Lang.bind(this, function (a, e) {
@ -116,14 +113,12 @@ function ResultArea(displayType, flags) {
ResultArea.prototype = {
_init : function(displayType, flags) {
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.actor = new St.BoxLayout({ vertical: true });
this.resultsContainer = new St.BoxLayout({ style_class: 'dash-results-container' });
this.actor.add(this.resultsContainer, { expand: true });
this.display = _createDisplay(displayType, flags);
this.resultsContainer.append(this.display.actor, Big.BoxPackFlags.EXPAND);
this.resultsContainer.add(this.display.actor, { expand: true });
this.display.load();
}
};
@ -190,7 +185,7 @@ function SearchEntry() {
SearchEntry.prototype = {
_init : function() {
this.actor = new St.Entry({ name: "searchEntry",
this.actor = new St.Entry({ name: 'searchEntry',
hint_text: _("Find") });
this.entry = this.actor.clutter_text;
@ -198,7 +193,7 @@ SearchEntry.prototype = {
function() {
if (this.isActive())
this.actor.set_secondary_icon_from_file(global.imagedir +
"close-black.svg");
'close-black.svg');
else
this.actor.set_secondary_icon_from_file(null);
}));
@ -359,7 +354,10 @@ SearchResult.prototype = {
},
setSelected: function(selected) {
this._content.set_style_pseudo_class(selected ? 'selected' : null);
if (selected)
this._content.add_style_pseudo_class('selected');
else
this._content.remove_style_pseudo_class('selected');
},
activate: function() {
@ -532,7 +530,7 @@ SearchResults.prototype = {
let meta = this._metaForProvider(provider);
meta.actor.show();
meta.resultDisplay.renderResults(providerResults, terms);
meta.count.set_text(""+providerResults.length);
meta.count.set_text('' + providerResults.length);
}
this.selectDown(false);
@ -610,11 +608,11 @@ function MoreLink() {
MoreLink.prototype = {
_init : function () {
this.actor = new St.BoxLayout({ style_class: "more-link",
this.actor = new St.BoxLayout({ style_class: 'more-link',
reactive: true });
this.pane = null;
this._expander = new St.Bin({ style_class: "more-link-expander" });
this._expander = new St.Bin({ style_class: 'more-link-expander' });
this.actor.add(this._expander, { expand: true, y_fill: false });
},
@ -630,10 +628,10 @@ MoreLink.prototype = {
setPane: function (pane) {
this._pane = pane;
this._pane.connect('open-state-changed', Lang.bind(this, function(pane, isOpen) {
if (!isOpen)
this._expander.style_class = 'more-link-expander';
if (isOpen)
this._expander.add_style_class_name('open');
else
this._expander.style_class = 'more-link-expander open';
this._expander.remove_style_class_name('open');
}));
}
};
@ -646,9 +644,9 @@ function BackLink() {
BackLink.prototype = {
_init : function () {
this.actor = new St.Button({ style_class: "section-header-back",
this.actor = new St.Button({ style_class: 'section-header-back',
reactive: true });
this.actor.set_child(new St.Bin({ style_class: "section-header-back-image" }));
this.actor.set_child(new St.Bin({ style_class: 'section-header-back-image' }));
}
};
@ -658,12 +656,12 @@ function SectionHeader(title, suppressBrowse) {
SectionHeader.prototype = {
_init : function (title, suppressBrowse) {
this.actor = new St.Bin({ style_class: "section-header",
this.actor = new St.Bin({ style_class: 'section-header',
x_align: St.Align.START,
x_fill: true,
y_fill: true,
reactive: !suppressBrowse });
this._innerBox = new St.BoxLayout({ style_class: "section-header-inner" });
this._innerBox = new St.BoxLayout({ style_class: 'section-header-inner' });
this.actor.set_child(this._innerBox);
this.backLink = new BackLink();
@ -673,12 +671,12 @@ SectionHeader.prototype = {
this.emit('back-link-activated');
}));
let textBox = new St.BoxLayout({ style_class: "section-text-content" });
this.text = new St.Label({ style_class: "section-title",
let textBox = new St.BoxLayout({ style_class: 'section-text-content' });
this.text = new St.Label({ style_class: 'section-title',
text: title });
textBox.add(this.text, { x_align: St.Align.START });
this.countText = new St.Label({ style_class: "section-count" });
this.countText = new St.Label({ style_class: 'section-count' });
textBox.add(this.countText, { expand: true, x_fill: false, x_align: St.Align.END });
this.countText.hide();
@ -714,7 +712,7 @@ SectionHeader.prototype = {
},
setCountText : function(countText) {
if (countText == "") {
if (countText == '') {
this.countText.hide();
} else {
this.countText.show();
@ -731,14 +729,14 @@ function SearchSectionHeader(title, onClick) {
SearchSectionHeader.prototype = {
_init : function(title, onClick) {
this.actor = new St.Button({ style_class: "dash-search-section-header",
this.actor = new St.Button({ style_class: 'dash-search-section-header',
x_fill: true,
y_fill: true });
let box = new St.BoxLayout();
this.actor.set_child(box);
let titleText = new St.Label({ style_class: "dash-search-section-title",
let titleText = new St.Label({ style_class: 'dash-search-section-title',
text: title });
this.countText = new St.Label({ style_class: "dash-search-section-count" });
this.countText = new St.Label({ style_class: 'dash-search-section-count' });
box.add(titleText);
box.add(this.countText, { expand: true, x_fill: false, x_align: St.Align.END });
@ -778,14 +776,14 @@ Dash.prototype = {
// 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 St.BoxLayout({ name: "dash",
this.actor = new St.BoxLayout({ name: 'dash',
vertical: true,
reactive: true });
// The searchArea just holds the entry
this.searchArea = new St.BoxLayout({ name: "dashSearchArea",
this.searchArea = new St.BoxLayout({ name: 'dashSearchArea',
vertical: true });
this.sectionArea = new St.BoxLayout({ name: "dashSections",
this.sectionArea = new St.BoxLayout({ name: 'dashSections',
vertical: true });
this.actor.add(this.searchArea);

View File

@ -1,10 +1,12 @@
/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk;
const St = imports.gi.St;
const Lang = imports.lang;
const Signals = imports.signals;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
const Params = imports.misc.params;
@ -21,7 +23,7 @@ function _getEventHandlerActor() {
eventHandlerActor = new Clutter.Rectangle();
eventHandlerActor.width = 0;
eventHandlerActor.height = 0;
global.stage.add_actor(eventHandlerActor);
Main.uiGroup.add_actor(eventHandlerActor);
// We connect to 'event' rather than 'captured-event' because the capturing phase doesn't happen
// when you've grabbed the pointer.
eventHandlerActor.connect('event',
@ -61,13 +63,20 @@ _Draggable.prototype = {
},
_onButtonPress : function (actor, event) {
// FIXME: we should make sure it's button 1, but we can't currently
// check that from JavaScript
if (event.get_button() != 1)
return false;
if (Tweener.getTweenCount(actor))
return false;
this._buttonDown = true;
this._grabActor();
// special case St.Clickable: grabbing the pointer would mess up the
// internal state, so we start the drag manually on hover change
if (this.actor instanceof St.Clickable)
this.actor.connect('notify::hover',
Lang.bind(this, this._onClickableHoverChanged));
else
this._grabActor();
let [stageX, stageY] = event.get_coords();
this._dragStartX = stageX;
@ -76,6 +85,15 @@ _Draggable.prototype = {
return false;
},
_onClickableHoverChanged: function(button) {
if (button.hover || !button.held)
return;
button.fake_release();
this.startDrag(this._dragStartX, this._dragStartY,
global.get_current_time());
},
_grabActor: function() {
Clutter.grab_pointer(this.actor);
this._onEventId = this.actor.connect('event',
@ -236,7 +254,7 @@ _Draggable.prototype = {
{ scale_x: scale * origScale,
scale_y: scale * origScale,
time: SCALE_ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onUpdate: function() {
let currentScale = this._dragActor.scale_x / origScale;
this._dragOffsetX = currentScale * origDragOffsetX;
@ -350,7 +368,7 @@ _Draggable.prototype = {
scale_y: this._snapBackScale,
opacity: this._dragOrigOpacity,
time: SNAP_BACK_ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: this._onSnapBackComplete,
onCompleteScope: this,
onCompleteParams: [this._dragActor, eventTime]

View File

@ -1,6 +1,5 @@
/* -*- 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;
@ -42,7 +41,7 @@ DocDisplayItem.prototype = {
GenericDisplay.GenericDisplayItem.prototype._init.call(this);
this._docInfo = docInfo;
this._setItemInfo(docInfo.name, "");
this._setItemInfo(docInfo.name, '');
this._timeoutTime = -1;
this._resetTimeDisplay(currentSecs);
@ -81,7 +80,7 @@ DocDisplayItem.prototype = {
// Creates and returns a large preview icon, but only if this._docInfo is an image file
// and we were able to generate a pixbuf from it successfully.
_createLargePreviewIcon : function() {
if (this._docInfo.mimeType == null || this._docInfo.mimeType.indexOf("image/") != 0)
if (this._docInfo.mimeType == null || this._docInfo.mimeType.indexOf('image/') != 0)
return null;
try {
@ -267,24 +266,26 @@ function DashDocDisplayItem(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 () {
this._icon = docInfo.createIcon(DASH_DOCS_ICON_SIZE);
this.actor = new St.Clickable({ style_class: 'recent-docs-item',
reactive: true,
x_align: St.Align.START });
let box = new St.BoxLayout({ style_class: 'recent-docs-item-box' });
this.actor.set_child(box);
box.add(this._icon);
let text = new St.Label({ text: docInfo.name });
box.add(text);
this.actor.connect('clicked', Lang.bind(this, function () {
docInfo.launch();
Main.overview.hide();
}));
this.actor._delegate = this;
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 St.Label({ style_class: 'dash-recent-docs-item',
text: docInfo.name });
this.actor.append(name, Big.BoxPackFlags.EXPAND);
let draggable = DND.makeDraggable(this.actor);
},
@ -512,6 +513,6 @@ DocSearchProvider.prototype = {
},
expandSearch: function(terms) {
log("TODO expand docs search");
log('TODO expand docs search');
}
};

View File

@ -1,5 +1,6 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext_gtk20 = imports.gettext.domain('gtk20');
@ -28,15 +29,57 @@ function _patchContainerClass(containerClass) {
};
}
_patchContainerClass(St.BoxLayout);
_patchContainerClass(St.Table);
// Replace @method with something that throws an error instead
function _blockMethod(method, replacement, reason) {
let match = method.match(/^(.+)\.([^.]+)$/);
if (!match)
throw new Error('Bad method name "' + method + '"');
let proto = 'imports.gi.' + match[1] + '.prototype';
let property = match[2];
if (!global.set_property_mutable(proto, property, true))
throw new Error('Bad method name "' + method + '"');
// eval() is evil in general, but we know it's safe here since
// set_property_mutable() would have failed if proto was
// malformed.
let node = eval(proto);
let msg = 'Do not use "' + method + '".';
if (replacement)
msg += ' Use "' + replacement + '" instead.';
if (reason)
msg += ' (' + reason + ')';
node[property] = function() {
throw new Error(msg);
};
global.set_property_mutable(proto, property, false);
}
function init() {
Tweener.init();
String.prototype.format = Format.format;
// Set the default direction for St widgets (this needs to be done before any use of St)
if (Gettext_gtk20.gettext("default:LTR") == "default:RTL") {
if (Gettext_gtk20.gettext('default:LTR') == 'default:RTL') {
St.Widget.set_default_direction(St.TextDirection.RTL);
}
_patchContainerClass(St.BoxLayout);
_patchContainerClass(St.Table);
_blockMethod('Clutter.Event.get_state', 'Shell.get_event_state',
'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.');
_blockMethod('Gdk.Display.get_pointer', 'global.get_pointer',
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
_blockMethod('Gdk.Window.get_pointer', 'global.get_pointer',
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
// Now close the back door to prevent extensions from trying to
// abuse it. We can't actually delete it since
// Shell.Global.prototype itself is read-only.
global.set_property_mutable('imports.gi.Shell.Global.prototype', 'set_property_mutable', true);
Shell.Global.prototype.set_property_mutable = undefined;
}

View File

@ -119,13 +119,12 @@ function loadExtension(dir, enabled, type) {
}
function init() {
let userConfigPath = GLib.get_user_config_dir();
let userExtensionsPath = GLib.build_filenamev([userConfigPath, 'gnome-shell', 'extensions']);
let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']);
userExtensionsDir = Gio.file_new_for_path(userExtensionsPath);
try {
userExtensionsDir.make_directory_with_parents(null);
} catch (e) {
global.logError(""+e);
global.logError('' + e);
}
disabledExtensions = Shell.GConf.get_default().get_string_list('disabled_extensions');

View File

@ -1,6 +1,5 @@
/* -*- 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 Gdk = imports.gi.Gdk;
@ -21,25 +20,9 @@ const RedisplayFlags = { NONE: 0,
SUBSEARCH: 1 << 2,
IMMEDIATE: 1 << 3 };
const ITEM_DISPLAY_DESCRIPTION_COLOR = new Clutter.Color();
ITEM_DISPLAY_DESCRIPTION_COLOR.from_pixel(0xffffffbb);
const DISPLAY_CONTROL_SELECTED_COLOR = new Clutter.Color();
DISPLAY_CONTROL_SELECTED_COLOR.from_pixel(0x112288ff);
const PREVIEW_BOX_BACKGROUND_COLOR = new Clutter.Color();
PREVIEW_BOX_BACKGROUND_COLOR.from_pixel(0xADADADf0);
const DEFAULT_PADDING = 4;
// Used by subclasses
const ITEM_DISPLAY_ICON_SIZE = 48;
const DEFAULT_COLUMN_GAP = 6;
const PREVIEW_ICON_SIZE = 96;
const PREVIEW_BOX_PADDING = 6;
const PREVIEW_BOX_SPACING = DEFAULT_PADDING;
const PREVIEW_BOX_CORNER_RADIUS = 10;
// how far relative to the full item width the preview box should be placed
const PREVIEW_PLACING = 3/4;
const PREVIEW_DETAILS_MIN_WIDTH = PREVIEW_ICON_SIZE * 2;
/* This is a virtual class that represents a single display item containing
* a name, a description, and an icon. It allows selecting an item and represents
@ -51,7 +34,7 @@ function GenericDisplayItem() {
GenericDisplayItem.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ style_class: "generic-display-item",
this.actor = new St.BoxLayout({ style_class: 'generic-display-item',
reactive: true });
this.actor._delegate = this;
@ -105,7 +88,10 @@ GenericDisplayItem.prototype = {
// Highlights the item by setting a different background color than the default
// if isSelected is true, removes the highlighting otherwise.
markSelected: function(isSelected) {
this.actor.set_style_pseudo_class(isSelected ? "selected" : null);
if (isSelected)
this.actor.add_style_pseudo_class('selected');
else
this.actor.remove_style_pseudo_class('selected');
},
/*
@ -114,11 +100,10 @@ GenericDisplayItem.prototype = {
*/
createDetailsActor: function() {
let details = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: PREVIEW_BOX_SPACING });
let details = new St.BoxLayout({ style_class: 'generic-display-container',
vertical: true });
let mainDetails = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: PREVIEW_BOX_SPACING });
let mainDetails = new St.BoxLayout({ style_class: 'generic-display-container' });
// Inner box with name and description
let textDetails = new St.BoxLayout({ style_class: 'generic-display-details',
@ -132,21 +117,19 @@ GenericDisplayItem.prototype = {
this._detailsDescriptions.push(detailsDescription);
mainDetails.append(textDetails, Big.BoxPackFlags.EXPAND);
mainDetails.add(textDetails, { expand: true });
let previewIcon = this._createPreviewIcon();
let largePreviewIcon = this._createLargePreviewIcon();
if (previewIcon != null && largePreviewIcon == null) {
mainDetails.prepend(previewIcon, Big.BoxPackFlags.NONE);
mainDetails.insert_actor(previewIcon, 0);
}
details.append(mainDetails, Big.BoxPackFlags.NONE);
details.add(mainDetails);
if (largePreviewIcon != null) {
let largePreview = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
largePreview.append(largePreviewIcon, Big.BoxPackFlags.NONE);
details.append(largePreview, Big.BoxPackFlags.NONE);
details.add(largePreviewIcon);
}
return details;
@ -161,7 +144,7 @@ GenericDisplayItem.prototype = {
// Performes an action associated with launching this item, such as opening a file or an application.
launch: function() {
throw new Error("Not implemented");
throw new Error('Not implemented');
},
//// Protected methods ////
@ -193,12 +176,12 @@ GenericDisplayItem.prototype = {
this._icon = this._createIcon();
this._iconBin.set_child(this._icon);
this._name = new St.Label({ style_class: "generic-display-item-name",
this._name = new St.Label({ style_class: 'generic-display-item-name',
text: nameText });
this._infoText.add(this._name);
this._description = new St.Label({ style_class: "generic-display-item-description",
text: descriptionText ? descriptionText : "" });
this._description = new St.Label({ style_class: 'generic-display-item-description',
text: descriptionText ? descriptionText : '' });
this._infoText.add(this._description);
},
@ -225,12 +208,12 @@ GenericDisplayItem.prototype = {
// Returns an icon for the item.
_createIcon: function() {
throw new Error("Not implemented");
throw new Error('Not implemented');
},
// Returns a preview icon for the item.
_createPreviewIcon: function() {
throw new Error("Not implemented");
throw new Error('Not implemented');
}
//// Private methods ////
@ -373,7 +356,7 @@ GenericDisplay.prototype = {
// TODO: figure out why this._list.displayedCount is returning a
// positive number when this._mathedItems.length is 0
// This can be triggered if a search string is entered for which there are no matches.
// log("this._mathedItems.length: " + this._matchedItems.length + " this._list.displayedCount " + this._list.displayedCount);
// log('this._mathedItems.length: ' + this._matchedItems.length + ' this._list.displayedCount ' + this._list.displayedCount);
return this._matchedItemKeys.length > 0;
},
@ -419,7 +402,7 @@ GenericDisplay.prototype = {
// and adds it to the list of displayed items, but does not yet display it.
_addDisplayItem : function(itemId) {
if (this._displayedItems.hasOwnProperty(itemId)) {
log("Tried adding a display item for " + itemId + ", but an item with this item id is already among displayed items.");
log('Tried adding a display item for ' + itemId + ', but an item with this item id is already among displayed items.');
return;
}
@ -478,7 +461,7 @@ GenericDisplay.prototype = {
// Return true if there's an active search or other constraint
// on the list
_filterActive: function() {
return this._search != "";
return this._search != '';
},
// Called when we are resetting state
@ -601,13 +584,13 @@ GenericDisplay.prototype = {
// Implementation should return %true if we are up to date, and %false
// if a full reload occurred.
_refreshCache: function() {
throw new Error("Not implemented");
throw new Error('Not implemented');
},
// Sets the list of the displayed items based on the default sorting order.
// The default sorting order is specific to each implementing class.
_setDefaultList: function() {
throw new Error("Not implemented");
throw new Error('Not implemented');
},
// Compares items associated with the item ids based on the order in which the
@ -615,18 +598,18 @@ GenericDisplay.prototype = {
// Intended to be used as a compareFunction for array.sort().
// Returns an integer value indicating the result of the comparison.
_compareItems: function(itemIdA, itemIdB) {
throw new Error("Not implemented");
throw new Error('Not implemented');
},
// Checks if the item info can be a match for the search string.
// Returns a boolean flag indicating if that's the case.
_isInfoMatching: function(itemInfo, search) {
throw new Error("Not implemented");
throw new Error('Not implemented');
},
// Creates a display item based on itemInfo.
_createDisplayItem: function(itemInfo) {
throw new Error("Not implemented");
throw new Error('Not implemented');
},
//// Private methods ////

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
/**
@ -60,8 +61,13 @@ Lightbox.prototype = {
},
_allocationChanged : function(container, box, flags) {
this.actor.width = this._container.width;
this.actor.height = this._container.height;
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
this.actor.width = this.width;
this.actor.height = this.height;
return false;
}));
this.width = this._container.width;
this.height = this._container.height;
},
_actorAdded : function(container, newChild) {

View File

@ -12,6 +12,7 @@ function Link(props) {
Link.prototype = {
_init : function(props) {
let realProps = { reactive: true,
track_hover: true,
style_class: 'shell-link' };
// The user can pass in reactive: false to override the above and get
// a non-reactive link (a link to the current page, perhaps)

View File

@ -1,7 +1,7 @@
/* -*- 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 Gio = imports.gi.Gio;
const Pango = imports.gi.Pango;
const St = imports.gi.St;
@ -18,22 +18,22 @@ const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
/* 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; " +
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; }; " +
'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); ";
'const it = Main.lookingGlass.getIt(); ' +
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
function Notebook() {
this._init();
@ -43,14 +43,16 @@ Notebook.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ vertical: true });
this.tabControls = new St.BoxLayout({ style_class: "labels" });
this.tabControls = new St.BoxLayout({ style_class: 'labels' });
this._selectedIndex = -1;
this._tabs = [];
},
appendPage: function(name, child) {
let labelBox = new St.BoxLayout({ style_class: "notebook-tab" });
let labelBox = new St.BoxLayout({ style_class: 'notebook-tab',
reactive: true,
track_hover: true });
let label = new St.Button({ label: name });
label.connect('clicked', Lang.bind(this, function () {
this.selectChild(child);
@ -84,7 +86,7 @@ Notebook.prototype = {
if (this._selectedIndex < 0)
return;
let tabData = this._tabs[this._selectedIndex];
tabData.labelBox.set_style_pseudo_class(null);
tabData.labelBox.remove_style_pseudo_class('selected');
tabData.scrollView.hide();
this._selectedIndex = -1;
},
@ -98,7 +100,7 @@ Notebook.prototype = {
return;
}
let tabData = this._tabs[index];
tabData.labelBox.set_style_pseudo_class('selected');
tabData.labelBox.add_style_pseudo_class('selected');
tabData.scrollView.show();
this._selectedIndex = index;
this.emit('selection', tabData.child);
@ -139,6 +141,40 @@ Notebook.prototype = {
};
Signals.addSignalMethods(Notebook.prototype);
function objectToString(o) {
if (typeof(o) == typeof(objectToString)) {
// special case this since the default is way, way too verbose
return "<js function>";
} else {
return "" + o;
}
}
function ObjLink(o, title) {
this._init(o, title);
}
ObjLink.prototype = {
__proto__: Link.Link,
_init: function(o, title) {
let text;
if (title)
text = title;
else
text = objectToString(o);
text = GLib.markup_escape_text(text, -1);
this._obj = o;
Link.Link.prototype._init.call(this, { label: text });
this.actor.get_child().single_line_mode = true;
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
},
_onClicked: function (link) {
Main.lookingGlass.inspectObject(this._obj, this.actor);
}
};
function Result(command, o, index) {
this._init(command, o, index);
}
@ -148,108 +184,175 @@ Result.prototype = {
this.index = index;
this.o = o;
this.actor = new Big.Box();
this.actor = new St.BoxLayout({ vertical: true });
let cmdTxt = new St.Label({ text: command });
cmdTxt.ellipsize = Pango.EllipsizeMode.END;
this.actor.append(cmdTxt, Big.BoxPackFlags.NONE);
let resultTxt = new St.Label({ text: "r(" + index + ") = " + o });
resultTxt.ellipsize = Pango.EllipsizeMode.END;
this.actor.append(resultTxt, Big.BoxPackFlags.NONE);
let line = new Clutter.Rectangle({ name: "Separator",
height: 1 });
let padBin = new St.Bin({ name: "Separator", x_fill: true, y_fill: true });
cmdTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
this.actor.add(cmdTxt);
let box = new St.BoxLayout({});
this.actor.add(box);
let resultTxt = new St.Label({ text: 'r(' + index + ') = ' });
resultTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
box.add(resultTxt);
let objLink = new ObjLink(o);
box.add(objLink.actor);
let line = new Clutter.Rectangle({ name: 'Separator' });
let padBin = new St.Bin({ name: 'Separator', x_fill: true, y_fill: true });
padBin.add_actor(line);
this.actor.append(padBin, Big.BoxPackFlags.NONE);
this.actor.add(padBin);
}
};
function ActorHierarchy() {
function WindowList() {
this._init();
}
ActorHierarchy.prototype = {
WindowList.prototype = {
_init : function () {
this._previousTarget = null;
this._target = null;
this._parentList = [];
this.actor = new St.BoxLayout({ name: "ActorHierarchy", vertical: true });
this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
let display = global.screen.get_display();
let tracker = Shell.WindowTracker.get_default();
this._updateId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._updateWindowList));
display.connect('window-created', Lang.bind(this, this._updateWindowList));
tracker.connect('tracked-windows-changed', Lang.bind(this, this._updateWindowList));
},
setTarget: function(actor) {
this._previousTarget = this._target;
this.target = actor;
this.actor.get_children().forEach(function (child) { child.destroy(); });
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 St.Label({ reactive: true,
text: "" + parent });
this.actor.add_actor(link);
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 St.BoxLayout({ name: "PropertyInspector", vertical: true });
},
setTarget: function(actor) {
this.target = actor;
this.actor.get_children().forEach(function (child) { child.destroy(); });
for (let propName in actor) {
let valueStr;
try {
valueStr = "" + actor[propName];
} catch (e) {
valueStr = '<error>';
_updateWindowList: function() {
this.actor.get_children().forEach(function (actor) { actor.destroy(); });
let windows = global.get_windows();
let tracker = Shell.WindowTracker.get_default();
for (let i = 0; i < windows.length; i++) {
let metaWindow = windows[i].metaWindow;
metaWindow.connect('unmanaged', Lang.bind(this, this._updateWindowList));
let box = new St.BoxLayout({ vertical: true });
this.actor.add(box);
let windowLink = new ObjLink(metaWindow, metaWindow.title);
box.add(windowLink.actor, { x_align: St.Align.START, x_fill: false });
let propsBox = new St.BoxLayout({ vertical: true, style: 'padding-left: 6px;' });
box.add(propsBox);
propsBox.add(new St.Label({ text: 'wmclass: ' + metaWindow.get_wm_class() }));
let app = tracker.get_window_app(metaWindow);
if (app != null && !app.is_transient()) {
let icon = app.create_icon_texture(22);
let propBox = new St.BoxLayout({ style: 'spacing: 6px; ' });
propsBox.add(propBox);
propBox.add(new St.Label({ text: 'app: ' }), { y_fill: false });
let appLink = new ObjLink(app, app.get_id());
propBox.add(appLink.actor, { y_fill: false });
propBox.add(icon, { y_fill: false });
} else {
propsBox.add(new St.Label({ text: '<untracked>' }));
}
let propText = propName + ": " + valueStr;
let propDisplay = new St.Label({ reactive: true,
text: propText });
this.actor.add_actor(propDisplay);
}
}
};
Signals.addSignalMethods(WindowList.prototype);
function ObjInspector() {
this._init();
}
ObjInspector.prototype = {
_init : function () {
this._obj = null;
this._previousObj = null;
this._parentList = [];
this.actor = new St.ScrollView({ x_fill: true, y_fill: true });
this.actor.get_hscroll_bar().hide();
this._container = new St.BoxLayout({ name: 'LookingGlassPropertyInspector',
style_class: 'lg-dialog',
vertical: true });
this.actor.add_actor(this._container);
},
selectObject: function(obj, skipPrevious) {
if (!skipPrevious)
this._previousObj = this._obj;
else
this._previousObj = null;
this._obj = obj;
this._container.get_children().forEach(function (child) { child.destroy(); });
let hbox = new St.BoxLayout({ style_class: 'lg-obj-inspector-title' });
this._container.add_actor(hbox);
let label = new St.Label({ text: 'Inspecting: %s: %s'.format(typeof(obj),
objectToString(obj)) });
label.single_line_mode = true;
hbox.add(label, { expand: true, y_fill: false });
let button = new St.Button({ label: 'Insert', style_class: 'lg-obj-inspector-button' });
button.connect('clicked', Lang.bind(this, this._onInsert));
hbox.add(button);
if (this._previousObj != null) {
button = new St.Button({ label: 'Back', style_class: 'lg-obj-inspector-button' });
button.connect('clicked', Lang.bind(this, this._onBack));
hbox.add(button);
}
button = new St.Button({ style_class: 'window-close' });
button.connect('clicked', Lang.bind(this, this.close));
hbox.add(button);
if (typeof(obj) == typeof({})) {
for (let propName in obj) {
let valueStr;
let link;
try {
let prop = obj[propName];
link = new ObjLink(prop).actor;
} catch (e) {
link = new St.Label({ text: '<error>' });
}
let hbox = new St.BoxLayout();
let propText = propName + ": " + valueStr;
hbox.add(new St.Label({ text: propName + ': ' }));
hbox.add(link);
this._container.add_actor(hbox);
}
}
},
open: function(sourceActor) {
if (this._open)
return;
this._previousObj = null;
this._open = true;
this.actor.show();
if (sourceActor) {
this.actor.set_scale(0, 0);
let [sourceX, sourceY] = sourceActor.get_transformed_position();
let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
this.actor.move_anchor_point(Math.floor(sourceX + sourceWidth / 2),
Math.floor(sourceY + sourceHeight / 2));
Tweener.addTween(this.actor, { scale_x: 1, scale_y: 1,
transition: "easeOutQuad",
time: 0.2 });
} else {
this.actor.set_scale(1, 1);
}
},
close: function() {
if (!this._open)
return;
this._open = false;
this.actor.hide();
this._previousObj = null;
this._obj = null;
},
_onInsert: function() {
let obj = this._obj;
this.close();
Main.lookingGlass.insertObject(obj);
},
_onBack: function() {
this.selectObject(this._previousObj, true);
}
};
function Inspector() {
this._init();
@ -259,14 +362,14 @@ Inspector.prototype = {
_init: function() {
let width = 150;
let primary = global.get_primary_monitor();
let eventHandler = new St.BoxLayout({ name: "LookingGlassDialog",
let eventHandler = new St.BoxLayout({ name: 'LookingGlassDialog',
vertical: false,
y: primary.y + Math.floor(primary.height / 2),
reactive: true });
eventHandler.connect('notify::allocation', Lang.bind(this, function () {
eventHandler.x = primary.x + Math.floor((primary.width - eventHandler.width) / 2);
}));
global.stage.add_actor(eventHandler);
Main.uiGroup.add_actor(eventHandler);
let displayText = new St.Label();
eventHandler.add(displayText, { expand: true });
@ -345,7 +448,7 @@ ErrorLog.prototype = {
let stack = Main._getAndClearErrorStack();
for (let i = 0; i < stack.length; i++) {
let logItem = stack[i];
text += logItem.category + " t=" + this._formatTime(new Date(logItem.timestamp)) + " " + logItem.message + "\n";
text += logItem.category + ' t=' + this._formatTime(new Date(logItem.timestamp)) + ' ' + logItem.message + '\n';
}
this.text.text = text;
}
@ -405,7 +508,7 @@ Extensions.prototype = {
case ExtensionSystem.ExtensionState.OUT_OF_DATE:
return _("Out of date");
}
return "Unknown"; // Not translated, shouldn't appear
return 'Unknown'; // Not translated, shouldn't appear
},
_createExtensionDisplay: function(meta) {
@ -451,7 +554,7 @@ function LookingGlass() {
LookingGlass.prototype = {
_init : function() {
this._idleHistorySaveId = 0;
let historyPath = global.configdir + "/lookingglass-history.txt";
let historyPath = global.userdatadir + '/lookingglass-history.txt';
this._historyFile = Gio.file_new_for_path(historyPath);
this._savedText = null;
this._historyNavIndex = -1;
@ -470,19 +573,24 @@ LookingGlass.prototype = {
// Sort of magic, but...eh.
this._maxItems = 150;
this.actor = new St.BoxLayout({ name: "LookingGlassDialog",
this.actor = new St.BoxLayout({ name: 'LookingGlassDialog',
style_class: 'lg-dialog',
vertical: true,
visible: false });
let gconf = Shell.GConf.get_default();
gconf.watch_directory("/desktop/gnome/interface");
gconf.connect("changed::/desktop/gnome/interface/monospace_font_name",
gconf.watch_directory('/desktop/gnome/interface');
gconf.connect('changed::/desktop/gnome/interface/monospace_font_name',
Lang.bind(this, this._updateFont));
this._updateFont();
global.stage.add_actor(this.actor);
Main.uiGroup.add_actor(this.actor);
let toolbar = new St.BoxLayout({ name: "Toolbar" });
this._objInspector = new ObjInspector();
Main.uiGroup.add_actor(this._objInspector.actor);
this._objInspector.actor.hide();
let toolbar = new St.BoxLayout({ name: 'Toolbar' });
this.actor.add_actor(toolbar);
let inspectIcon = St.TextureCache.get_default().load_gicon(new Gio.ThemedIcon({ name: 'gtk-color-picker' }),
24);
@ -493,7 +601,6 @@ LookingGlass.prototype = {
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();
@ -511,18 +618,17 @@ LookingGlass.prototype = {
toolbar.add(emptyBox, { expand: true });
toolbar.add_actor(notebook.tabControls);
this._evalBox = new St.BoxLayout({ name: "EvalBox", vertical: true });
this._evalBox = new St.BoxLayout({ name: 'EvalBox', vertical: true });
notebook.appendPage('Evaluator', this._evalBox);
this._resultsArea = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
spacing: 4 });
this._resultsArea = new St.BoxLayout({ name: 'ResultsArea', vertical: true });
this._evalBox.add(this._resultsArea, { expand: true });
let entryArea = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
let entryArea = new St.BoxLayout({ name: 'EntryArea' });
this._evalBox.add_actor(entryArea);
let label = new St.Label({ text: 'js>>> ' });
entryArea.append(label, Big.BoxPackFlags.NONE);
entryArea.add(label);
this._entry = new St.Entry();
/* unmapping the edit box will un-focus it, undo that */
@ -530,17 +636,14 @@ LookingGlass.prototype = {
if (child == this._evalBox)
global.stage.set_key_focus(this._entry);
}));
entryArea.append(this._entry, Big.BoxPackFlags.EXPAND);
entryArea.add(this._entry, { expand: true });
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);
this._windowList = new WindowList();
this._windowList.connect('selected', Lang.bind(this, function(list, window) {
notebook.selectIndex(0);
this._pushResult('<window selection>', window);
}));
notebook.appendPage('Windows', this._windowList.actor);
this._errorLog = new ErrorLog();
notebook.appendPage('Errors', this._errorLog.actor);
@ -554,7 +657,7 @@ LookingGlass.prototype = {
// newline-separated.
text.replace('\n', ' ');
// Strip leading and trailing whitespace
text = text.replace(/^\s+/g, "").replace(/\s+$/g, "");
text = text.replace(/^\s+/g, '').replace(/\s+$/g, '');
if (text == '')
return true;
this._evaluate(text);
@ -590,7 +693,7 @@ LookingGlass.prototype = {
_updateFont: function() {
let gconf = Shell.GConf.get_default();
let fontName = gconf.get_string("/desktop/gnome/interface/monospace_font_name");
let fontName = gconf.get_string('/desktop/gnome/interface/monospace_font_name');
// This is mishandled by the scanner - should by Pango.FontDescription_from_string(fontName);
// https://bugzilla.gnome.org/show_bug.cgi?id=595889
let fontDesc = Pango.Font.description_from_string(fontName);
@ -628,8 +731,7 @@ LookingGlass.prototype = {
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);
this._resultsArea.add(result.actor);
if (this._borderPaintTarget != null) {
this._borderPaintTarget.disconnect(this._borderPaintId);
this._borderPaintTarget = null;
@ -664,11 +766,10 @@ LookingGlass.prototype = {
try {
resultObj = eval(fullCmd);
} catch (e) {
resultObj = "<exception " + e + ">";
resultObj = '<exception ' + e + '>';
}
this._pushResult(command, resultObj);
this._hierarchy.setTarget(null);
this._entry.text = '';
},
@ -698,6 +799,9 @@ LookingGlass.prototype = {
this.actor.y = this._hiddenY;
this.actor.width = myWidth;
this.actor.height = myHeight;
this._objInspector.actor.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
this._objInspector.actor.set_position(this.actor.x + Math.floor(myWidth * 0.1),
this._targetY + Math.floor(myHeight * 0.1));
},
slaveTo: function(actor) {
@ -708,11 +812,24 @@ LookingGlass.prototype = {
this._resizeTo(actor);
},
insertObject: function(obj) {
this._pushResult('<insert>', obj);
},
inspectObject: function(obj, sourceActor) {
this._objInspector.open(sourceActor);
this._objInspector.selectObject(obj);
},
// Handle key events which are relevant for all tabs of the LookingGlass
_globalKeyPressEvent : function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.Escape) {
this.close();
if (this._objInspector.actor.visible) {
this._objInspector.close();
} else {
this.close();
}
return true;
}
return false;
@ -737,7 +854,7 @@ LookingGlass.prototype = {
global.stage.set_key_focus(this._entry);
Tweener.addTween(this.actor, { time: 0.5,
transition: "easeOutQuad",
transition: 'easeOutQuad',
y: this._targetY
});
},
@ -749,6 +866,8 @@ LookingGlass.prototype = {
if (this._keyPressEventId)
global.stage.disconnect(this._keyPressEventId);
this._objInspector.actor.hide();
this._historyNavIndex = -1;
this._open = false;
Tweener.removeTweens(this.actor);
@ -762,7 +881,7 @@ LookingGlass.prototype = {
Main.popModal(this.actor);
Tweener.addTween(this.actor, { time: 0.5,
transition: "easeOutQuad",
transition: 'easeOutQuad',
y: this._hiddenY,
onComplete: Lang.bind(this, function () {
this.actor.hide();

1479
js/ui/magnifier.js Normal file

File diff suppressed because it is too large Load Diff

375
js/ui/magnifierDBus.js Normal file
View File

@ -0,0 +1,375 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const DBus = imports.dbus;
const Main = imports.ui.main;
const MAG_SERVICE_NAME = 'org.gnome.Magnifier';
const MAG_SERVICE_PATH = '/org/gnome/Magnifier';
const ZOOM_SERVICE_NAME = 'org.gnome.Magnifier.ZoomRegion';
const ZOOM_SERVICE_PATH = '/org/gnome/Magnifier/ZoomRegion';
// Subset of gnome-mag's Magnifier dbus interface -- to be expanded. See:
// http://git.gnome.org/browse/gnome-mag/tree/xml/...Magnifier.xml
const MagnifierIface = {
name: MAG_SERVICE_NAME,
methods: [
{ name: 'setActive', inSignature: 'b', outSignature: '' },
{ name: 'isActive', inSignature: '', outSignature: 'b' },
{ name: 'showCursor', inSignature: '', outSignature: '' },
{ name: 'hideCursor', inSignature: '', outSignature: '' },
{ name: 'createZoomRegion', inSignature: 'ddaiai', outSignature: 'o' },
{ name: 'addZoomRegion', inSignature: 'o', outSignature: 'b' },
{ name: 'getZoomRegions', inSignature: '', outSignature: 'ao' },
{ name: 'clearAllZoomRegions', inSignature: '', outSignature: '' },
{ name: 'fullScreenCapable', inSignature: '', outSignature: 'b' },
{ name: 'setCrosswireSize', inSignature: 'i', outSignature: '' },
{ name: 'getCrosswireSize', inSignature: '', outSignature: 'i' },
{ name: 'setCrosswireLength', inSignature: 'i', outSignature: '' },
{ name: 'getCrosswireLength', inSignature: '', outSignature: 'i' },
{ name: 'setCrosswireClip', inSignature: 'b', outSignature: '' },
{ name: 'getCrosswireClip', inSignature: '', outSignature: 'b' },
{ name: 'setCrosswireColor', inSignature: 'u', outSignature: '' },
{ name: 'getCrosswireColor', inSignature: '', outSignature: 'u' }
],
signals: [],
properties: []
};
// Subset of gnome-mag's ZoomRegion dbus interface -- to be expanded. See:
// http://git.gnome.org/browse/gnome-mag/tree/xml/...ZoomRegion.xml
const ZoomRegionIface = {
name: ZOOM_SERVICE_NAME,
methods: [
{ name: 'setMagFactor', inSignature: 'dd', outSignature: ''},
{ name: 'getMagFactor', inSignature: '', outSignature: 'dd' },
{ name: 'setRoi', inSignature: 'ai', outSignature: '' },
{ name: 'getRoi', inSignature: '', outSignature: 'ai' },
{ name: 'shiftContentsTo', inSignature: 'ii', outSignature: 'b' },
{ name: 'moveResize', inSignature: 'ai', outSignature: '' }
],
signals: [],
properties: []
};
// For making unique ZoomRegion DBus proxy object paths of the form:
// '/org/gnome/Magnifier/ZoomRegion/zoomer0',
// '/org/gnome/Magnifier/ZoomRegion/zoomer1', etc.
let _zoomRegionInstanceCount = 0;
function ShellMagnifier() {
this._init();
}
ShellMagnifier.prototype = {
_init: function() {
this._zoomers = {};
DBus.session.exportObject(MAG_SERVICE_PATH, this);
},
/**
* setActive:
* @activate: Boolean to activate or de-activate the magnifier.
*/
setActive: function(activate) {
Main.magnifier.setActive(activate);
},
/**
* isActive:
* @return Whether the magnifier is active (boolean).
*/
isActive: function() {
return Main.magnifier.isActive();
},
/**
* showCursor:
* Show the system mouse pointer.
*/
showCursor: function() {
Main.magnifier.showSystemCursor();
},
/**
* hideCursor:
* Hide the system mouse pointer.
*/
hideCursor: function() {
Main.magnifier.hideSystemCursor();
},
/**
* createZoomRegion:
* Create a new ZoomRegion and return its object path.
* @xMagFactor: The power to set horizontal magnification of the
* ZoomRegion. A value of 1.0 means no magnification. A
* value of 2.0 doubles the size.
* @yMagFactor: The power to set the vertical magnification of the
* ZoomRegion.
* @roi Array of integers defining the region of the
* screen/desktop to magnify. The array has the form
* [x, y, width, height].
* @viewPort Array of integers, [ x, y, width, height ] that defines
* the position of the ZoomRegion on screen.
* @return The newly created ZoomRegion.
*/
createZoomRegion: function(xMagFactor, yMagFactor, roi, viewPort) {
let ROI = { x: roi[0], y: roi[1], width: roi[2], height: roi[3] };
let viewBox = { x: viewPort[0], y: viewPort[1], width: viewPort[2], height: viewPort[3] };
let realZoomRegion = Main.magnifier.createZoomRegion(xMagFactor, yMagFactor, ROI, viewBox);
let objectPath = ZOOM_SERVICE_PATH + '/zoomer' + _zoomRegionInstanceCount;
_zoomRegionInstanceCount++;
let zoomRegionProxy = new ShellMagnifierZoomRegion(objectPath, realZoomRegion);
let proxyAndZoomRegion = {};
proxyAndZoomRegion.proxy = zoomRegionProxy;
proxyAndZoomRegion.zoomRegion = realZoomRegion;
this._zoomers[objectPath] = proxyAndZoomRegion;
return objectPath;
},
/**
* addZoomRegion:
* Append the given ZoomRegion to the magnifier's list of ZoomRegions.
* @zoomerObjectPath: The object path for the zoom region proxy.
*/
addZoomRegion: function(zoomerObjectPath) {
let proxyAndZoomRegion = this._zoomers[zoomerObjectPath];
if (proxyAndZoomRegion && proxyAndZoomRegion.zoomRegion) {
Main.magnifier.addZoomRegion(proxyAndZoomRegion.zoomRegion);
return true;
}
else
return false;
},
/**
* getZoomRegions:
* Return a list of ZoomRegion object paths for this Magnifier.
* @return: The Magnifier's zoom region list as an array of DBus object
* paths.
*/
getZoomRegions: function() {
// There may be more ZoomRegions in the magnifier itself than have
// been added through dbus. Make sure all of them are associated with
// an object path and proxy.
let zoomRegions = Main.magnifier.getZoomRegions();
let objectPaths = [];
let thoseZoomers = this._zoomers;
zoomRegions.forEach (function(aZoomRegion, index, array) {
let found = false;
for (let objectPath in thoseZoomers) {
let proxyAndZoomRegion = thoseZoomers[objectPath];
if (proxyAndZoomRegion.zoomRegion === aZoomRegion) {
objectPaths.push(objectPath);
found = true;
break;
}
}
if (!found) {
// Got a ZoomRegion with no DBus proxy, make one.
let newPath = ZOOM_SERVICE_PATH + '/zoomer' + _zoomRegionInstanceCount;
_zoomRegionInstanceCount++;
let zoomRegionProxy = new ShellMagnifierZoomRegion(newPath, aZoomRegion);
let proxyAndZoomer = {};
proxyAndZoomer.proxy = zoomRegionProxy;
proxyAndZoomer.zoomRegion = aZoomRegion;
thoseZoomers[newPath] = proxyAndZoomer;
objectPaths.push(newPath);
}
});
return objectPaths;
},
/**
* clearAllZoomRegions:
* Remove all the zoom regions from this Magnfier's ZoomRegion list.
*/
clearAllZoomRegions: function() {
Main.magnifier.clearAllZoomRegions();
for (let objectPath in this._zoomers) {
let proxyAndZoomer = this._zoomers[objectPath];
proxyAndZoomer.proxy = null;
proxyAndZoomer.zoomRegion = null;
delete this._zoomers[objectPath];
DBus.session.unexportObject(proxyAndZoomer);
}
this._zoomers = {};
},
/**
* fullScreenCapable:
* Consult if the Magnifier can magnify in full-screen mode.
* @return Always return true.
*/
fullScreenCapable: function() {
return true;
},
/**
* setCrosswireSize:
* Set the crosswire size of all ZoomRegions.
* @size: The thickness of each line in the cross wire.
*/
setCrosswireSize: function(size) {
Main.magnifier.setCrosshairsThickness(size);
},
/**
* getCrosswireSize:
* Get the crosswire size of all ZoomRegions.
* @return: The thickness of each line in the cross wire.
*/
getCrosswireSize: function() {
return Main.magnifier.getCrosshairsThickness();
},
/**
* setCrosswireLength:
* Set the crosswire length of all zoom-regions..
* @size: The length of each line in the cross wire.
*/
setCrosswireLength: function(length) {
Main.magnifier.setCrosshairsLength(length);
},
/**
* setCrosswireSize:
* Set the crosswire size of all zoom-regions.
* @size: The thickness of each line in the cross wire.
*/
getCrosswireLength: function() {
return Main.magnifier.getCrosshairsLength();
},
/**
* setCrosswireClip:
* Set if the crosswire will be clipped by the cursor image..
* @clip: Flag to indicate whether to clip the crosswire.
*/
setCrosswireClip: function(clip) {
Main.magnifier.setCrosshairsClip(clip);
},
/**
* getCrosswireClip:
* Get the crosswire clip value.
* @return: Whether the crosswire is clipped by the cursor image.
*/
getCrosswireClip: function() {
return Main.magnifier.getCrosshairsClip();
},
/**
* setCrosswireColor:
* Set the crosswire color of all ZoomRegions.
* @color: Unsigned int of the form rrggbbaa.
*/
setCrosswireColor: function(color) {
Main.magnifier.setCrosshairsColor('#' + color.toString(16));
},
/**
* getCrosswireClip:
* Get the crosswire color of all ZoomRegions.
* @return: The crosswire color as an unsigned int in the form rrggbbaa.
*/
getCrosswireColor: function() {
let colorString = Main.magnifier.getCrosshairsColor();
// Drop the leading '#'.
return parseInt(colorString.slice(1), 16);
}
};
/**
* ShellMagnifierZoomRegion:
* Object that implements the DBus ZoomRegion interface.
* @zoomerObjectPath: String that is the path to a DBus ZoomRegion.
* @zoomRegion: The actual zoom region associated with the object path.
*/
function ShellMagnifierZoomRegion(zoomerObjectPath, zoomRegion) {
this._init(zoomerObjectPath, zoomRegion);
}
ShellMagnifierZoomRegion.prototype = {
_init: function(zoomerObjectPath, zoomRegion) {
this._zoomRegion = zoomRegion;
DBus.session.proxifyObject(this, ZOOM_SERVICE_NAME, zoomerObjectPath);
DBus.session.exportObject(zoomerObjectPath, this);
},
/**
* setMagFactor:
* @xMagFactor: The power to set the horizontal magnification factor to
* of the magnified view. A value of 1.0 means no
* magnification. A value of 2.0 doubles the size.
* @yMagFactor: The power to set the vertical magnification factor to
* of the magnified view.
*/
setMagFactor: function(xMagFactor, yMagFactor) {
this._zoomRegion.setMagFactor(xMagFactor, yMagFactor);
},
/**
* getMagFactor:
* @return an array, [xMagFactor, yMagFactor], containing the horizontal
* and vertical magnification powers. A value of 1.0 means no
* magnification. A value of 2.0 means the contents are doubled
* in size, and so on.
*/
getMagFactor: function() {
return this._zoomRegion.getMagFactor();
},
/**
* setRoi:
* Sets the "region of interest" that the ZoomRegion is magnifying.
* @roi Array, [x, y, width, height], defining the region of the screen to
* magnify. The values are in screen (unmagnified) coordinate
* space.
*/
setRoi: function(roi) {
let roiObject = { x: roi[0], y: roi[1], width: roi[2], height: roi[3] };
this._zoomRegion.setROI(roiObject);
},
/**
* getRoi:
* Retrieves the "region of interest" -- the rectangular bounds of that part
* of the desktop that the magnified view is showing (x, y, width, height).
* The bounds are given in non-magnified coordinates.
* @return an array, [x, y, width, height], representing the bounding
* rectangle of what is shown in the magnified view.
*/
getRoi: function() {
return this._zoomRegion.getROI();
},
/**
* Set the "region of interest" by centering the given screen coordinate
* within the zoom region.
* @x The x-coord of the point to place at the center of the zoom region.
* @y The y-coord.
* @return Whether the shift was successful (for GS-mag, this is always
* true).
*/
shiftContentsTo: function(x, y) {
this._zoomRegion.scrollContentsTo(x, y);
return true;
},
/**
* moveResize
* Sets the position and size of the ZoomRegion on screen.
* @viewPort Array, [x, y, width, height], defining the position and size
* on screen to place the zoom region.
*/
moveResize: function(viewPort) {
let viewRect = { x: viewPort[0], y: viewPort[1], width: viewPort[2], height: viewPort[3] };
this._zoomRegion.setViewPort(viewRect);
}
};
DBus.conformExport(ShellMagnifier.prototype, MagnifierIface);
DBus.conformExport(ShellMagnifierZoomRegion.prototype, ZoomRegionIface);

View File

@ -1,5 +1,11 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
imports.gi.versions.Clutter = '1.0';
imports.gi.versions.Gio = '2.0';
imports.gi.versions.Gdk = '2.0';
imports.gi.versions.GdkPixbuf = '2.0';
imports.gi.versions.Gtk = '2.0';
const Clutter = imports.gi.Clutter;
const DBus = imports.dbus;
const Gdk = imports.gi.Gdk;
@ -23,37 +29,41 @@ const RunDialog = imports.ui.runDialog;
const LookingGlass = imports.ui.lookingGlass;
const NotificationDaemon = imports.ui.notificationDaemon;
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
const Scripting = imports.ui.scripting;
const ShellDBus = imports.ui.shellDBus;
const Sidebar = imports.ui.sidebar;
const TelepathyClient = imports.ui.telepathyClient;
const WindowManager = imports.ui.windowManager;
const Magnifier = imports.ui.magnifier;
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
let chrome = null;
let panel = null;
let sidebar = null;
let placesManager = null;
let overview = null;
let runDialog = null;
let lookingGlass = null;
let wm = null;
let notificationDaemon = null;
let messageTray = null;
let notificationDaemon = null;
let windowAttentionHandler = null;
let telepathyClient = null;
let recorder = null;
let shellDBusService = null;
let modalCount = 0;
let modalActorFocusStack = [];
let uiGroup = null;
let magnifier = null;
let _errorLogStack = [];
let _startDate;
let background = null;
function start() {
// Add a binding for "global" in the global JS namespace; (gjs
// Add a binding for 'global' in the global JS namespace; (gjs
// keeps the web browser convention of having that namespace be
// called "window".)
// called 'window'.)
window.global = Shell.Global.get();
// Now monkey patch utility functions into the global proxy;
@ -62,7 +72,7 @@ function start() {
global.logError = _logError;
global.log = _logDebug;
Gio.DesktopAppInfo.set_desktop_env("GNOME");
Gio.DesktopAppInfo.set_desktop_env('GNOME');
global.grab_dbus_service();
shellDBusService = new ShellDBus.GnomeShell();
@ -91,29 +101,35 @@ function start() {
global.stage.color = DEFAULT_BACKGROUND_COLOR;
let themeContext = St.ThemeContext.get_for_stage (global.stage);
let stylesheetPath = global.datadir + "/theme/gnome-shell.css";
let stylesheetPath = global.datadir + '/theme/gnome-shell.css';
let theme = new St.Theme ({ application_stylesheet: stylesheetPath });
themeContext.set_theme (theme);
let shellwm = global.window_manager;
shellwm.takeover_keybinding("panel_main_menu");
shellwm.connect("keybinding::panel_main_menu", function () {
shellwm.takeover_keybinding('panel_main_menu');
shellwm.connect('keybinding::panel_main_menu', function () {
overview.toggle();
});
shellwm.takeover_keybinding("panel_run_dialog");
shellwm.connect("keybinding::panel_run_dialog", function () {
shellwm.takeover_keybinding('panel_run_dialog');
shellwm.connect('keybinding::panel_run_dialog', function () {
getRunDialog().open();
});
// Set up stage hierarchy to group all UI actors under one container.
uiGroup = new Clutter.Group();
global.window_group.reparent(uiGroup);
global.overlay_group.reparent(uiGroup);
global.stage.add_actor(uiGroup);
placesManager = new PlaceDisplay.PlacesManager();
overview = new Overview.Overview();
chrome = new Chrome.Chrome();
panel = new Panel.Panel();
sidebar = new Sidebar.Sidebar();
wm = new WindowManager.WindowManager();
messageTray = new MessageTray.MessageTray();
notificationDaemon = new NotificationDaemon.NotificationDaemon();
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
messageTray = new MessageTray.MessageTray();
telepathyClient = new TelepathyClient.Client();
_startDate = new Date();
@ -127,9 +143,9 @@ function start() {
} else {
//read the parameters from GConf always in case they have changed
let gconf = Shell.GConf.get_default();
recorder.set_framerate(gconf.get_int("recorder/framerate"));
recorder.set_filename("shell-%d%u-%c." + gconf.get_string("recorder/file_extension"));
let pipeline = gconf.get_string("recorder/pipeline");
recorder.set_framerate(gconf.get_int('recorder/framerate'));
recorder.set_filename('shell-%d%u-%c.' + gconf.get_string('recorder/file_extension'));
let pipeline = gconf.get_string('recorder/pipeline');
if (!pipeline.match(/^\s*$/))
recorder.set_pipeline(pipeline);
else
@ -155,10 +171,23 @@ function start() {
global.stage.connect('captured-event', _globalKeyPressHandler);
// Install magnifier.
magnifier = new Magnifier.Magnifier();
// Perform initial relayout here
_relayout();
_log('info', 'loaded at ' + _startDate);
log('GNOME Shell started at ' + _startDate);
Mainloop.idle_add(_removeUnusedWorkspaces);
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
if (perfModuleName) {
let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT");
let module = eval('imports.perf.' + perfModuleName + ';');
Scripting.runPerfScript(module, perfOutput);
}
}
/**
@ -179,7 +208,7 @@ function _log(category, msg) {
for (let i = 2; i < arguments.length; i++) {
text += JSON.stringify(arguments[i]);
if (i < arguments.length - 1)
text += " ";
text += ' ';
}
}
_errorLogStack.push({timestamp: new Date().getTime(),
@ -268,8 +297,8 @@ function _globalKeyPressHandler(actor, event) {
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 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();
@ -342,7 +371,7 @@ function _findModal(actor) {
function pushModal(actor) {
if (modalCount == 0) {
if (!global.begin_modal(global.get_current_time())) {
log("pushModal: invocation of begin_modal failed");
log('pushModal: invocation of begin_modal failed');
return false;
}
}
@ -485,7 +514,7 @@ function _queueBeforeRedraw(workId) {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, function () {
_runBeforeRedrawQueue();
return false;
}, null);
});
}
}
@ -509,7 +538,7 @@ function _queueBeforeRedraw(workId) {
*/
function initializeDeferredWork(actor, callback, props) {
// Turn into a string so we can use as an object property
let workId = "" + (++_deferredWorkSequence);
let workId = '' + (++_deferredWorkSequence);
_deferredWorkData[workId] = { 'actor': actor,
'callback': callback };
actor.connect('notify::mapped', function () {
@ -539,7 +568,7 @@ function initializeDeferredWork(actor, callback, props) {
function queueDeferredWork(workId) {
let data = _deferredWorkData[workId];
if (!data) {
global.logError("invalid work id ", workId);
global.logError('invalid work id ', workId);
return;
}
if (_deferredWorkQueue.indexOf(workId) < 0)

View File

@ -1,6 +1,7 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Pango = imports.gi.Pango;
@ -15,7 +16,7 @@ const ANIMATION_TIME = 0.2;
const NOTIFICATION_TIMEOUT = 4;
const SUMMARY_TIMEOUT = 1;
const MESSAGE_TRAY_TIMEOUT = 0.2;
const HIDE_TIMEOUT = 0.2;
const ICON_SIZE = 24;
@ -29,10 +30,10 @@ const State = {
function _cleanMarkup(text) {
// Support &amp;, &quot;, &apos;, &lt; and &gt;, escape all other
// occurrences of '&'.
let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, "&amp;");
let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&amp;');
// Support <b>, <i>, and <u>, escape anything else
// so it displays as raw markup.
return _text.replace(/<(\/?[^biu]>|[^>\/][^>])/g, "&lt;$1");
return _text.replace(/<(\/?[^biu]>|[^>\/][^>])/g, '&lt;$1');
}
// Notification:
@ -46,11 +47,15 @@ function _cleanMarkup(text) {
// @source's icon, @title (in bold) and @banner, all on a single line
// (with @banner ellipsized if necessary).
//
// Additional notification details can be added via addBody(),
// addAction(), and addActor(). If any of these are called, then the
// notification will expand to show the additional actors (while
// hiding the @banner) if the pointer is moved into it while it is
// visible.
// Additional notification details can be added, in which case the
// notification can be expanded by moving the pointer into it. In
// expanded mode, the banner text disappears, and there can be one or
// more rows of additional content. This content is put inside a
// scrollview, so if it gets too tall, the notification will scroll
// rather than continuing to grow. In addition to this main content
// area, there is also a single-row "action area", which is not
// scrolled and can contain a single actor. There are also convenience
// methods for creating a button box in the action area.
//
// If @bannerBody is %true, then @banner will also be used as the body
// of the notification (as with addBody()) when the banner is expanded.
@ -65,45 +70,52 @@ Notification.prototype = {
this.id = id;
this.source = source;
this._bannerBody = bannerBody;
this.urgent = false;
source.connect('clicked', Lang.bind(this,
function() {
this.emit('dismissed');
}));
this.actor = new St.Table({ name: 'notification' });
this.actor = new St.Table({ name: 'notification',
reactive: true });
this.actor.connect('style-changed', Lang.bind(this, this._styleChanged));
this.update(title, banner, true);
},
// update:
// @title: the new title
// @banner: the new banner
// @clear: whether or not to clear out extra actors
// @clear: whether or not to clear out body and action actors
//
// Updates the notification by regenerating its icon and updating
// the title/banner. If @clear is %true, it will also remove any
// additional actors/action buttons previously added.
update: function(title, banner, clear) {
let children = this.actor.get_children();
for (let i = 0; i < children.length; i++) {
let meta = this.actor.get_child_meta(children[i]);
if (clear || meta.row == 0 || (this._bannerBody && meta.row == 1))
children[i].destroy();
if (this._icon)
this._icon.destroy();
if (this._bannerBox)
this._bannerBox.destroy();
if (this._scrollArea && (this._bannerBody || clear)) {
this._scrollArea.destroy();
this._scrollArea = null;
this._contentArea = null;
}
if (clear) {
this.actions = {};
this._actionBox = null;
if (this._actionArea && clear) {
this._actionArea.destroy();
this._actionArea = null;
this._buttonBox = null;
}
let icon = this.source.createIcon(ICON_SIZE);
icon.reactive = true;
this.actor.add(icon, { row: 0,
col: 0,
x_expand: false,
y_expand: false,
y_fill: false });
this._icon = this.source.createIcon(ICON_SIZE);
this._icon.reactive = true;
this.actor.add(this._icon, { row: 0,
col: 0,
x_expand: false,
y_expand: false,
y_fill: false });
icon.connect('button-release-event', Lang.bind(this,
this._icon.connect('button-release-event', Lang.bind(this,
function () {
this.source.clicked();
}));
@ -136,67 +148,39 @@ Notification.prototype = {
banner = banner ? _cleanMarkup(banner.replace(/\n/g, ' ')) : '';
this._bannerLabel.clutter_text.set_markup(banner);
this._bannerBox.add_actor(this._bannerLabel);
// Add the bannerBody now if we know for sure we'll need it
if (this._bannerBodyText && this._bannerBodyText.indexOf('\n') > -1)
this._addBannerBody();
},
// addActor:
// @actor: actor to add to the notification
// @props: (optional) child properties
// @actor: actor to add to the body of the notification
//
// Adds @actor to the notification's St.Table, using @props.
//
// If @props does not specify a %row, then @actor will be added
// to the bottom of the notification (unless there are action
// buttons present, in which case it will be added above them).
//
// If @props does not specify a %col, it will default to column 1.
// (Normally only the icon is in column 0.)
//
// If @props specifies an already-occupied cell, then the existing
// contents of the table will be shifted down to make room for it.
addActor: function(actor, props) {
if (!props)
props = {};
if (!('col' in props))
props.col = 1;
if ('row' in props) {
let children = this.actor.get_children();
let i, meta, collision = false;
for (i = 0; i < children.length; i++) {
meta = this.actor.get_child_meta(children[i]);
if (meta.row == props.row && meta.col == props.col) {
collision = true;
break;
}
}
if (collision) {
for (i = 0; i < children.length; i++) {
meta = this.actor.get_child_meta(children[i]);
if (meta.row >= props.row)
meta.row++;
}
}
} else {
if (this._actionBox) {
props.row = this.actor.row_count - 1;
this.actor.get_child_meta(this._actionBox).row++;
} else {
props.row = this.actor.row_count;
}
// Appends @actor to the notification's body
addActor: function(actor) {
if (!this._scrollArea) {
this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
hscrollbar_policy: Gtk.PolicyType.NEVER,
vshadows: true });
this.actor.add(this._scrollArea, { row: 1,
col: 1 });
this._contentArea = new St.BoxLayout({ name: 'notification-body',
vertical: true });
this._scrollArea.add_actor(this._contentArea);
}
this.actor.add(actor, props);
this._contentArea.add(actor);
},
// addBody:
// @text: the text
// @props: (optional) properties for addActor()
//
// Adds a multi-line label containing @text to the notification.
addBody: function(text, props) {
//
// Return value: the newly-added label
addBody: function(text) {
let body = new St.Label();
body.clutter_text.line_wrap = true;
body.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
@ -205,15 +189,56 @@ Notification.prototype = {
text = text ? _cleanMarkup(text) : '';
body.clutter_text.set_markup(text);
this.addActor(body, props);
this.addActor(body);
return body;
},
_addBannerBody: function() {
this.addBody(this._bannerBodyText, { row: 1 });
this.addBody(this._bannerBodyText);
this._bannerBodyText = null;
},
// addAction:
// scrollTo:
// @side: St.Side.TOP or St.Side.BOTTOM
//
// Scrolls the content area (if scrollable) to the indicated edge
scrollTo: function(side) {
// Hack to force a relayout, since the caller probably
// just added or removed something to scrollArea, and
// the adjustment needs to reflect that.
global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, 0, 0);
let adjustment = this._scrollArea.vscroll.adjustment;
if (side == St.Side.TOP)
adjustment.value = adjustment.lower;
else if (side == St.Side.BOTTOM)
adjustment.value = adjustment.upper;
},
// setActionArea:
// @actor: the actor
// @props: (option) St.Table child properties
//
// Puts @actor into the action area of the notification, replacing
// the previous contents
setActionArea: function(actor, props) {
if (this._actionArea) {
this._actionArea.destroy();
this._actionArea = null;
if (this._buttonBox)
this._buttonBox = null;
}
this._actionArea = actor;
if (!props)
props = {};
props.row = 2;
props.col = 1;
this.actor.add(this._actionArea, props);
},
// addButton:
// @id: the action ID
// @label: the label for the action's button
//
@ -223,31 +248,51 @@ Notification.prototype = {
//
// If the button is clicked, the notification will emit the
// %action-invoked signal with @id as a parameter
addAction: function(id, label) {
if (!this._actionBox) {
addButton: function(id, label) {
if (!this._buttonBox) {
if (this._bannerBodyText)
this._addBannerBody();
let box = new St.BoxLayout({ name: 'notification-actions' });
this.addActor(box, { x_expand: false,
x_fill: false,
x_align: St.Align.END });
this._actionBox = box;
this.setActionArea(box, { x_expand: false,
x_fill: false,
x_align: St.Align.END });
this._buttonBox = box;
}
let button = new St.Button({ style_class: 'notification-button',
label: label });
this._actionBox.add(button);
this._buttonBox.add(button);
button.connect('clicked', Lang.bind(this, function() { this.emit('action-invoked', id); }));
},
setUrgent: function(urgent) {
this.urgent = urgent;
},
_styleChanged: function() {
let [has_spacing, spacing] = this.actor.get_theme_node().get_length('spacing-columns', false);
this._spacing = has_spacing ? spacing : 0;
// Figure out now (before allocation starts) whether or not we
// need to be expandable, and add the expansion row if so
if (this._bannerBodyText) {
let [minBannerWidth, natBannerWidth] =
this._bannerBox.get_preferred_width(-1);
let [minNotificationWidth, natNotificationWidth] =
this.actor.get_preferred_width(-1);
if (natBannerWidth > natNotificationWidth)
this._addBannerBody();
}
},
_bannerBoxGetPreferredWidth: function(actor, forHeight, alloc) {
let [titleMin, titleNat] = this._titleLabel.get_preferred_width(forHeight);
let [bannerMin, bannerNat] = this._bannerLabel.get_preferred_width(forHeight);
let [has_spacing, spacing] = this.actor.get_theme_node().get_length('spacing-columns', false);
alloc.min_size = titleMin;
alloc.natural_size = titleNat + (has_spacing ? spacing : 0) + bannerNat;
alloc.natural_size = titleNat + this._spacing + bannerNat;
},
_bannerBoxGetPreferredHeight: function(actor, forWidth, alloc) {
@ -259,9 +304,6 @@ Notification.prototype = {
let [titleMinW, titleNatW] = this._titleLabel.get_preferred_width(-1);
let [titleMinH, titleNatH] = this._titleLabel.get_preferred_height(-1);
let [bannerMinW, bannerNatW] = this._bannerLabel.get_preferred_width(-1);
let [has_spacing, spacing] = this.actor.get_theme_node().get_length('spacing-columns', false);
if (!has_spacing)
spacing = 0;
let availWidth = box.x2 - box.x1;
let titleBox = new Clutter.ActorBox();
@ -270,26 +312,17 @@ Notification.prototype = {
titleBox.y2 = titleNatH;
this._titleLabel.allocate(titleBox, flags);
let overflow = false;
if (titleBox.x2 + spacing > availWidth) {
if (titleBox.x2 + this._spacing > availWidth) {
this._bannerLabel.hide();
overflow = true;
} else {
let bannerBox = new Clutter.ActorBox();
bannerBox.x1 = titleBox.x2 + spacing;
bannerBox.x1 = titleBox.x2 + this._spacing;
bannerBox.y1 = 0;
bannerBox.x2 = Math.min(bannerBox.x1 + bannerNatW, availWidth);
bannerBox.y2 = titleNatH;
this._bannerLabel.show();
this._bannerLabel.allocate(bannerBox, flags);
if (bannerBox.x2 < bannerBox.x1 + bannerNatW)
overflow = true;
}
if (this._bannerBodyText &&
(overflow || this._bannerBodyText.indexOf('\n') > -1))
this._addBannerBody();
},
popOut: function() {
@ -299,7 +332,7 @@ Notification.prototype = {
Tweener.addTween(this._bannerLabel,
{ opacity: 0,
time: ANIMATION_TIME,
transition: "easeOutQuad" });
transition: 'easeOutQuad' });
return true;
},
@ -309,7 +342,7 @@ Notification.prototype = {
Tweener.addTween(this._bannerLabel,
{ opacity: 255,
time: ANIMATION_TIME,
transition: "easeOutQuad" });
transition: 'easeOutQuad' });
return true;
},
@ -329,7 +362,6 @@ Source.prototype = {
this.text = null;
if (createIcon)
this.createIcon = createIcon;
this.handleReplacing = true;
},
// This can be overridden by a subclass, or by the createIcon
@ -339,6 +371,19 @@ Source.prototype = {
},
notify: function(notification) {
if (this.notification)
this.notification.disconnect(this._notificationDestroyedId);
this.notification = notification;
this._notificationDestroyedId = notification.connect('destroy', Lang.bind(this,
function () {
if (this.notification == notification) {
this.notification = null;
this._notificationDestroyedId = 0;
}
}));
this.emit('notify', notification);
},
@ -359,30 +404,35 @@ function MessageTray() {
MessageTray.prototype = {
_init: function() {
this.actor = new St.BoxLayout({ name: 'message-tray',
reactive: true });
reactive: true,
track_hover: true });
this.actor.connect('notify::hover', Lang.bind(this, this._onTrayHoverChanged));
this._notificationBin = new St.Bin({ reactive: true,
x_align: St.Align.MIDDLE });
this._notificationBin = new St.Bin();
this.actor.add(this._notificationBin);
this._notificationBin.hide();
this._notificationQueue = [];
this._notification = null;
this._summaryBin = new St.BoxLayout();
this._summaryBin = new St.Bin({ anchor_gravity: Clutter.Gravity.NORTH_EAST });
this.actor.add(this._summaryBin);
this._summary = new St.BoxLayout({ name: 'summary-mode',
reactive: true });
this._summaryBin.add(this._summary, { x_align: St.Align.END,
x_fill: false,
expand: true });
this._summary.connect('enter-event',
Lang.bind(this, this._onSummaryEntered));
this._summary.connect('leave-event',
Lang.bind(this, this._onSummaryLeft));
reactive: true,
track_hover: true });
this._summary.connect('notify::hover', Lang.bind(this, this._onSummaryHoverChanged));
this._summaryBin.child = this._summary;
this._summaryBin.opacity = 0;
this.actor.connect('enter-event', Lang.bind(this, this._onTrayEntered));
this.actor.connect('leave-event', Lang.bind(this, this._onTrayLeft));
this._summaryNotificationBin = new St.Bin({ name: 'summary-notification-bin',
anchor_gravity: Clutter.Gravity.NORTH_EAST,
reactive: true,
track_hover: true });
this.actor.add(this._summaryNotificationBin);
this._summaryNotificationBin.lower_bottom();
this._summaryNotificationBin.hide();
this._summaryNotificationBin.connect('notify::hover', Lang.bind(this, this._onSummaryNotificationHoverChanged));
this._summaryNotification = null;
this._hoverSource = null;
this._trayState = State.HIDDEN;
this._trayLeftTimeoutId = 0;
@ -392,13 +442,15 @@ MessageTray.prototype = {
this._pointerInSummary = false;
this._notificationState = State.HIDDEN;
this._notificationTimeoutId = 0;
this._summaryNotificationState = State.HIDDEN;
this._summaryNotificationTimeoutId = 0;
this._overviewVisible = false;
this._notificationRemoved = false;
this.actor.show();
Main.chrome.addActor(this.actor, { affectsStruts: false,
visibleInOverview: true });
Main.chrome.trackActor(this._notificationBin, { affectsStruts: false });
Main.chrome.trackActor(this._notificationBin);
Main.chrome.trackActor(this._summaryNotificationBin);
global.connect('screen-size-changed',
Lang.bind(this, this._setSizePosition));
@ -424,9 +476,12 @@ MessageTray.prototype = {
this.actor.x = primary.x;
this.actor.y = primary.y + primary.height - 1;
this.actor.width = primary.width;
this._notificationBin.x = 0;
this._notificationBin.width = primary.width;
this._notificationBin.x = this._summaryBin.x = 0;
this._notificationBin.width = this._summaryBin.width = primary.width;
// These work because of their anchor_gravity
this._summaryBin.x = primary.width;
this._summaryNotificationBin.x = primary.width;
},
contains: function(source) {
@ -439,7 +494,8 @@ MessageTray.prototype = {
return;
}
let iconBox = new St.Bin({ reactive: true });
let iconBox = new St.Clickable({ style_class: 'summary-icon',
reactive: true });
iconBox.child = source.createIcon(ICON_SIZE);
this._summary.insert_actor(iconBox, 0);
this._summaryNeedsToBeShown = true;
@ -448,7 +504,11 @@ MessageTray.prototype = {
source.connect('notify', Lang.bind(this, this._onNotify));
iconBox.connect('button-release-event', Lang.bind(this,
iconBox.connect('notify::hover', Lang.bind(this,
function () {
this._onSourceHoverChanged(source, iconBox.hover);
}));
iconBox.connect('clicked', Lang.bind(this,
function () {
source.clicked();
}));
@ -479,14 +539,23 @@ MessageTray.prototype = {
delete this._icons[source.id];
delete this._sources[source.id];
let needUpdate = false;
if (this._notification && this._notification.source == source) {
if (this._notificationTimeoutId) {
Mainloop.source_remove(this._notificationTimeoutId);
this._notificationTimeoutId = 0;
}
this._notificationRemoved = true;
this._updateState();
needUpdate = true;
}
if (this._hoverSource == source) {
this._hoverSource = null;
needUpdate = true;
}
if (needUpdate);
this._updateState();
},
removeSourceByApp: function(app) {
@ -527,42 +596,90 @@ MessageTray.prototype = {
return null;
},
lock: function() {
this._locked = true;
},
unlock: function() {
this._locked = false;
this.actor.sync_hover();
this._summary.sync_hover();
this._updateState();
},
_onNotify: function(source, notification) {
if (!notification.source.handleReplacing || this._getNotification(notification.id, source) == null) {
if (notification == this._summaryNotification)
return;
if (this._getNotification(notification.id, source) == null) {
notification.connect('destroy',
Lang.bind(this, this.removeNotification));
this._notificationQueue.push(notification);
if (notification.urgent)
this._notificationQueue.unshift(notification);
else
this._notificationQueue.push(notification);
}
this._updateState();
},
_onSummaryEntered: function() {
this._pointerInSummary = true;
this._updateState();
},
_onSummaryLeft: function() {
this._pointerInSummary = false;
this._updateState();
},
_onTrayEntered: function() {
if (this._trayLeftTimeoutId) {
Mainloop.source_remove(this._trayLeftTimeoutId);
this._trayLeftTimeoutId = 0;
_onSourceHoverChanged: function(source, hover) {
if (!source.notification)
return;
if (this._summaryNotificationTimeoutId != 0) {
Mainloop.source_remove(this._summaryNotificationTimeoutId);
this._summaryNotificationTimeoutId = 0;
}
this._pointerInTray = true;
if (hover) {
this._hoverSource = source;
this._updateState();
} else if (this._hoverSource == source) {
let timeout = HIDE_TIMEOUT * 1000;
this._summaryNotificationTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, this._onSourceHoverChangedTimeout, source));
}
},
_onSourceHoverChangedTimeout: function(source) {
this._summaryNotificationTimeoutId = 0;
if (this._hoverSource == source) {
this._hoverSource = null;
this._updateState();
}
},
_onSummaryNotificationHoverChanged: function() {
if (!this._summaryNotification)
return;
this._onSourceHoverChanged(this._summaryNotification.source,
this._summaryNotificationBin.hover);
},
_onSummaryHoverChanged: function() {
this._pointerInSummary = this._summary.hover;
this._updateState();
},
_onTrayLeft: function() {
// We wait just a little before hiding the message tray in case the
// user quickly moves the mouse back into it.
let timeout = MESSAGE_TRAY_TIMEOUT * 1000;
this._trayLeftTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, this._onTrayLeftTimeout));
_onTrayHoverChanged: function() {
if (this.actor.hover) {
if (this._trayLeftTimeoutId) {
Mainloop.source_remove(this._trayLeftTimeoutId);
this._trayLeftTimeoutId = 0;
return;
}
this._pointerInTray = true;
this._updateState();
} else {
// We wait just a little before hiding the message tray in case the
// user quickly moves the mouse back into it.
let timeout = HIDE_TIMEOUT * 1000;
this._trayLeftTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, this._onTrayLeftTimeout));
}
},
_onTrayLeftTimeout: function() {
@ -575,7 +692,7 @@ MessageTray.prototype = {
// All of the logic for what happens when occurs here; the various
// event handlers merely update variables such as
// "this._pointerInTray", "this._summaryState", etc, and
// 'this._pointerInTray', 'this._summaryState', etc, and
// _updateState() figures out what (if anything) needs to be done
// at the present time.
_updateState: function() {
@ -583,7 +700,7 @@ MessageTray.prototype = {
let notificationsPending = this._notificationQueue.length > 0;
let notificationPinned = this._pointerInTray && !this._pointerInSummary && !this._notificationRemoved;
let notificationExpanded = this._notificationBin.y < 0;
let notificationExpired = (this._notificationTimeoutId == 0 && !this._pointerInTray) || this._notificationRemoved;
let notificationExpired = (this._notificationTimeoutId == 0 && !this._pointerInTray && !this._locked) || this._notificationRemoved;
if (this._notificationState == State.HIDDEN) {
if (notificationsPending)
@ -613,6 +730,22 @@ MessageTray.prototype = {
this._hideSummary();
}
// Summary notification
let haveSummaryNotification = this._hoverSource != null;
let summaryNotificationIsMainNotification = (haveSummaryNotification &&
this._hoverSource.notification == this._notification);
let canShowSummaryNotification = this._summaryState == State.SHOWN;
let wrongSummaryNotification = (haveSummaryNotification &&
this._summaryNotification != this._hoverSource.notification);
if (this._summaryNotificationState == State.HIDDEN) {
if (haveSummaryNotification && !summaryNotificationIsMainNotification && canShowSummaryNotification)
this._showSummaryNotification();
} else if (this._summaryNotificationState == State.SHOWN) {
if (!haveSummaryNotification || !canShowSummaryNotification || wrongSummaryNotification)
this._hideSummaryNotification();
}
// Tray itself
let trayIsVisible = (this._trayState == State.SHOWING ||
this._trayState == State.SHOWN);
@ -649,19 +782,19 @@ MessageTray.prototype = {
_showTray: function() {
let primary = global.get_primary_monitor();
this._tween(this.actor, "_trayState", State.SHOWN,
this._tween(this.actor, '_trayState', State.SHOWN,
{ y: primary.y + primary.height - this.actor.height,
time: ANIMATION_TIME,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
},
_hideTray: function() {
let primary = global.get_primary_monitor();
this._tween(this.actor, "_trayState", State.HIDDEN,
this._tween(this.actor, '_trayState', State.HIDDEN,
{ y: primary.y + primary.height - 1,
time: ANIMATION_TIME,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
},
@ -673,14 +806,23 @@ MessageTray.prototype = {
this._notificationBin.y = this.actor.height;
this._notificationBin.show();
this._tween(this._notificationBin, "_notificationState", State.SHOWN,
this._tween(this._notificationBin, '_notificationState', State.SHOWN,
{ y: 0,
opacity: 255,
time: ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: this._showNotificationCompleted,
onCompleteScope: this
});
if (this._notification.urgent) {
// This will overwrite the y tween, but leave the opacity
// tween, and so the onComplete will remain as well.
this._expandNotification();
}
let [x, y, mods] = global.get_pointer();
this._lastSeenMouseY = y;
},
_showNotificationCompleted: function() {
@ -690,19 +832,37 @@ MessageTray.prototype = {
},
_notificationTimeout: function() {
this._notificationTimeoutId = 0;
this._updateState();
let [x, y, mods] = global.get_pointer();
if (y > this._lastSeenMouseY + 10 && y < this.actor.y) {
// The mouse is moving towards the notification, so don't
// hide it yet. (We just create a new timeout (and destroy
// the old one) each time because the bookkeeping is
// simpler.)
this._lastSeenMouseY = y;
this._notificationTimeoutId =
Mainloop.timeout_add(1000,
Lang.bind(this, this._notificationTimeout));
} else {
this._notificationTimeoutId = 0;
this._updateState();
}
return false;
},
_hideNotification: function() {
this._notification.popIn();
this._tween(this._notificationBin, "_notificationState", State.HIDDEN,
if (this._reExpandNotificationId) {
this._notificationBin.disconnect(this._reExpandNotificationId);
this._reExpandNotificationId = 0;
}
this._tween(this._notificationBin, '_notificationState', State.HIDDEN,
{ y: this.actor.height,
opacity: 0,
time: ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: this._hideNotificationCompleted,
onCompleteScope: this
});
@ -717,11 +877,14 @@ MessageTray.prototype = {
_expandNotification: function() {
if (this._notification && this._notification.popOut()) {
this._tween(this._notificationBin, "_notificationState", State.SHOWN,
this._tween(this._notificationBin, '_notificationState', State.SHOWN,
{ y: this.actor.height - this._notificationBin.height,
time: ANIMATION_TIME,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
if (!this._reExpandNotificationId)
this._reExpandNotificationId = this._notificationBin.connect('notify::height', Lang.bind(this, this._expandNotification));
}
},
@ -729,11 +892,11 @@ MessageTray.prototype = {
let primary = global.get_primary_monitor();
this._summaryBin.opacity = 0;
this._summaryBin.y = this.actor.height;
this._tween(this._summaryBin, "_summaryState", State.SHOWN,
this._tween(this._summaryBin, '_summaryState', State.SHOWN,
{ y: 0,
opacity: 255,
time: ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: this._showSummaryCompleted,
onCompleteScope: this,
onCompleteParams: [withTimeout]
@ -757,11 +920,68 @@ MessageTray.prototype = {
},
_hideSummary: function() {
this._tween(this._summaryBin, "_summaryState", State.HIDDEN,
this._tween(this._summaryBin, '_summaryState', State.HIDDEN,
{ opacity: 0,
time: ANIMATION_TIME,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
this._summaryNeedsToBeShown = false;
},
_showSummaryNotification: function() {
this._summaryNotification = this._hoverSource.notification;
let index = this._notificationQueue.indexOf(this._summaryNotification);
if (index != -1)
this._notificationQueue.splice(index, 1);
this._summaryNotificationBin.child = this._summaryNotification.actor;
this._summaryNotification.popOut();
this._summaryNotificationBin.opacity = 0;
this._summaryNotificationBin.y = this.actor.height;
this._summaryNotificationBin.show();
this._tween(this._summaryNotificationBin, '_summaryNotificationState', State.SHOWN,
{ y: this.actor.height - this._summaryNotificationBin.height,
opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
if (!this._reExpandSummaryNotificationId)
this._reExpandSummaryNotificationId = this._summaryNotificationBin.connect('notify::height', Lang.bind(this, this._reExpandSummaryNotification));
},
_reExpandSummaryNotification: function() {
this._tween(this._summaryNotificationBin, '_summaryNotificationState', State.SHOWN,
{ y: this.actor.height - this._summaryNotificationBin.height,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
},
_hideSummaryNotification: function() {
this._summaryNotification.popIn();
this._tween(this._summaryNotificationBin, '_summaryNotificationState', State.HIDDEN,
{ y: this.actor.height,
opacity: 0,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._hideSummaryNotificationCompleted,
onCompleteScope: this
});
if (this._reExpandSummaryNotificationId) {
this._summaryNotificationBin.disconnect(this._reExpandSummaryNotificationId);
this._reExpandSummaryNotificationId = 0;
}
},
_hideSummaryNotificationCompleted: function() {
this._summaryNotificationBin.hide();
this._summaryNotificationBin.child = null;
this._summaryNotification = null;
}
};

View File

@ -11,8 +11,6 @@ const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Params = imports.misc.params;
const EMPATHY = 'Empathy';
let nextNotificationId = 1;
// Should really be defined in dbus.js
@ -123,10 +121,10 @@ NotificationDaemon.prototype = {
// kill the notification-daemon. pkill is more portable
// than killall, but on Linux at least it won't match if
// you pass more than 15 characters of the process name...
// However, if you use the "-f" flag to match the entire
// However, if you use the '-f' flag to match the entire
// command line, it will work, but we have to be careful
// in that case that we don't match "gedit
// notification-daemon.c" or whatever...
// in that case that we don't match 'gedit
// notification-daemon.c' or whatever...
let p = new Shell.Process({ args: ['pkill', '-f',
'^([^ ]*/)?(notification-daemon|notify-osd)$']});
p.run();
@ -139,46 +137,27 @@ NotificationDaemon.prototype = {
Notify: function(appName, replacesId, icon, summary, body,
actions, hints, timeout) {
let notification, id;
// We associate each application with a source and set the source id to be based on
// the appName. We support application updates by creating a new Notification object
// only if replacesId was not specified or if we no longer have the notification with
// the specified replacesId.
//
// We are planning to add Empathy-specific features in the message tray, but in the
// meantime we handle Empathy notifications received through the notification daemon
// differently from other notifications.
// 1) We display different people sending messages as different sources. So we use
// notification id instead of the appName when creating id for the source.
// 2) We queue notification with different messages to show them one after another,
// rather than replace the notification on the spot. So we create a new Notification
// object each time, disregarding the fact that we might already have another
// notification with the same replacesId.
// Empathy uses replacesId for all the notifications from the same window until the
// notification with that id is dismissed. Notifications from different people in
// different tabs have the same replacesId. So while being closer to the eventual design,
// our special-handling of Empathy notifications is somewhat buggy. The user might end up
// with multiple icons for the same person if the user dismisses the window for that person
// (which doesn't result in removing the icon) or the user might not get the icon for
// the person after a new notification in one of the tabs of the chat window for which
// another person's icon is already displayed.
let source = Main.messageTray.getSource(this._sourceId(appName));
let id = null;
let isEmpathy = appName == EMPATHY;
if (replacesId != 0) {
id = replacesId;
if (!isEmpathy)
notification = this._currentNotifications[id];
} else {
// Filter out notifications from Empathy, since we
// handle that information from telepathyClient.js
if (appName == 'Empathy') {
id = nextNotificationId++;
Mainloop.idle_add(Lang.bind(this,
function () {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
}));
return id;
}
let sourceId = this._sourceId(isEmpathy ? id : appName);
let source = Main.messageTray.getSource(sourceId);
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
// Source may be null if we have never received a notification from
// this app or if all notifications from this app have been acknowledged.
// Source may be null if we have never received a notification
// from this app or if all notifications from this app have
// been acknowledged.
if (source == null) {
source = new Source(sourceId, icon, hints);
source = new Source(this._sourceId(appName), icon, hints);
Main.messageTray.add(source);
source.connect('clicked', Lang.bind(this,
@ -190,7 +169,8 @@ NotificationDaemon.prototype = {
let busProxy = new Bus();
busProxy.GetConnectionUnixProcessIDRemote(sender, function (result, excp) {
let app = Shell.WindowTracker.get_default().get_app_from_pid(result);
source.setApp(app);
if (app)
source.setApp(app);
});
} else {
source.update(icon, hints);
@ -207,14 +187,15 @@ NotificationDaemon.prototype = {
}
}
let notification;
if (replacesId != 0) {
id = replacesId;
notification = this._currentNotifications[id];
}
if (notification == null) {
id = nextNotificationId++;
notification = new MessageTray.Notification(id, source, summary, body, true);
// This will result in us keeping only the latest Empathy notification with the given
// id in this._currentNotifications, which will only affect not being able to close all
// the Empathy notifications with a given id in CloseNotification(). Since this not a
// a likely scenario and this special-casing of Empathy in the notification daemon is
// temporary, it doesn't seem worthwhile to change this._currentNotifications to
// {id, [array of notifications]} just for that case.
this._currentNotifications[id] = notification;
notification.connect('dismissed', Lang.bind(this,
function(n) {
@ -229,10 +210,12 @@ NotificationDaemon.prototype = {
if (actions.length) {
for (let i = 0; i < actions.length - 1; i += 2)
notification.addAction(actions[i], actions[i + 1]);
notification.addButton(actions[i], actions[i + 1]);
notification.connect('action-invoked', Lang.bind(this, this._actionInvoked, source, id));
}
notification.setUrgent(hints.urgency == Urgency.CRITICAL);
source.notify(notification);
return id;
},
@ -268,7 +251,8 @@ NotificationDaemon.prototype = {
_onFocusAppChanged: function() {
let tracker = Shell.WindowTracker.get_default();
Main.messageTray.removeSourceByApp(tracker.focus_app);
if (tracker.focus_app)
Main.messageTray.removeSourceByApp(tracker.focus_app);
},
_actionInvoked: function(notification, action, source, id) {
@ -311,8 +295,6 @@ Source.prototype = {
},
update: function(icon, hints) {
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
this._icon = icon;
this._iconData = hints.icon_data;
this._urgency = hints.urgency;
@ -358,9 +340,6 @@ Source.prototype = {
this.app = app;
if (this._openAppRequested)
this.openApp();
if (app.get_name() == EMPATHY)
this.handleReplacing = false;
},
openApp: function() {

View File

@ -1,6 +1,5 @@
/* -*- 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;
@ -73,7 +72,7 @@ const SHADOW_WIDTH = 6;
const NUMBER_OF_SECTIONS_IN_SEARCH = 2;
const INFO_BAR_HIDE_TIMEOUT = 30;
const INFO_BAR_HIDE_TIMEOUT = 10;
let wideScreen = false;
let displayGridColumnWidth = null;
@ -108,9 +107,6 @@ InfoBar.prototype = {
this._undoCallback = null;
this._undo.connect('clicked', Lang.bind(this, this._onUndoClicked));
this._overviewWasHidden = false;
this._hidingOverviewId = 0;
},
_onUndoClicked: function() {
@ -128,7 +124,6 @@ InfoBar.prototype = {
},
_hide: function() {
this._overviewWasHidden = false;
Tweener.addTween(this.actor,
{ opacity: 0,
transition: 'easeOutQuad',
@ -140,31 +135,15 @@ InfoBar.prototype = {
_onTimeout: function() {
this._timeoutId = 0;
if (this._overviewWasHidden)
this._hide();
this._hide();
return false;
},
_onOverviewHiding: function() {
if (this._timeoutId == 0)
this._hide();
else
this._overviewWasHidden = true;
},
setMessage: function(text, undoCallback, undoLabel) {
if (this._timeoutId)
Mainloop.source_remove(this._timeoutId);
if (this._hidingOverviewId == 0) {
// Set here, because when constructor is called, overview is null.
if (!Main.overview)
return;
// We don't actually use the ID, it's just a way of tracking whether we've hooked up the signal
this._hidingOverviewId = Main.overview.connect('hiding', Lang.bind(this, this._onOverviewHiding));
}
this._timeout = false;
this._overviewWasHidden = false;
this._label.text = text;
@ -251,19 +230,19 @@ Overview.prototype = {
this._coverPane.lower_bottom();
this._workspaces = null;
this.workspaces = null;
},
_onViewChanged: function() {
if (!this.visible)
return;
this._workspaces = this._workspacesManager.workspacesView;
this.workspaces = this._workspacesManager.workspacesView;
// Show new workspacesView
this._group.add_actor(this._workspaces.actor);
this._workspacesBar.raise(this._workspaces.actor);
this._dash.actor.raise(this._workspaces.actor);
this._group.add_actor(this.workspaces.actor);
this._workspacesBar.raise(this.workspaces.actor);
this._dash.actor.raise(this.workspaces.actor);
},
_recalculateGridSizes: function () {
@ -382,7 +361,7 @@ Overview.prototype = {
this._activeDisplayPane.close();
return true;
}));
this._workspaces.actor.opacity = 64;
this.workspaces.actor.opacity = 64;
} else if (pane == this._activeDisplayPane) {
this._activeDisplayPane = null;
if (backgroundEventId != null) {
@ -391,7 +370,7 @@ Overview.prototype = {
}
this._transparentBackground.lower_bottom();
this._paneContainer.hide();
this._workspaces.actor.opacity = 255;
this.workspaces.actor.opacity = 255;
}
}));
},
@ -417,13 +396,13 @@ Overview.prototype = {
// 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();
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 [posX, posY] = this.workspaces.getActiveWorkspacePosition();
let scale = this.getZoomedInScale();
return [- posX * scale, - posY * scale];
@ -458,13 +437,13 @@ Overview.prototype = {
this._workspacesY);
this._workspacesManager.connect('view-changed',
Lang.bind(this, this._onViewChanged));
this._workspaces = this._workspacesManager.workspacesView;
this._group.add_actor(this._workspaces.actor);
this.workspaces = this._workspacesManager.workspacesView;
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);
this._dash.actor.raise(this.workspaces.actor);
this._workspacesBar = this._workspacesManager.controlsBar.actor;
this._workspacesBar.set_position(this._workspacesBarX,
@ -472,7 +451,7 @@ Overview.prototype = {
this._workspacesBar.width = this._workspacesBarWidth;
this._group.add_actor(this._workspacesBar);
this._workspacesBar.raise(this._workspaces.actor);
this._workspacesBar.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
@ -522,7 +501,7 @@ Overview.prototype = {
this._hideInProgress = true;
if (this._activeDisplayPane != null)
this._activeDisplayPane.close();
this._workspaces.hide();
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
@ -567,7 +546,7 @@ Overview.prototype = {
* and will return %null.
*/
getWorkspacesForWindow: function(metaWindow) {
return this._workspaces;
return this.workspaces;
},
//// Private methods ////
@ -585,8 +564,8 @@ Overview.prototype = {
_hideDone: function() {
global.window_group.show();
this._workspaces.destroy();
this._workspaces = null;
this.workspaces.destroy();
this.workspaces = null;
this._workspacesBar.destroy();
this._workspacesBar = null;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
/* -*- 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;
@ -72,7 +71,7 @@ PlaceDeviceInfo.prototype = {
this._mount = mount;
this.name = mount.get_name();
this._lowerName = this.name.toLowerCase();
this.id = "mount:" + mount.get_root().get_uri();
this.id = 'mount:' + mount.get_root().get_uri();
},
iconFactory: function(size) {
@ -93,12 +92,18 @@ PlaceDeviceInfo.prototype = {
if (!this.isRemovable())
return;
this._mount.unmount(0, null, Lang.bind(this, this._removeFinish));
if (this._mount.can_eject())
this._mount.eject(0, null, Lang.bind(this, this._removeFinish));
else
this._mount.unmount(0, null, Lang.bind(this, this._removeFinish));
},
_removeFinish: function(o, res, data) {
try {
this._mount.unmount_finish(res);
if (this._mount.can_eject())
this._mount.eject_finish(res);
else
this._mount.unmount_finish(res);
} catch (e) {
let message = _("Failed to unmount '%s'").format(o.get_name());
Main.overview.infoBar.setMessage(message,
@ -150,7 +155,7 @@ PlacesManager.prototype = {
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
function (size) {
return St.TextureCache.get_default().load_icon_name("applications-internet", size);
return St.TextureCache.get_default().load_icon_name('applications-internet', size);
},
function () {
new Shell.Process({ args: ['nautilus-connect-server'] }).run();
@ -163,7 +168,7 @@ PlacesManager.prototype = {
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.");
log('Cannot create "Network" item, .desktop file not found or corrupt.');
}
}
@ -203,7 +208,7 @@ PlacesManager.prototype = {
this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
this._updateDevices();
this._bookmarksPath = GLib.build_filenamev([GLib.get_home_dir(), ".gtk-bookmarks"]);
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;
@ -335,7 +340,7 @@ PlacesManager.prototype = {
this._isDesktopHome = gconf.get_boolean(DESKTOP_IS_HOME_KEY);
if (this._isDesktopHome)
this._removeById(this._defaultPlaces, "special:desktop");
this._removeById(this._defaultPlaces, 'special:desktop');
else
this._defaultPlaces.splice(this._desktopMenuIndex, 0,
this._desktopMenu);
@ -435,18 +440,9 @@ DashPlaceDisplayItem.prototype = {
}
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this.actor.connect('notify::hover',
Lang.bind(this, this._onHoverChanged));
this.actor.connect('button-press-event',
Lang.bind(this, this._onButtonPress));
this.actor.connect('button-release-event',
Lang.bind(this, this._onButtonRelease));
this.actor._delegate = this;
this._dragStartX = null;
this._dragStartY = null;
this._draggable = DND.makeDraggable(this.actor,
{ manualMode: true });
this._draggable = DND.makeDraggable(this.actor);
},
_onClicked: function(b) {
@ -454,36 +450,6 @@ DashPlaceDisplayItem.prototype = {
Main.overview.hide();
},
_onButtonPress: function(actor, event) {
if (event.get_button() != 1)
return false;
let [stageX, stageY] = event.get_coords();
this._dragStartX = stageX;
this._dragStartY = stageY;
return false;
},
_onButtonRelease: function(actor, event) {
if (event.get_button() != 1)
return false;
this._dragStartX = null;
this._dragStartY = null;
return false;
},
_onHoverChanged: function(button) {
let hover = button.hover;
if (!hover) {
if (button.pressed && this._dragStartX != null) {
button.fake_release();
this._draggable.startDrag(this._dragStartX, this._dragStartY,
global.get_current_time());
}
}
},
getDragActorSource: function() {
return this._icon;
},
@ -510,28 +476,12 @@ DashPlaceDisplay.prototype = {
// look better in that there would be an even number of items left+right,
// but it seems like we want some sort of differentiation between actions
// like "Connect to server..." and regular folders
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
spacing: 4 });
this._leftBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
this.actor.append(this._leftBox, Big.BoxPackFlags.EXPAND);
this._rightBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
this.actor.append(this._rightBox, Big.BoxPackFlags.EXPAND);
this.actor = new St.Table({ style_class: 'places-section',
homogeneous: true });
// Subdivide left into actions and devices
this._actionsBox = new St.BoxLayout({ style_class: 'places-actions',
vertical: true });
this._devBox = new St.BoxLayout({ style_class: 'places-actions',
name: 'placesDevices',
vertical: true });
this._dirsBox = new St.BoxLayout({ style_class: 'places-actions',
vertical: true });
this._leftBox.append(this._actionsBox, Big.BoxPackFlags.NONE);
this._leftBox.append(this._devBox, Big.BoxPackFlags.NONE);
this._rightBox.append(this._dirsBox, Big.BoxPackFlags.NONE);
this._defaultsList = [];
this._bookmarksList = [];
this._mountsList = [];
Main.placesManager.connect('defaults-updated', Lang.bind(this, this._updateDefaults));
Main.placesManager.connect('bookmarks-updated', Lang.bind(this, this._updateBookmarks));
@ -543,27 +493,40 @@ DashPlaceDisplay.prototype = {
},
_updateDefaults: function() {
this._actionsBox.destroy_children();
for (let i = 0; i < this._defaultsList.length; i++)
this._defaultsList[i].destroy();
this._defaultsList = [];
let places = Main.placesManager.getDefaultPlaces();
for (let i = 0; i < places.length; i++)
this._actionsBox.add(new DashPlaceDisplayItem(places[i]).actor);
for (let i = 0; i < places.length; i++) {
this._defaultsList[i] = new DashPlaceDisplayItem(places[i]).actor;
this.actor.add(this._defaultsList[i], {row: i, col: 0});
}
this._updateMounts();
},
_updateMounts: function() {
this._devBox.destroy_children();
for (let i = 0; i < this._mountsList.length; i++)
this._mountsList[i].destroy();
this._mountsList = [];
let places = Main.placesManager.getMounts();
for (let i = 0; i < places.length; i++)
this._devBox.add(new DashPlaceDisplayItem(places[i]).actor);
for (let i = 0; i < places.length; i++) {
this._mountsList[i] = new DashPlaceDisplayItem(places[i]).actor;
this.actor.add(this._mountsList[i], {row: this._defaultsList.length + i, col: 0});
}
},
_updateBookmarks: function() {
this._dirsBox.destroy_children();
for (let i = 0; i < this._bookmarksList.length; i++)
this._bookmarksList[i].destroy();
this._bookmarksList = [];
let places = Main.placesManager.getBookmarks();
for (let i = 0; i < places.length; i ++)
this._dirsBox.add(new DashPlaceDisplayItem(places[i]).actor);
for (let i = 0; i < places.length; i ++) {
this._bookmarksList[i] = new DashPlaceDisplayItem(places[i]).actor;
this.actor.add(this._bookmarksList[i], {row: i, col: 1});
}
}
};

View File

@ -1,6 +1,5 @@
/* -*- 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 GLib = imports.gi.GLib;
@ -52,7 +51,7 @@ CommandCompleter.prototype = {
this._paths[i] = file.get_path();
this._monitors[i] = file.monitor_directory(Gio.FileMonitorFlags.NONE, null);
if (this._monitors[i] != null) {
this._monitors[i].connect("changed", Lang.bind(this, this._onChanged));
this._monitors[i].connect('changed', Lang.bind(this, this._onChanged));
}
}
this._paths = this._paths.filter(function(a) {
@ -133,7 +132,7 @@ CommandCompleter.prototype = {
},
getCompletion: function(text) {
let common = "";
let common = '';
let notInit = true;
if (!this._valid) {
this._update(0);
@ -146,7 +145,7 @@ CommandCompleter.prototype = {
break;
}
if (k == 0)
return "";
return '';
return s1.substr(0, k);
}
function _hasPrefix(s1, prefix) {
@ -214,7 +213,7 @@ RunDialog.prototype = {
// hidden then show it in show()
this._group = new Clutter.Group({ visible: false,
x: 0, y: 0 });
global.stage.add_actor(this._group);
Main.uiGroup.add_actor(this._group);
let lightbox = new Lightbox.Lightbox(this._group, true);
@ -268,8 +267,8 @@ RunDialog.prototype = {
this._setCommandFromHistory(this._historyIndex--);
return true;
}
if (symbol == Clutter.Return) {
if (e.get_state() & Clutter.ModifierType.CONTROL_MASK)
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
if (Shell.get_event_state(e) & Clutter.ModifierType.CONTROL_MASK)
this._run(o.get_text(), true);
else
this._run(o.get_text(), false);
@ -330,8 +329,10 @@ RunDialog.prototype = {
_run : function(input, inTerminal) {
let command = input;
this._history.push(input);
this._saveHistory();
if (this._history.length > 0 && this._history[this._history.length - 1] != input) {
this._history.push(input);
this._saveHistory();
}
this._commandError = false;
let f;
@ -371,7 +372,7 @@ RunDialog.prototype = {
// We are only interested in the actual error, so parse
//that out.
let m = /.+\((.+)\)/.exec(e);
let errorStr = _("Execution of '%s' failed:").format(command) + "\n" + m[1];
let errorStr = _("Execution of '%s' failed:").format(command) + '\n' + m[1];
this._errorMessage.set_text(errorStr);
this._errorBox.show();

261
js/ui/scripting.js Normal file
View File

@ -0,0 +1,261 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
// This module provides functionality for driving the shell user interface
// in an automated fashion. The primary current use case for this is
// automated performance testing (see runPerfScript()), but it could
// be applied to other forms of automation, such as testing for
// correctness as well.
//
// When scripting an automated test we want to make a series of calls
// in a linear fashion, but we also want to be able to let the main
// loop run so actions can finish. For this reason we write the script
// as a generator function that yields when it want to let the main
// loop run.
//
// yield Scripting.sleep(1000);
// main.overview.show();
// yield Scripting.waitLeisure();
//
// While it isn't important to the person writing the script, the actual
// yielded result is a function that the caller uses to provide the
// callback for resuming the script.
/**
* sleep:
* @milliseconds: number of milliseconds to wait
*
* Used within an automation script to pause the the execution of the
* current script for the specified amount of time. Use as
* 'yield Scripting.sleep(500);'
*/
function sleep(milliseconds) {
let cb;
Mainloop.timeout_add(milliseconds, function() {
if (cb)
cb();
return false;
});
return function(callback) {
cb = callback;
};
}
/**
* waitLeisure:
*
* Used within an automation script to pause the the execution of the
* current script until the shell is completely idle. Use as
* 'yield Scripting.waitLeisure();'
*/
function waitLeisure() {
let cb;
global.run_at_leisure(function() {
if (cb)
cb();
});
return function(callback) {
cb = callback;
};
}
/**
* defineScriptEvent
* @name: The event will be called script.<name>
* @description: Short human-readable description of the event
*
* Convenience function to define a zero-argument performance event
* within the 'script' namespace that is reserved for events defined locally
* within a performance automation script
*/
function defineScriptEvent(name, description) {
Shell.PerfLog.get_default().define_event("script." + name,
description,
"");
}
/**
* scriptEvent
* @name: Name registered with defineScriptEvent()
*
* Convenience function to record a script-local performance event
* previously defined with defineScriptEvent
*/
function scriptEvent(name) {
Shell.PerfLog.get_default().event("script." + name);
}
/**
* collectStatistics
*
* Convenience function to trigger statistics collection
*/
function collectStatistics() {
Shell.PerfLog.get_default().collect_statistics();
}
function _step(g, finish, onError) {
try {
let waitFunction = g.next();
waitFunction(function() {
_step(g, finish, onError);
});
} catch (err if err instanceof StopIteration) {
if (finish)
finish();
} catch (err) {
if (onError)
onError(err);
}
}
function _collect(scriptModule, outputFile) {
let eventHandlers = {};
for (let f in scriptModule) {
let m = /([A-Za-z]+)_([A-Za-z]+)/.exec(f);
if (m)
eventHandlers[m[1] + "." + m[2]] = scriptModule[f];
}
Shell.PerfLog.get_default().replay(
function(time, eventName, signature, arg) {
if (eventName in eventHandlers)
eventHandlers[eventName](time, arg);
});
if ('finish' in scriptModule)
scriptModule.finish();
if (outputFile) {
let f = Gio.file_new_for_path(outputFile);
let raw = f.replace(null, false,
Gio.FileCreateFlags.NONE,
null);
let out = Gio.BufferedOutputStream.new_sized (raw, 4096);
Shell.write_string_to_stream (out, "{\n");
Shell.write_string_to_stream(out, '"events":\n');
Shell.PerfLog.get_default().dump_events(out);
let monitors = global.get_monitors()
let primary = global.get_primary_monitor()
Shell.write_string_to_stream(out, ',\n"monitors":\n[');
for (let i = 0; i < monitors.length; i++) {
let monitor = monitors[i];
let is_primary = (monitor.x == primary.x &&
monitor.y == primary.y &&
monitor.width == primary.width &&
monitor.height == primary.height);
if (i != 0)
Shell.write_string_to_stream(out, ', ');
Shell.write_string_to_stream(out, '"%s%dx%d+%d+%d"'.format(is_primary ? "*" : "",
monitor.width, monitor.height,
monitor.x, monitor.y));
}
Shell.write_string_to_stream(out, ' ]');
Shell.write_string_to_stream(out, ',\n"metrics":\n[ ');
let first = true;
for (let name in scriptModule.METRICS) {
let metric = scriptModule.METRICS[name];
if (!first)
Shell.write_string_to_stream(out, ',\n ');
first = false;
Shell.write_string_to_stream(out,
'{ "name": ' + JSON.stringify(name) + ',\n' +
' "description": ' + JSON.stringify(metric.description) + ',\n' +
' "units": ' + JSON.stringify(metric.units) + ',\n' +
' "value": ' + JSON.stringify(metric.value) + ' }');
}
Shell.write_string_to_stream(out, ' ]');
Shell.write_string_to_stream (out, ',\n"log":\n');
Shell.PerfLog.get_default().dump_log(out);
Shell.write_string_to_stream (out, '\n}\n');
out.close(null);
} else {
let metrics = [];
for (let metric in scriptModule.METRICS)
metrics.push(metric);
metrics.sort();
print ('------------------------------------------------------------');
for (let i = 0; i < metrics.length; i++) {
let metric = metrics[i];
print ('# ' + scriptModule.METRIC_DESCRIPTIONS[metric]);
print (metric + ': ' + scriptModule.METRICS[metric]);
}
print ('------------------------------------------------------------');
}
}
/**
* runPerfScript
* @scriptModule: module object with run and finish functions
* and event handlers
*
* Runs a script for automated collection of performance data. The
* script is defined as a Javascript module with specified contents.
*
* First the run() function within the module will be called as a
* generator to automate a series of actions. These actions will
* trigger performance events and the script can also record its
* own performance events.
*
* Then the recorded event log is replayed using handler functions
* within the module. The handler for the event 'foo.bar' is called
* foo_bar().
*
* Finally if the module has a function called finish(), that will
* be called.
*
* The event handler and finish functions are expected to fill in
* metrics to an object within the module called METRICS. Each
* property of this object represents an individual metric. The
* name of the property is the name of the metric, the value
* of the property is an object with the following properties:
*
* description: human readable description of the metric
* units: a string representing the units of the metric. It has
* the form '<unit> <unit> ... / <unit> / <unit> ...'. Certain
* unit values are recognized: s, ms, us, B, KiB, MiB. Other
* values can appear but are uninterpreted. Examples 's',
* '/ s', 'frames', 'frames / s', 'MiB / s / frame'
* value: computed value of the metric
*
* The resulting metrics will be written to @outputFile as JSON, or,
* if @outputFile is not provided, logged.
*
* After running the script and collecting statistics from the
* event log, GNOME Shell will exit.
**/
function runPerfScript(scriptModule, outputFile) {
Shell.PerfLog.get_default().set_enabled(true);
let g = scriptModule.run();
_step(g,
function() {
_collect(scriptModule, outputFile);
Meta.exit(Meta.ExitCode.SUCCESS);
},
function(err) {
log("Script failed: " + err + "\n" + err.stack);
Meta.exit(Meta.ExitCode.ERROR);
});
}

View File

@ -40,7 +40,7 @@ SearchResultDisplay.prototype = {
* The terms are useful for search match highlighting.
*/
renderResults: function(results, terms) {
throw new Error("not implemented");
throw new Error('Not implemented');
},
/**
@ -67,7 +67,7 @@ SearchResultDisplay.prototype = {
* Returns: The number of actors visible.
*/
getVisibleResultCount: function() {
throw new Error("not implemented");
throw new Error('Not implemented');
},
/**
@ -79,14 +79,14 @@ SearchResultDisplay.prototype = {
* available.
*/
selectIndex: function() {
throw new Error("not implemented");
throw new Error('Not implemented');
},
/**
* Activate the currently selected search result.
*/
activateSelected: function() {
throw new Error("not implemented");
throw new Error('Not implemented');
}
};
@ -127,7 +127,7 @@ SearchProvider.prototype = {
* or network queries.
*/
getInitialResultSet: function(terms) {
throw new Error("not implemented");
throw new Error('Not implemented');
},
/**
@ -144,7 +144,7 @@ SearchProvider.prototype = {
* result set, rather than possibly performing a full re-query.
*/
getSubsearchResultSet: function(previousResults, newTerms) {
throw new Error("not implemented");
throw new Error('Not implemented');
},
/**
@ -155,7 +155,7 @@ SearchProvider.prototype = {
* properties which describe the given search result.
*/
getResultMeta: function(id) {
throw new Error("not implemented");
throw new Error('Not implemented');
},
/**
@ -194,7 +194,7 @@ SearchProvider.prototype = {
* Called when the user chooses a given result.
*/
activateResult: function(id) {
throw new Error("not implemented");
throw new Error('Not implemented');
},
/**
@ -205,7 +205,7 @@ SearchProvider.prototype = {
* displaying search results for that item type.
*/
expandSearch: function(terms) {
throw new Error("not implemented");
throw new Error('Not implemented');
}
};
Signals.addSignalMethods(SearchProvider.prototype);
@ -238,7 +238,7 @@ SearchSystem.prototype = {
},
updateSearch: function(searchString) {
searchString = searchString.replace(/^\s+/g, "").replace(/\s+$/g, "");
searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, '');
if (searchString == '')
return null;

View File

@ -8,16 +8,16 @@ const Mainloop = imports.mainloop;
const Main = imports.ui.main;
const GnomeShellIface = {
name: "org.gnome.Shell",
methods: [{ name: "Eval",
inSignature: "s",
outSignature: "bs"
name: 'org.gnome.Shell',
methods: [{ name: 'Eval',
inSignature: 's',
outSignature: 'bs'
}
],
signals: [],
properties: [{ name: "OverviewActive",
signature: "b",
access: "readwrite" }]
properties: [{ name: 'OverviewActive',
signature: 'b',
access: 'readwrite' }]
};
function GnomeShell() {
@ -50,7 +50,7 @@ GnomeShell.prototype = {
returnValue = JSON.stringify(eval(code));
// A hack; DBus doesn't have null/undefined
if (returnValue == undefined)
returnValue = "";
returnValue = '';
success = true;
} catch (e) {
returnValue = JSON.stringify(e);

View File

@ -1,264 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const Tweener = imports.ui.tweener;
const Widget = imports.ui.widget;
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
// (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();
}
Sidebar.prototype = {
_init : function() {
// 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
// WidgetBox corners on the screen edge side.)
this.actor = new Clutter.Group({ x: -WidgetBox.WIDGETBOX_PADDING,
y: Panel.PANEL_HEIGHT,
width: SIDEBAR_EXPANDED_WIDTH });
// The actual widgets go into a Big.Box inside this.actor. The
// box's width will vary during the expand/collapse animations,
// but this.actor's width will remain constant until we adjust
// it at the end of the animation, because we don't want the
// wm strut to move and cause windows to move multiple times
// during the animation.
this.box = new Big.Box ({ padding_top: SIDEBAR_PADDING,
padding_bottom: SIDEBAR_PADDING,
padding_right: 0,
padding_left: 0,
spacing: SIDEBAR_SPACING });
this.actor.add_actor(this.box);
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._hidden = false;
this._hideTimeoutId = 0;
this._widgets = [];
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));
this._gconf.connect('changed::sidebar/autohide',
Lang.bind(this, this._autohideChanged));
this.actor.connect('enter-event',Lang.bind(this,this._restoreHidden));
this.actor.connect('leave-event',Lang.bind(this,this._startHideTimeout));
this._adjustPosition();
this._autohideChanged();
},
addWidget: function(widget) {
let widgetBox;
try {
widgetBox = new WidgetBox.WidgetBox(widget, this._expanded);
} catch(e) {
logError(e, "Failed to add widget '" + widget + "'");
return;
}
this.box.append(widgetBox.actor, Big.BoxPackFlags.NONE);
this._widgets.push(widgetBox);
this._adjustPosition();
},
_adjustPosition: function() {
let primary=global.get_primary_monitor();
this.actor.y = Math.floor(Math.max(primary.y + Panel.PANEL_HEIGHT,primary.height/2 - this.actor.height/2));
this.actor.x = primary.x;
},
_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);
},
_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();
},
_autohideChanged: function() {
let autohide = this._gconf.get_boolean("sidebar/autohide");
if (autohide == this._autohide)
return;
this._autohide = autohide;
if (autohide) {
this.actor.set_reactive(true);
this._hide();
} else {
this.actor.set_reactive(false);
this._restore();
}
},
_expand: function() {
this._expanded = true;
for (let i = 0; i < this._widgets.length; i++)
this._widgets[i].expand();
// Updated the strut/stage area after the animation completes
Tweener.addTween(this, { time: WidgetBox.ANIMATION_TIME,
onComplete: function () {
this.actor.width = SIDEBAR_EXPANDED_WIDTH;
} });
},
_collapse: function() {
this._expanded = false;
for (let i = 0; i < this._widgets.length; i++)
this._widgets[i].collapse();
// Update the strut/stage area after the animation completes
Tweener.addTween(this, { time: WidgetBox.ANIMATION_TIME,
onComplete: Lang.bind(this, function () {
this.actor.width = SIDEBAR_COLLAPSED_WIDTH;
}) });
},
_hide: function() {
if (!this._expanded) {
this._hidden = true;
for (let i = 0; i < this._widgets.length; i++)
this._widgets[i].hide();
// Update the strut/stage area after the animation completes
Tweener.addTween(this, { time: WidgetBox.ANIMATION_TIME / 2,
onComplete: Lang.bind(this, function () {
this.actor.width = Math.floor(WidgetBox.WIDGETBOX_PADDING * 2 + SIDEBAR_PADDING);
}) });
}
},
_restore: function() {
if (!this._expanded) {
this._hidden = false;
for (let i = 0; i < this._widgets.length; i++)
this._widgets[i].restore();
// Updated the strut/stage area after the animation completes
Tweener.addTween(this, { time: WidgetBox.ANIMATION_TIME / 2,
onComplete: function () {
this.actor.width = SIDEBAR_COLLAPSED_WIDTH;
} });
}
},
_restoreHidden: function(actor, event) {
this._cancelHideTimeout();
if (this._hidden)
this._restore();
return false;
},
_startHideTimeout: function(actor, event) {
if (!this._expanded) {
this._cancelHideTimeout();
this._hideTimeoutId = Mainloop.timeout_add_seconds(2, Lang.bind(this,this._hideTimeoutFunc));
}
return false;
},
_cancelHideTimeout: function() {
if (this._hideTimeoutId != 0) {
Mainloop.source_remove(this._hideTimeoutId);
this._hideTimeoutId = 0;
}
},
_hideTimeoutFunc: function() {
this._hide();
return false;
},
destroy: function() {
this.hide();
for (let i = 0; i < this._widgets.length; i++)
this._widgets[i].destroy();
this.actor.destroy();
}
};
const LEFT_DOUBLE_ARROW = "\u00AB";
const RIGHT_DOUBLE_ARROW = "\u00BB";
function ToggleWidget() {
this._init();
}
ToggleWidget.prototype = {
__proto__ : Widget.Widget.prototype,
_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, 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, this._expand));
},
_collapse : function () {
this._gconf.set_boolean ("sidebar/expanded", false);
},
_expand : function () {
this._gconf.set_boolean ("sidebar/expanded", true);
}
};

View File

@ -1,16 +1,14 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const DBus = imports.dbus;
const Gdm = imports.gi.Gdm;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const GnomeSession = imports.misc.gnomeSession;
const Panel = imports.ui.panel;
// Adapted from gdm/gui/user-switch-applet/applet.c
@ -18,23 +16,26 @@ const Panel = imports.ui.panel;
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
// Copyright (C) 2008,2009 Red Hat, Inc.
const SIDEBAR_VISIBLE_KEY = 'sidebar/visible';
function StatusMenu() {
function StatusMenuButton() {
this._init();
}
StatusMenu.prototype = {
StatusMenuButton.prototype = {
__proto__: Panel.PanelMenuButton.prototype,
_init: function() {
Panel.PanelMenuButton.prototype._init.call(this, St.Align.START);
let box = new St.BoxLayout({ name: 'panelStatusMenu' });
this.actor.set_child(box);
this._gdm = Gdm.UserManager.ref_default();
this._user = this._gdm.get_user(GLib.get_user_name());
this._presence = new GnomeSessionPresence();
this._presence = new GnomeSession.Presence();
this.actor = new St.BoxLayout({ name: 'statusMenu' });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._iconBox = new St.Bin();
this.actor.add(this._iconBox, { y_align: St.Align.MIDDLE });
box.add(this._iconBox, { y_align: St.Align.MIDDLE, y_fill: false });
let textureCache = St.TextureCache.get_default();
// FIXME: these icons are all wrong (likewise in createSubMenu)
@ -47,7 +48,7 @@ StatusMenu.prototype = {
this._presence.getStatus(Lang.bind(this, this._updatePresenceIcon));
this._name = new St.Label({ text: this._user.get_real_name() });
this.actor.add(this._name, { expand: true, y_align: St.Align.MIDDLE });
box.add(this._name, { y_align: St.Align.MIDDLE, y_fill: false });
this._userNameChangedId = this._user.connect('notify::display-name', Lang.bind(this, this._updateUserName));
this._createSubMenu();
@ -67,110 +68,70 @@ StatusMenu.prototype = {
_updateSwitchUser: function() {
let users = this._gdm.list_users();
if (users.length > 1)
this._loginScreenItem.show();
this._loginScreenItem.actor.show();
else
this._loginScreenItem.hide();
this._loginScreenItem.actor.hide();
},
_updatePresenceIcon: function(presence, status) {
if (status == GnomeSessionPresenceStatus.AVAILABLE)
if (status == GnomeSession.PresenceStatus.AVAILABLE)
this._iconBox.child = this._availableIcon;
else if (status == GnomeSessionPresenceStatus.BUSY)
else if (status == GnomeSession.PresenceStatus.BUSY)
this._iconBox.child = this._busyIcon;
else if (status == GnomeSessionPresenceStatus.INVISIBLE)
else if (status == GnomeSession.PresenceStatus.INVISIBLE)
this._iconBox.child = this._invisibleIcon;
else
this._iconBox.child = this._idleIcon;
},
// The menu
_createImageMenuItem: function(label, iconName, forceIcon) {
let image = new Gtk.Image();
let item = new Gtk.ImageMenuItem({ label: label,
image: image,
always_show_image: forceIcon == true });
item.connect('style-set', Lang.bind(this,
function() {
image.set_from_icon_name(iconName, Gtk.IconSize.MENU);
}));
return item;
},
_createSubMenu: function() {
this._menu = new Gtk.Menu();
this._menu.connect('deactivate', Lang.bind(this, function() { this.emit('deactivated'); }));
let item;
item = this._createImageMenuItem(_("Available"), 'gtk-yes', true);
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSessionPresenceStatus.AVAILABLE));
this._menu.append(item);
item.show();
item = new Panel.PanelImageMenuItem(_("Available"), 'gtk-yes', true);
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.AVAILABLE));
this.menu.addMenuItem(item);
item = this._createImageMenuItem(_("Busy"), 'gtk-no', true);
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSessionPresenceStatus.BUSY));
this._menu.append(item);
item.show();
item = new Panel.PanelImageMenuItem(_("Busy"), 'gtk-no', true);
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.BUSY));
this.menu.addMenuItem(item);
item = this._createImageMenuItem(_("Invisible"), 'gtk-close', true);
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSessionPresenceStatus.INVISIBLE));
this._menu.append(item);
item.show();
item = new Panel.PanelImageMenuItem(_("Invisible"), 'gtk-close', true);
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.INVISIBLE));
this.menu.addMenuItem(item);
item = new Gtk.SeparatorMenuItem();
this._menu.append(item);
item.show();
item = new Panel.PanelSeparatorMenuItem();
this.menu.addMenuItem(item);
item = this._createImageMenuItem(_("Account Information..."), 'user-info');
item = new Panel.PanelImageMenuItem(_("Account Information..."), 'user-info');
item.connect('activate', Lang.bind(this, this._onAccountInformationActivate));
this._menu.append(item);
item.show();
this.menu.addMenuItem(item);
let gconf = Shell.GConf.get_default();
item = new Gtk.CheckMenuItem({ label: _("Sidebar"),
active: gconf.get_boolean(SIDEBAR_VISIBLE_KEY) });
item.connect('activate', Lang.bind(this,
function() {
gconf.set_boolean(SIDEBAR_VISIBLE_KEY, this._sidebarItem.active);
}));
this._menu.append(item);
item.show();
this._sidebarItem = item;
item = this._createImageMenuItem(_("System Preferences..."), 'preferences-desktop');
item = new Panel.PanelImageMenuItem(_("System Preferences..."), 'preferences-desktop');
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
this._menu.append(item);
item.show();
this.menu.addMenuItem(item);
item = new Gtk.SeparatorMenuItem();
this._menu.append(item);
item.show();
item = new Panel.PanelSeparatorMenuItem();
this.menu.addMenuItem(item);
item = this._createImageMenuItem(_("Lock Screen"), 'system-lock-screen');
item = new Panel.PanelImageMenuItem(_("Lock Screen"), 'system-lock-screen');
item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
this._menu.append(item);
item.show();
this.menu.addMenuItem(item);
item = this._createImageMenuItem(_("Switch User"), 'system-users');
item = new Panel.PanelImageMenuItem(_("Switch User"), 'system-users');
item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
this._menu.append(item);
item.show();
this.menu.addMenuItem(item);
this._loginScreenItem = item;
item = this._createImageMenuItem(_("Log Out..."), 'system-log-out');
item = new Panel.PanelImageMenuItem(_("Log Out..."), 'system-log-out');
item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
this._menu.append(item);
item.show();
this.menu.addMenuItem(item);
item = this._createImageMenuItem(_("Shut Down..."), 'system-shutdown');
item = new Panel.PanelImageMenuItem(_("Shut Down..."), 'system-shutdown');
item.connect('activate', Lang.bind(this, this._onShutDownActivate));
this._menu.append(item);
item.show();
this.menu.addMenuItem(item);
},
_setPresenceStatus: function(item, status) {
_setPresenceStatus: function(item, event, status) {
this._presence.setStatus(status);
},
@ -205,98 +166,5 @@ StatusMenu.prototype = {
// on failure
let p = new Shell.Process({'args' : args});
p.run();
},
// shell_status_menu_toggle:
// @event: event causing the toggle
//
// If the menu is not currently up, pops it up. Otherwise, hides it.
// Popping up may fail if another grab is already active; check with
// isActive().
toggle: function(event) {
if (this._menu.visible)
this._menu.popdown();
else {
// We don't want to overgrab a Mutter grab with the grab
// that GTK+ uses on menus.
if (global.display_is_grabbed())
return;
let [menuWidth, menuHeight] = this._menu.get_size_request ();
let panel;
for (panel = this.actor; panel; panel = panel.get_parent()) {
if (panel._delegate instanceof Panel.Panel)
break;
}
let [panelX, panelY] = panel.get_transformed_position();
let [panelWidth, panelHeight] = panel.get_transformed_size();
let menuX;
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
menuX = panelX;
} else {
menuX = Math.round(panelX + panelWidth - menuWidth);
}
let menuY = Math.round(panelY + panelHeight);
Shell.popup_menu(this._menu, event.get_button(), event.get_time(),
menuX, menuY);
}
},
// isActive:
//
// Gets whether the menu is currently popped up
//
// Return value: %true if the menu is currently popped up
isActive: function() {
return this._menu.visible;
}
};
Signals.addSignalMethods(StatusMenu.prototype);
const GnomeSessionPresenceIface = {
name: 'org.gnome.SessionManager.Presence',
methods: [{ name: 'SetStatus',
inSignature: 'u' }],
properties: [{ name: 'status',
signature: 'u',
access: 'readwrite' }],
signals: [{ name: 'StatusChanged',
inSignature: 'u' }]
};
const GnomeSessionPresenceStatus = {
AVAILABLE: 0,
INVISIBLE: 1,
BUSY: 2,
IDLE: 3
};
function GnomeSessionPresence() {
this._init();
}
GnomeSessionPresence.prototype = {
_init: function() {
DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager/Presence', this);
this.connect('StatusChanged', Lang.bind(this, function (proxy, status) { this.status = status; }));
},
getStatus: function(callback) {
this.GetRemote('status', Lang.bind(this,
function(status, ex) {
if (!ex)
callback(this, status);
}));
},
setStatus: function(status) {
this.SetStatusRemote(status);
}
};
DBus.proxifyPrototype(GnomeSessionPresence.prototype, GnomeSessionPresenceIface);

686
js/ui/telepathyClient.js Normal file
View File

@ -0,0 +1,686 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const DBus = imports.dbus;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Telepathy = imports.misc.telepathy;
let contactManager;
let channelDispatcher;
// See Notification.appendMessage
const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes
const SCROLLBACK_RECENT_LENGTH = 20;
const SCROLLBACK_IDLE_LENGTH = 5;
// A 'Qualified_Property_Value_Map' that represents a single-user
// text-based chat.
let singleUserTextChannel = {};
singleUserTextChannel[Telepathy.CHANNEL_NAME + '.ChannelType'] = Telepathy.CHANNEL_TEXT_NAME;
singleUserTextChannel[Telepathy.CHANNEL_NAME + '.TargetHandleType'] = Telepathy.HandleType.CONTACT;
// Some protocols only support 'multi-user' chats, and single-user
// chats are just treated as multi-user chats with only one other
// participant. Telepathy uses HandleType.NONE for all chats in these
// protocols; there's no good way for us to tell if the channel is
// single- or multi-user.
let oneOrMoreUserTextChannel = {};
oneOrMoreUserTextChannel[Telepathy.CHANNEL_NAME + '.ChannelType'] = Telepathy.CHANNEL_TEXT_NAME;
oneOrMoreUserTextChannel[Telepathy.CHANNEL_NAME + '.TargetHandleType'] = Telepathy.HandleType.NONE;
// The (non-chat) channel indicating the users whose presence
// information we subscribe to
let subscribedContactsChannel = {};
subscribedContactsChannel[Telepathy.CHANNEL_NAME + '.ChannelType'] = Telepathy.CHANNEL_CONTACT_LIST_NAME;
subscribedContactsChannel[Telepathy.CHANNEL_NAME + '.TargetHandleType'] = Telepathy.HandleType.LIST;
subscribedContactsChannel[Telepathy.CHANNEL_NAME + '.TargetID'] = 'subscribe';
// This is GNOME Shell's implementation of the Telepathy 'Client'
// interface. Specifically, the shell is a Telepathy 'Observer', which
// lets us see messages even if they belong to another app (eg,
// Empathy).
function Client() {
this._init();
};
Client.prototype = {
_init : function() {
let name = Telepathy.CLIENT_NAME + '.GnomeShell';
DBus.session.exportObject(Telepathy.nameToPath(name), this);
DBus.session.acquire_name(name, DBus.SINGLE_INSTANCE,
function (name) { /* FIXME: acquired */ },
function (name) { /* FIXME: lost */ });
this._accounts = {};
this._sources = {};
contactManager = new ContactManager();
contactManager.connect('presence-changed', Lang.bind(this, this._presenceChanged));
channelDispatcher = new Telepathy.ChannelDispatcher(DBus.session,
Telepathy.CHANNEL_DISPATCHER_NAME,
Telepathy.nameToPath(Telepathy.CHANNEL_DISPATCHER_NAME));
// Acquire existing connections. (Needed to make things work
// through a restart.)
let accountManager = new Telepathy.AccountManager(DBus.session,
Telepathy.ACCOUNT_MANAGER_NAME,
Telepathy.nameToPath(Telepathy.ACCOUNT_MANAGER_NAME));
accountManager.GetRemote('ValidAccounts', Lang.bind(this,
function (accounts, err) {
if (!accounts)
return;
for (let i = 0; i < accounts.length; i++)
this._gotAccount(accounts[i]);
}));
accountManager.connect('AccountValidityChanged', Lang.bind(this, this._accountValidityChanged));
},
_accountValidityChanged: function(accountManager, accountPath, valid) {
if (!valid) {
delete this._accounts[accountPath];
// We don't need to clean up connections, sources, etc; they'll
// get Closed and cleaned up independently.
} else
this._gotAccount(accountPath);
},
_gotAccount: function(accountPath) {
let account = new Telepathy.Account(DBus.session,
Telepathy.ACCOUNT_MANAGER_NAME,
accountPath);
this._accounts[accountPath] = account;
account.GetRemote('Connection', Lang.bind(this,
function (connPath, err) {
if (!connPath || connPath == '/')
return;
let connReq = new Telepathy.ConnectionRequests(DBus.session,
Telepathy.pathToName(connPath),
connPath);
connReq.GetRemote('Channels', Lang.bind(this,
function(channels, err) {
if (!channels)
return;
this._addChannels(accountPath, connPath, channels);
}));
contactManager.addConnection(connPath);
}));
},
get Interfaces() {
return [ Telepathy.CLIENT_OBSERVER_NAME ];
},
get ObserverChannelFilter() {
return [ singleUserTextChannel, oneOrMoreUserTextChannel ];
},
ObserveChannels: function(accountPath, connPath, channels,
dispatchOperation, requestsSatisfied,
observerInfo) {
this._addChannels(accountPath, connPath, channels);
},
_addChannels: function(accountPath, connPath, channelDetailsList) {
for (let i = 0; i < channelDetailsList.length; i++) {
let [channelPath, props] = channelDetailsList[i];
// If this is being called from the startup code then it
// won't have passed through our filters, so we need to
// check the channel/targetHandle type ourselves.
let channelType = props[Telepathy.CHANNEL_NAME + '.ChannelType'];
if (channelType != Telepathy.CHANNEL_TEXT_NAME)
continue;
let targetHandleType = props[Telepathy.CHANNEL_NAME + '.TargetHandleType'];
if (targetHandleType != Telepathy.HandleType.CONTACT &&
targetHandleType != Telepathy.HandleType.NONE)
continue;
let targetHandle = props[Telepathy.CHANNEL_NAME + '.TargetHandle'];
let targetId = props[Telepathy.CHANNEL_NAME + '.TargetID'];
if (this._sources[connPath + ':' + targetHandle])
continue;
let source = new Source(accountPath, connPath, channelPath,
targetHandle, targetHandleType, targetId);
this._sources[connPath + ':' + targetHandle] = source;
source.connect('destroy', Lang.bind(this,
function() {
delete this._sources[connPath + ':' + targetHandle];
}));
}
},
_presenceChanged: function(contactManager, connPath, handle,
type, message) {
let source = this._sources[connPath + ':' + handle];
if (!source)
return;
source.setPresence(type, message);
}
};
DBus.conformExport(Client.prototype, Telepathy.ClientIface);
DBus.conformExport(Client.prototype, Telepathy.ClientObserverIface);
function ContactManager() {
this._init();
};
ContactManager.prototype = {
_init: function() {
this._connections = {};
// Note that if we changed this to '/telepathy/avatars' then
// we would share cache files with empathy. But since this is
// not documented/guaranteed, it seems a little sketchy
this._cacheDir = GLib.get_user_cache_dir() + '/gnome-shell/avatars';
},
addConnection: function(connPath) {
let info = this._connections[connPath];
if (info)
return info;
info = {};
// Figure out the cache subdirectory for this connection by
// parsing the connection manager name (eg, 'gabble') and
// protocol name (eg, 'jabber') from the Connection's path.
// Telepathy requires the D-Bus path for a connection to have
// a specific form, and explicitly says that clients are
// allowed to parse it.
let match = connPath.match(/\/org\/freedesktop\/Telepathy\/Connection\/([^\/]*\/[^\/]*)\/.*/);
if (!match)
throw new Error('Could not parse connection path ' + connPath);
info.cacheDir = this._cacheDir + '/' + match[1];
GLib.mkdir_with_parents(info.cacheDir, 0700);
// info.names[handle] is @handle's real name
// info.tokens[handle] is the token for @handle's avatar
info.names = {};
info.tokens = {};
// info.icons[handle] is an array of the icon actors currently
// being displayed for @handle. These will be updated
// automatically if @handle's avatar changes.
info.icons = {};
let connName = Telepathy.pathToName(connPath);
info.connectionAvatars = new Telepathy.ConnectionAvatars(DBus.session, connName, connPath);
info.updatedId = info.connectionAvatars.connect(
'AvatarUpdated', Lang.bind(this, this._avatarUpdated));
info.retrievedId = info.connectionAvatars.connect(
'AvatarRetrieved', Lang.bind(this, this._avatarRetrieved));
info.connectionContacts = new Telepathy.ConnectionContacts(DBus.session, connName, connPath);
info.connectionPresence = new Telepathy.ConnectionSimplePresence(DBus.session, connName, connPath);
info.presenceChangedId = info.connectionPresence.connect(
'PresencesChanged', Lang.bind(this, this._presencesChanged));
let conn = new Telepathy.Connection(DBus.session, connName, connPath);
info.statusChangedId = conn.connect('StatusChanged', Lang.bind(this,
function (status, reason) {
if (status == Telepathy.ConnectionStatus.DISCONNECTED)
this._removeConnection(conn);
}));
let connReq = new Telepathy.ConnectionRequests(DBus.session,
connName, connPath);
connReq.EnsureChannelRemote(subscribedContactsChannel, Lang.bind(this,
function (result, err) {
if (!result)
return;
let [mine, channelPath, props] = result;
this._gotContactsChannel(connPath, channelPath, props);
}));
this._connections[connPath] = info;
return info;
},
_gotContactsChannel: function(connPath, channelPath, props) {
let info = this._connections[connPath];
if (!info)
return;
info.contactsGroup = new Telepathy.ChannelGroup(DBus.session,
Telepathy.pathToName(connPath),
channelPath);
info.contactsListChangedId =
info.contactsGroup.connect('MembersChanged', Lang.bind(this, this._contactsListChanged, info));
info.contactsGroup.GetRemote('Members', Lang.bind(this,
function(contacts, err) {
if (!contacts)
return;
info.connectionContacts.GetContactAttributesRemote(
contacts, [Telepathy.CONNECTION_ALIASING_NAME], false,
Lang.bind(this, this._gotContactAttributes, info));
}));
},
_contactsListChanged: function(group, message, added, removed,
local_pending, remote_pending,
actor, reason, info) {
for (let i = 0; i < removed.length; i++)
delete info.names[removed[i]];
info.connectionContacts.GetContactAttributesRemote(
added, [Telepathy.CONNECTION_ALIASING_NAME], false,
Lang.bind(this, this._gotContactAttributes, info));
},
_gotContactAttributes: function(attrs, err, info) {
if (!attrs)
return;
for (let handle in attrs)
info.names[handle] = attrs[handle][Telepathy.CONNECTION_ALIASING_NAME + '/alias'];
},
_presencesChanged: function(conn, presences, err) {
if (!presences)
return;
let info = this._connections[conn.getPath()];
if (!info)
return;
for (let handle in presences) {
let [type, status, message] = presences[handle];
this.emit('presence-changed', conn.getPath(), handle, type, message);
}
},
_removeConnection: function(conn) {
let info = this._connections[conn.getPath()];
if (!info)
return;
conn.disconnect(info.statusChangedId);
info.connectionAvatars.disconnect(info.updatedId);
info.connectionAvatars.disconnect(info.retrievedId);
info.connectionPresence.disconnect(info.presenceChangedId);
info.contactsGroup.disconnect(info.contactsListChangedId);
delete this._connections[conn.getPath()];
},
_getFileForToken: function(info, token) {
return info.cacheDir + '/' + Telepathy.escapeAsIdentifier(token);
},
_setIcon: function(iconBox, info, handle) {
let textureCache = St.TextureCache.get_default();
let token = info.tokens[handle];
let file;
if (token) {
file = this._getFileForToken(info, token);
if (!GLib.file_test(file, GLib.FileTest.EXISTS))
file = null;
}
if (file) {
let uri = GLib.filename_to_uri(file, null);
iconBox.child = textureCache.load_uri_async(uri, iconBox._size, iconBox._size);
} else {
iconBox.child = textureCache.load_icon_name('stock_person', iconBox._size);
}
},
_updateIcons: function(info, handle) {
if (!info.icons[handle])
return;
for (let i = 0; i < info.icons[handle].length; i++) {
let iconBox = info.icons[handle][i];
this._setIcon(iconBox, info, handle);
}
},
_avatarUpdated: function(conn, handle, token) {
let info = this._connections[conn.getPath()];
if (!info)
return;
if (info.tokens[handle] == token)
return;
info.tokens[handle] = token;
if (token != '') {
let file = this._getFileForToken(info, token);
if (!GLib.file_test(file, GLib.FileTest.EXISTS)) {
info.connectionAvatars.RequestAvatarsRemote([handle]);
return;
}
}
this._updateIcons(info, handle);
},
_avatarRetrieved: function(conn, handle, token, avatarData, mimeType) {
let info = this._connections[conn.getPath()];
if (!info)
return;
let file = this._getFileForToken(info, token);
let success = false;
try {
success = GLib.file_set_contents(file, avatarData, avatarData.length);
} catch (e) {
logError(e, 'Error caching avatar data');
}
if (success)
this._updateIcons(info, handle);
},
createAvatar: function(conn, handle, size) {
let iconBox = new St.Bin({ style_class: 'avatar-box' });
iconBox._size = size;
let info = this._connections[conn.getPath()];
if (!info)
info = this.addConnection(conn.getPath());
if (!info.icons[handle])
info.icons[handle] = [];
info.icons[handle].push(iconBox);
iconBox.connect('destroy', Lang.bind(this,
function() {
let i = info.icons[handle].indexOf(iconBox);
if (i != -1)
info.icons[handle].splice(i, 1);
}));
// If we already have the icon cached and know its token, this
// will fill it in. Otherwise it will fill in the default
// icon.
this._setIcon(iconBox, info, handle);
// Asynchronously load the real avatar if we don't have it yet.
if (info.tokens[handle] == null) {
info.connectionAvatars.GetKnownAvatarTokensRemote([handle], Lang.bind(this,
function (tokens, err) {
let token = tokens && tokens[handle] ? tokens[handle] : '';
this._avatarUpdated(conn, handle, token);
}));
}
return iconBox;
}
};
Signals.addSignalMethods(ContactManager.prototype);
function Source(accountPath, connPath, channelPath, targetHandle, targetHandleType, targetId) {
this._init(accountPath, connPath, channelPath, targetHandle, targetHandleType, targetId);
}
Source.prototype = {
__proto__: MessageTray.Source.prototype,
_init: function(accountPath, connPath, channelPath, targetHandle, targetHandleType, targetId) {
MessageTray.Source.prototype._init.call(this, targetId);
this._accountPath = accountPath;
let connName = Telepathy.pathToName(connPath);
this._conn = new Telepathy.Connection(DBus.session, connName, connPath);
this._channel = new Telepathy.Channel(DBus.session, connName, channelPath);
this._closedId = this._channel.connect('Closed', Lang.bind(this, this._channelClosed));
this._targetHandle = targetHandle;
this._targetHandleType = targetHandleType;
this._targetId = targetId;
this.name = this._targetId;
if (targetHandleType == Telepathy.HandleType.CONTACT) {
let aliasing = new Telepathy.ConnectionAliasing(DBus.session, connName, connPath);
aliasing.RequestAliasesRemote([this._targetHandle], Lang.bind(this,
function (aliases, err) {
if (aliases && aliases.length)
this.name = aliases[0];
}));
}
// Since we only create sources when receiving a message, this
// is a plausible default
this._presence = Telepathy.ConnectionPresenceType.AVAILABLE;
this._channelText = new Telepathy.ChannelText(DBus.session, connName, channelPath);
this._receivedId = this._channelText.connect('Received', Lang.bind(this, this._messageReceived));
this._channelText.ListPendingMessagesRemote(false, Lang.bind(this, this._gotPendingMessages));
},
createIcon: function(size) {
return contactManager.createAvatar(this._conn, this._targetHandle, size);
},
clicked: function() {
channelDispatcher.EnsureChannelRemote(this._accountPath,
{ 'org.freedesktop.Telepathy.Channel.ChannelType': Telepathy.CHANNEL_TEXT_NAME,
'org.freedesktop.Telepathy.Channel.TargetHandle': this._targetHandle,
'org.freedesktop.Telepathy.Channel.TargetHandleType': this._targetHandleType },
global.get_current_time(),
'',
Lang.bind(this, this._gotChannelRequest));
MessageTray.Source.prototype.clicked.call(this);
},
_gotChannelRequest: function (chanReqPath, ex) {
if (ex) {
log ('EnsureChannelRemote failed? ' + ex);
return;
}
let chanReq = new Telepathy.ChannelRequest(DBus.session, Telepathy.CHANNEL_DISPATCHER_NAME, chanReqPath);
chanReq.ProceedRemote();
},
_gotPendingMessages: function(msgs, err) {
if (!msgs)
return;
for (let i = 0; i < msgs.length; i++)
this._messageReceived.apply(this, [this._channel].concat(msgs[i]));
},
_channelClosed: function() {
this._channel.disconnect(this._closedId);
this._channelText.disconnect(this._receivedId);
this.destroy();
},
_ensureNotification: function() {
if (!Main.messageTray.contains(this))
Main.messageTray.add(this);
if (!this._notification)
this._notification = new Notification(this._targetId, this);
},
_messageReceived: function(channel, id, timestamp, sender,
type, flags, text) {
this._ensureNotification();
this._notification.appendMessage(text);
this.notify(this._notification);
},
respond: function(text) {
this._channelText.SendRemote(Telepathy.ChannelTextMessageType.NORMAL, text);
},
setPresence: function(presence, message) {
let msg, notify;
if (presence == Telepathy.ConnectionPresenceType.AVAILABLE) {
msg = _("%s is online.").format(this.name);
notify = (this._presence == Telepathy.ConnectionPresenceType.OFFLINE);
} else if (presence == Telepathy.ConnectionPresenceType.OFFLINE ||
presence == Telepathy.ConnectionPresenceType.EXTENDED_AWAY) {
presence = Telepathy.ConnectionPresenceType.OFFLINE;
msg = _("%s is offline.").format(this.name);
notify = (this._presence != Telepathy.ConnectionPresenceType.OFFLINE);
} else if (presence == Telepathy.ConnectionPresenceType.AWAY) {
msg = _("%s is away.").format(this.name);
notify = false;
} else if (presence == Telepathy.ConnectionPresenceType.BUSY) {
msg = _("%s is busy.").format(this.name);
notify = false;
} else
return;
this._presence = presence;
if (message)
msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
this._ensureNotification();
this._notification.appendMessage(msg, true);
if (notify)
this.notify(this._notification);
}
};
function Notification(id, source) {
this._init(id, source);
}
Notification.prototype = {
__proto__: MessageTray.Notification.prototype,
_init: function(id, source) {
MessageTray.Notification.prototype._init.call(this, id, source, source.name);
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this._responseEntry = new St.Entry({ style_class: 'chat-response' });
this._responseEntry.clutter_text.connect('key-focus-in', Lang.bind(this, this._onEntryFocused));
this._responseEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivated));
this.setActionArea(this._responseEntry);
this._history = [];
},
appendMessage: function(text, asTitle) {
if (asTitle)
this.update(text);
else
this.update(this.source.name, text);
this._append(text, 'chat-received');
},
_append: function(text, style) {
let body = this.addBody(text);
body.add_style_class_name(style);
this.scrollTo(St.Side.BOTTOM);
let now = new Date().getTime() / 1000;
this._history.unshift({ actor: body, time: now });
if (this._history.length > 1) {
// Keep the scrollback from growing too long. If the most
// recent message (before the one we just added) is within
// SCROLLBACK_RECENT_TIME, we will keep
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
// we'll keep SCROLLBACK_IDLE_LENGTH messages.
let lastMessageTime = this._history[1].time;
let maxLength = (lastMessageTime < now - SCROLLBACK_RECENT_TIME) ?
SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
if (this._history.length > maxLength) {
let expired = this._history.splice(maxLength);
for (let i = 0; i < expired.length; i++)
expired[i].actor.destroy();
}
}
},
_onButtonPress: function(notification, event) {
if (!this._active)
return false;
let source = event.get_source ();
while (source) {
if (source == notification)
return false;
source = source.get_parent();
}
// @source is outside @notification, which has to mean that
// we have a pointer grab, and the user clicked outside the
// notification, so we should deactivate.
this._deactivate();
return true;
},
_onEntryFocused: function() {
if (this._active)
return;
if (!Main.pushModal(this.actor))
return;
Clutter.grab_pointer(this.actor);
this._active = true;
Main.messageTray.lock();
},
_onEntryActivated: function() {
let text = this._responseEntry.get_text();
if (text == '') {
this._deactivate();
return;
}
this._responseEntry.set_text('');
this._append(text, 'chat-sent');
this.source.respond(text);
},
_deactivate: function() {
if (this._active) {
Clutter.ungrab_pointer(this.actor);
Main.popModal(this.actor);
global.stage.set_key_focus(null);
// We have to do this after calling popModal(), because
// that will return the keyboard focus to
// this._responseEntry (because that's where it was when
// pushModal() was called), which will cause
// _onEntryFocused() to be called again, but we don't want
// it to do anything.
this._active = false;
Main.messageTray.unlock();
}
}
};

View File

@ -46,7 +46,7 @@ let slowDownFactor = 1.0;
// Called from Main.start
function init() {
let slowdownEnv = GLib.getenv("GNOME_SHELL_SLOWDOWN_FACTOR");
let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
if (slowdownEnv) {
let factor = parseFloat(slowdownEnv);
if (!isNaN(factor) && factor > 0.0)
@ -190,7 +190,7 @@ function registerSpecialPropertySplitter(name, splitFunction, parameters) {
}
// The "FrameTicker" object is an object used to feed new frames to
// The 'FrameTicker' object is an object used to feed new frames to
// Tweener so it can update values and redraw. The default frame
// ticker for Tweener just uses a simple timeout at a fixed frame rate
// and has no idea of "catching up" by dropping frames.
@ -243,12 +243,14 @@ ClutterFrameTicker.prototype = {
start : function() {
this._timeline.start();
global.begin_work();
},
stop : function() {
this._timeline.stop();
this._startTime = -1;
this._currentTime = -1;
global.end_work();
}
};

View File

@ -1,364 +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 Lang = imports.lang;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const AppFavorites = imports.ui.appFavorites;
const DocInfo = imports.misc.docInfo;
const COLLAPSED_WIDTH = 24;
const EXPANDED_WIDTH = 200;
const STATE_EXPANDED = 0;
const STATE_COLLAPSING = 1;
const STATE_COLLAPSED = 2;
const STATE_EXPANDING = 3;
const STATE_POPPING_OUT = 4;
const STATE_POPPED_OUT = 5;
const STATE_POPPING_IN = 6;
function Widget() {
}
Widget.prototype = {
// _init():
//
// 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
// that mode. (It may be the same actor.) This actor will be
// clipped to Widget.COLLAPSED_WIDTH, and will normally end up
// having the same height as the main actor.
//
// If you do not set a collapsedActor, then you must set a title,
// since that is what will be displayed in collapsed mode, and
// in this case (and only in this case), the widget will support
// pop-out, meaning that if the user hovers over its title while
// 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():
//
// Optional. Will be called when the widget is removed from the
// sidebar. (Note that you don't need to destroy the actors,
// since they will be destroyed for you.)
// collapse():
//
// Optional. Called during the sidebar collapse process, at the
// point when the expanded sidebar has slid offscreen, but the
// collapsed sidebar has not yet slid onscreen.
// expand():
//
// Optional. Called during the sidebar expand process, at the
// point when the collapsed sidebar has slid offscreen, but the
// expanded sidebar has not yet slid onscreen.
// activated():
//
// Emits the "activated" signal for you, which will cause pop-out
// to end.
activated: function() {
this.emit('activated');
}
// state:
//
// A field set on your widget by the sidebar. Will contain one of
// the Widget.STATE_* values. (Eg, Widget.STATE_EXPANDED).
};
Signals.addSignalMethods(Widget.prototype);
function ClockWidget() {
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
// it's the same in both modes
height: COLLAPSED_WIDTH });
this.collapsedActor = new St.DrawingArea({ width: COLLAPSED_WIDTH,
height: COLLAPSED_WIDTH });
this.collapsedActor.connect('repaint', Lang.bind(this, this._repaintClock));
this._update();
},
destroy: function() {
if (this.timer)
Mainloop.source_remove(this.timer);
},
expand: function() {
this._update();
},
collapse: function() {
this._update();
},
_update: function() {
this.currentTime = new Date();
let msec_remaining = 60000 - (1000 * this.currentTime.getSeconds() +
this.currentTime.getMilliseconds());
if (msec_remaining < 500) {
this.currentTime.setMinutes(this.currentTime.getMinutes() + 1);
msec_remaining += 60000;
}
if (this.state == STATE_COLLAPSED || this.state == STATE_COLLAPSING)
this.collapsedActor.queue_repaint();
else
this._updateText();
if (this.timer)
Mainloop.source_remove(this.timer);
this.timer = Mainloop.timeout_add(msec_remaining, Lang.bind(this, this._update));
return false;
},
_updateText: function(time) {
// Translators: This is a time format.
this.actor.set_text(this.currentTime.toLocaleFormat(_("%H:%M")));
},
_repaintClock: function(area) {
Shell.draw_clock(area,
this.currentTime.getHours() % 12,
this.currentTime.getMinutes());
}
};
const ITEM_ICON_SIZE = 48;
const ITEM_PADDING = 1;
const ITEM_SPACING = 4;
const ITEM_BG_COLOR = new Clutter.Color();
ITEM_BG_COLOR.from_pixel(0x00000000);
const ITEM_NAME_COLOR = new Clutter.Color();
ITEM_NAME_COLOR.from_pixel(0x000000ff);
function LauncherWidget() {
this._init.apply(this, arguments);
}
LauncherWidget.prototype = {
__proto__ : Widget.prototype,
addItem : function(info) {
let item = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
width: EXPANDED_WIDTH,
height: ITEM_ICON_SIZE,
padding: ITEM_PADDING,
spacing: ITEM_SPACING,
reactive: true });
item._info = info;
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,
text: info.name }),
Big.BoxPackFlags.NONE);
this.actor.append(item, Big.BoxPackFlags.NONE);
item.connect('button-press-event', Lang.bind(this, this._buttonPress));
item.connect('button-release-event', Lang.bind(this, this._buttonRelease));
item.connect('leave-event', Lang.bind(this, this._leave));
item.connect('enter-event', Lang.bind(this, this._enter));
if (!this.collapsedActor)
return;
item = new Big.Box({ width: COLLAPSED_WIDTH,
height: COLLAPSED_WIDTH,
padding: ITEM_PADDING,
reactive: true });
item._info = info;
item.append(info.createIcon(COLLAPSED_WIDTH - 2 * ITEM_PADDING),
Big.BoxPackFlags.NONE);
this.collapsedActor.append(item, Big.BoxPackFlags.NONE);
item.connect('button-press-event', Lang.bind(this, this._buttonPress));
item.connect('button-release-event', Lang.bind(this, this._buttonRelease));
item.connect('leave-event', Lang.bind(this, this._leave));
item.connect('enter-event', Lang.bind(this, this._enter));
},
clear : function() {
let children, i;
children = this.actor.get_children();
for (i = 0; i < children.length; i++)
children[i].destroy();
if (this.collapsedActor) {
children = this.collapsedActor.get_children();
for (i = 0; i < children.length; i++)
children[i].destroy();
}
},
_buttonPress : function(item) {
Clutter.grab_pointer(item);
item._buttonDown = true;
item._inItem = true;
this._updateItemState(item);
return true;
},
_leave : function(item, evt) {
if (evt.get_source() == item && item._buttonDown) {
item._inItem = false;
this._updateItemState(item);
}
return false;
},
_enter : function(item, evt) {
if (evt.get_source() == item && item._buttonDown) {
item._inItem = true;
this._updateItemState(item);
}
return false;
},
_buttonRelease : function(item) {
Clutter.ungrab_pointer(item);
item._buttonDown = false;
this._updateItemState(item);
if (item._inItem) {
item._info.launch();
this.activated();
}
return true;
},
_updateItemState : function(item) {
if (item._buttonDown && item._inItem) {
item.padding_top = item.padding_left = 2 * ITEM_PADDING;
item.padding_bottom = item.padding_right = 0;
} else
item.padding = ITEM_PADDING;
}
};
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.apply(this, arguments);
}
AppsWidget.prototype = {
__proto__ : LauncherWidget.prototype,
_init : function() {
Widget.prototype._init.apply(this, arguments);
this.title = _("Applications");
this.actor = new Big.Box({ spacing: 2 });
this.collapsedActor = new Big.Box({ spacing: 2});
let appSystem = Shell.AppSystem.get_default();
let apps = AppFavorites.getAppFavorites().getFavorites();
for (let i = 0; i < apps.length; i++) {
this.addItem(new AppsWidgetInfo(apps[i]));
}
}
};
function RecentDocsWidget() {
this._init.apply(this, arguments);
}
RecentDocsWidget.prototype = {
__proto__ : LauncherWidget.prototype,
_init : function() {
Widget.prototype._init.apply(this, arguments);
this.title = _("Recent Documents");
this.actor = new Big.Box({ spacing: 2 });
this._recentManager = Gtk.RecentManager.get_default();
this._recentManager.connect('changed', Lang.bind(this, this._recentChanged));
this._recentChanged();
},
_recentChanged: function() {
let i;
this.clear();
let items = [];
let docs = this._recentManager.get_items();
for (i = 0; i < docs.length; i++) {
let docInfo = new DocInfo.DocInfo (docs[i]);
items.push(docInfo);
}
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

@ -1,395 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const Widget = imports.ui.widget;
const WIDGETBOX_BG_COLOR = new Clutter.Color();
WIDGETBOX_BG_COLOR.from_pixel(0xf0f0f0ff);
const BLACK = new Clutter.Color();
BLACK.from_pixel(0x000000ff);
const WIDGETBOX_PADDING = 2;
const ANIMATION_TIME = 0.5;
const POP_IN_LAG = 250; /* milliseconds */
function WidgetBox(widget, expanded) {
this._init(widget, expanded);
}
WidgetBox.prototype = {
_init: function(widget, expanded) {
this.state = expanded ? Widget.STATE_EXPANDED : Widget.STATE_COLLAPSED;
if (widget instanceof Widget.Widget) {
this._widget = widget;
this._widget.state = this.state;
} else {
let ctor = this._ctorFromName(widget);
this._widget = new ctor(this.state);
}
if (!this._widget.actor)
throw new Error("widget has no actor");
else if (!this._widget.title && !this._widget.collapsedActor)
throw new Error("widget has neither title nor collapsedActor");
this.state = expanded ? Widget.STATE_EXPANDED : Widget.STATE_COLLAPSED;
// The structure of a WidgetBox:
//
// The top level is a Clutter.Group, which exists to make
// pop-out work correctly; when another widget pops out, its
// width will increase, which will in turn cause the sidebar's
// width to increase, which will cause the sidebar to increase
// the width of each of its children (the WidgetBoxes). But we
// don't want the non-popped-out widgets to expand, so we make
// the top-level actor be a Clutter.Group, which will accept
// the new width from the Sidebar, but not impose it on its
// own child.
//
// Inside the toplevel group is a horizontal Big.Box
// containing 2 Clutter.Groups; one for the collapsed state
// (cgroup) and one for the expanded state (egroup). Each
// group contains a single vertical Big.Box (cbox and ebox
// respectively), which have the appropriate fixed width. The
// cbox contains either the collapsed widget actor or else the
// rotated title. The ebox contains the horizontal title (if
// any), separator line, and the expanded widget actor. (If
// the widget doesn't have a collapsed actor, and therefore
// supports pop-out, then it will also have a vertical line
// between the two groups, which will only be shown during
// pop-out.)
//
// In the expanded view, cgroup is hidden and egroup is shown.
// When animating to the collapsed view, first the ebox is
// slid offscreen by giving it increasingly negative x
// coordinates within egroup. Then once it's fully offscreen,
// we hide egroup, show cgroup, and slide cbox back in in the
// same way.
//
// The pop-out view works similarly to the second half of the
// collapsed-to-expanded transition, except that the
// horizontal title gets hidden to avoid duplication.
this.actor = new Clutter.Group();
this._hbox = new Big.Box({ background_color: WIDGETBOX_BG_COLOR,
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,
orientation: Big.BoxOrientation.HORIZONTAL,
reactive: true });
this.actor.add_actor(this._hbox);
this._cgroup = new Clutter.Group({ clip_to_allocation: true });
this._hbox.append(this._cgroup, Big.BoxPackFlags.NONE);
this._cbox = new Big.Box({ width: Widget.COLLAPSED_WIDTH,
clip_to_allocation: true });
this._cgroup.add_actor(this._cbox);
if (this._widget.collapsedActor) {
if (this._widget.collapsedActor == this._widget.actor)
this._singleActor = true;
else {
this._cbox.append(this._widget.collapsedActor,
Big.BoxPackFlags.NONE);
}
} else {
let vtitle = new Clutter.Text({ font_name: "Sans 16px",
text: this._widget.title,
rotation_angle_z: -90.0 });
let signalId = vtitle.connect('notify::allocation',
function () {
vtitle.disconnect(signalId);
vtitle.set_anchor_point(vtitle.natural_width, 0);
vtitle.set_size(vtitle.natural_height,
vtitle.natural_width);
});
this._vtitle = vtitle;
this._cbox.append(this._vtitle, Big.BoxPackFlags.NONE);
this._vline = new Clutter.Rectangle({ color: BLACK, width: 1 });
this._hbox.append(this._vline, Big.BoxPackFlags.NONE);
this._vline.hide();
// Set up pop-out
this._eventHandler = this._hbox.connect('captured-event',
Lang.bind(this, this._popEventHandler));
this._activationHandler = this._widget.connect('activated',
Lang.bind(this, this._activationHandler));
}
this._egroup = new Clutter.Group({ clip_to_allocation: true });
this._hbox.append(this._egroup, Big.BoxPackFlags.NONE);
this._ebox = new Big.Box({ spacing: WIDGETBOX_PADDING,
width: Widget.EXPANDED_WIDTH,
clip_to_allocation: true });
this._egroup.add_actor(this._ebox);
if (this._widget.title) {
this._htitle = new Clutter.Text({ font_name: "Sans 16px",
text: this._widget.title });
this._ebox.append(this._htitle, Big.BoxPackFlags.NONE);
this._hline = new Clutter.Rectangle({ color: BLACK, height: 1 });
this._ebox.append(this._hline, Big.BoxPackFlags.NONE);
}
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
// into a constructor function
_ctorFromName: function(name) {
// Make sure it's a valid import
if (!name.match(/^imports(\.[a-zA-Z0-9_]+)+$/))
throw new Error("widget name must start with 'imports.'");
if (name.match(/^imports\.gi\./))
throw new Error("cannot import widget from GIR");
let ctor = eval(name);
// Make sure it's really a constructor
if (!ctor || typeof(ctor) != "function")
throw new Error("widget name is not a constructor");
// Make sure it's a widget
let proto = ctor.prototype;
while (proto && proto != Widget.Widget.prototype)
proto = proto.__proto__;
if (!proto)
throw new Error("widget does not inherit from Widget prototype");
return ctor;
},
expand: function() {
Tweener.addTween(this._cbox, { x: -Widget.COLLAPSED_WIDTH,
time: ANIMATION_TIME / 2,
transition: "easeOutQuad",
onComplete: this._expandPart1Complete,
onCompleteScope: this });
this.state = this._widget.state = Widget.STATE_EXPANDING;
},
_setWidgetExpanded: function() {
this._cgroup.hide();
this._egroup.show();
if (this._singleActor) {
this._widget.actor.get_parent().remove_actor(this._widget.actor);
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();
} catch (e) {
logError(e, 'Widget failed to expand');
}
}
this._ebox.x = -Widget.EXPANDED_WIDTH;
Tweener.addTween(this._ebox, { x: 0,
time: ANIMATION_TIME / 2,
transition: "easeOutQuad",
onComplete: this._expandComplete,
onCompleteScope: this });
},
_expandComplete: function() {
this.state = this._widget.state = Widget.STATE_EXPANDED;
},
collapse: function() {
Tweener.addTween(this._ebox, { x: -Widget.EXPANDED_WIDTH,
time: ANIMATION_TIME / 2,
transition: "easeOutQuad",
onComplete: this._collapsePart1Complete,
onCompleteScope: this });
this.state = this._widget.state = Widget.STATE_COLLAPSING;
},
_setWidgetCollapsed: function() {
this._egroup.hide();
this._cgroup.show();
if (this._singleActor) {
this._widget.actor.get_parent().remove_actor(this._widget.actor);
this._cbox.append(this._widget.actor, Big.BoxPackFlags.NONE);
}
if (this._htitle) {
this._htitle.hide();
this._hline.hide();
}
if (this._vtitle)
this._cbox.height = this._ebox.height;
},
_collapsePart1Complete: function() {
this._ebox.x = 0;
this._setWidgetCollapsed();
if (this._widget.collapse) {
try {
this._widget.collapse();
} catch (e) {
logError(e, 'Widget failed to collapse');
}
}
this._cbox.x = -Widget.COLLAPSED_WIDTH;
Tweener.addTween(this._cbox, { x: 0,
time: ANIMATION_TIME / 2,
transition: "easeOutQuad",
onComplete: this._collapseComplete,
onCompleteScope: this });
},
_collapseComplete: function() {
this.state = this._widget.state = Widget.STATE_COLLAPSED;
},
_popEventHandler: function(actor, event) {
let type = event.type();
if (type == Clutter.EventType.ENTER) {
this._clearPopInTimeout();
if (this.state == Widget.STATE_COLLAPSED ||
this.state == Widget.STATE_COLLAPSING) {
this._popOut();
return false;
}
} else if (type == Clutter.EventType.LEAVE &&
(this.state == Widget.STATE_POPPED_OUT ||
this.state == Widget.STATE_POPPING_OUT)) {
// If moving into another actor within this._hbox, let the
// event be propagated
let into = event.get_related();
while (into) {
if (into == this._hbox)
return false;
into = into.get_parent();
}
// Else, moving out of this._hbox
this._setPopInTimeout();
return false;
}
return false;
},
_activationHandler: function() {
if (this.state == Widget.STATE_POPPED_OUT)
this._popIn();
},
_popOut: function() {
if (this.state != Widget.STATE_COLLAPSED &&
this.state != Widget.STATE_COLLAPSING)
return;
this._vline.show();
this._egroup.show();
this._ebox.x = -Widget.EXPANDED_WIDTH;
Tweener.addTween(this._ebox, { x: 0,
time: ANIMATION_TIME / 2,
transition: "easeOutQuad",
onComplete: this._popOutComplete,
onCompleteScope: this });
this.state = this._widget.state = Widget.STATE_POPPING_OUT;
Main.chrome.trackActor(this._hbox, { affectsStruts: false });
},
_popOutComplete: function() {
this.state = this._widget.state = Widget.STATE_POPPED_OUT;
},
_setPopInTimeout: function() {
this._clearPopInTimeout();
this._popInTimeout = Mainloop.timeout_add(POP_IN_LAG, Lang.bind(this, function () { this._popIn(); return false; }));
},
_clearPopInTimeout: function() {
if (this._popInTimeout) {
Mainloop.source_remove(this._popInTimeout);
delete this._popInTimeout;
}
},
_popIn: function() {
this._clearPopInTimeout();
if (this.state != Widget.STATE_POPPED_OUT &&
this.state != Widget.STATE_POPPING_OUT)
return;
Tweener.addTween(this._ebox, { x: -Widget.EXPANDED_WIDTH,
time: ANIMATION_TIME / 2,
transition: "easeOutQuad",
onComplete: this._popInComplete,
onCompleteScope: this });
},
_popInComplete: function() {
this.state = this._widget.state = Widget.STATE_COLLAPSED;
this._vline.hide();
this._egroup.hide();
this._ebox.x = 0;
Main.chrome.untrackActor(this._hbox);
},
hide: function() {
if (this.state == Widget.STATE_COLLAPSED)
Tweener.addTween(this._cbox, { x: -Widget.COLLAPSED_WIDTH,
time: ANIMATION_TIME / 2,
transition: "easeOutQuad" });
},
restore: function() {
if (this.state == Widget.STATE_COLLAPSED)
Tweener.addTween(this._cbox, { x: 0,
time: ANIMATION_TIME / 2,
transition: "easeOutQuad" });
},
destroy: function() {
if (this._widget.destroy)
this._widget.destroy();
}
};

View File

@ -103,7 +103,7 @@ WindowManager.prototype = {
x: xDest,
y: 0,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: this._minimizeWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
@ -152,17 +152,15 @@ WindowManager.prototype = {
return;
}
actor.move_anchor_point_from_gravity(Clutter.Gravity.CENTER);
actor.set_scale(0.0, 0.0);
actor.opacity = 0;
actor.show();
/* scale window up from 0x0 to normal size */
/* Fade window in */
this._mapping.push(actor);
Tweener.addTween(actor,
{ scale_x: 1.0,
scale_y: 1.0,
{ opacity: 255,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: this._mapWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
@ -175,8 +173,7 @@ WindowManager.prototype = {
_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);
actor.opacity = 255;
shellwm.completed_map(actor);
}
},
@ -261,7 +258,7 @@ WindowManager.prototype = {
{ x: xDest,
y: yDest,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: this._switchWorkspaceDone,
onCompleteScope: this,
onCompleteParams: [shellwm]
@ -270,7 +267,7 @@ WindowManager.prototype = {
{ x: 0,
y: 0,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
},
@ -309,7 +306,7 @@ WindowManager.prototype = {
_showWorkspaceSwitcher : function(shellwm, binding, window, backwards) {
/* We don't support this kind of layout */
if (binding == "switch_to_workspace_up" || binding == "switch_to_workspace_down")
if (binding == 'switch_to_workspace_up' || binding == 'switch_to_workspace_down')
return;
if (global.screen.n_workspaces == 1)
@ -318,11 +315,11 @@ WindowManager.prototype = {
if (this._workspaceSwitcherPopup == null)
this._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup();
if (binding == "switch_to_workspace_left") {
if (binding == 'switch_to_workspace_left') {
this.actionMoveWorkspaceLeft();
}
if (binding == "switch_to_workspace_right") {
if (binding == 'switch_to_workspace_right') {
this.actionMoveWorkspaceRight();
}
},

View File

@ -1,6 +1,5 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf;
const Gdk = imports.gi.Gdk;
@ -122,11 +121,8 @@ WindowClone.prototype = {
Lang.bind(this, this._onScroll));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('enter-event',
Lang.bind(this, this._onEnter));
this.actor.connect('leave-event',
Lang.bind(this, this._onLeave));
this._havePointer = false;
this._draggable = DND.makeDraggable(this.actor,
{ dragActorMaxSize: WINDOW_DND_SIZE,
@ -135,6 +131,7 @@ WindowClone.prototype = {
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
this.inDrag = false;
this._windowIsZooming = false;
this._zooming = false;
this._selected = false;
},
@ -179,23 +176,7 @@ WindowClone.prototype = {
this.disconnectAll();
},
_onEnter: function (actor, event) {
// If the user drags faster than we can follow, he'll end up
// leaving the window temporarily and then re-entering it
if (this.inDrag)
return;
this._havePointer = true;
},
_onLeave: function (actor, event) {
// If the user drags faster than we can follow, he'll end up
// leaving the window temporarily and then re-entering it
if (this.inDrag)
return;
this._havePointer = false;
if (this._zoomStep)
this._zoomEnd();
},
@ -298,14 +279,6 @@ WindowClone.prototype = {
_onDragEnd : function (draggable, time, snapback) {
this.inDrag = false;
// Most likely, the clone is going to move away from the
// pointer now. But that won't cause a leave-event, so
// do this by hand. Of course, if the window only snaps
// back a short distance, this might be wrong, but it's
// better to have the label mysteriously missing than
// mysteriously present
this._havePointer = false;
// We may not have a parent if DnD completed successfully, in
// which case our clone will shortly be destroyed and replaced
// with a new one on the target workspace.
@ -352,7 +325,7 @@ DesktopClone.prototype = {
Tweener.addTween(this._desktop,
{ opacity: 255,
time: Overview.ANIMATION_TIME,
transition: "easeOutQuad" });
transition: 'easeOutQuad' });
}
},
@ -366,7 +339,7 @@ DesktopClone.prototype = {
Tweener.addTween(this._desktop,
{ opacity: 0,
time: Overview.ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this._desktop.hide();
@ -401,7 +374,7 @@ WindowOverlay.prototype = {
this._windowClone = windowClone;
this._parentActor = parentActor;
let title = new St.Label({ style_class: "window-caption",
let title = new St.Label({ style_class: 'window-caption',
text: metaWindow.title });
title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
title._spacing = 0;
@ -411,7 +384,7 @@ WindowOverlay.prototype = {
this.title.text = w.title;
}));
let button = new St.Button({ style_class: "window-close" });
let button = new St.Button({ style_class: 'window-close' });
button._overlap = 0;
this._idleToggleCloseId = 0;
@ -450,7 +423,7 @@ WindowOverlay.prototype = {
},
show: function() {
let [child, x, y, mask] = Gdk.Screen.get_default().get_root_window().get_pointer();
let [x, y, mask] = global.get_pointer();
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
x, y);
if (actor == this._windowClone.actor) {
@ -466,7 +439,7 @@ WindowOverlay.prototype = {
Tweener.addTween(this.title,
{ opacity: 255,
time: Overview.ANIMATION_TIME,
transition: "easeOutQuad" });
transition: 'easeOutQuad' });
},
chromeWidth: function () {
@ -560,7 +533,7 @@ WindowOverlay.prototype = {
_idleToggleCloseButton: function() {
this._idleToggleCloseId = 0;
let [child, x, y, mask] = Gdk.Screen.get_default().get_root_window().get_pointer();
let [x, y, mask] = global.get_pointer();
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
x, y);
if (actor != this._windowClone.actor && actor != this.closeButton) {
@ -652,10 +625,11 @@ Workspace.prototype = {
this._desktop.connect('selected',
Lang.bind(this,
function(clone, time) {
// Only switch to the workspace when one window is open
// We check for "2" here because the Desktop does not really count
// as a window in this context.
if (this._windows.length <= 2) {
// Only switch to the workspace when there's no application windows
// open (we always have one window for the desktop). The problem
// is that it's too easy to miss an app window and get the wrong
// one focused.
if (this._windows.length == 1) {
this.metaWorkspace.activate(time);
Main.overview.hide();
}
@ -1049,8 +1023,13 @@ Workspace.prototype = {
(desiredHeight - buttonOuterHeight - captionHeight) / rect.height,
1.0 / this.scale);
x = xCenter - 0.5 * scale * rect.width;
y = y + height - rect.height * scale - captionHeight;
x = Math.floor(xCenter - 0.5 * scale * rect.width);
// We want to center the window in case we have just one
if (metaWindow.get_workspace().n_windows == 1)
y = Math.floor(yCenter * global.screen_height - 0.5 * scale * rect.height);
else
y = Math.floor(y + height - rect.height * scale - captionHeight);
return [x, y, scale];
},
@ -1126,7 +1105,7 @@ Workspace.prototype = {
Tweener.addTween(clone.actor,
{ opacity: 255,
time: Overview.ANIMATION_TIME,
transition: "easeInQuad"
transition: 'easeInQuad'
});
}
@ -1137,7 +1116,7 @@ Workspace.prototype = {
scale_y: scale,
workspace_relative: workspaceZooming ? this : null,
time: Overview.ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._fadeInWindowOverlay(clone, overlay);
})
@ -1169,6 +1148,9 @@ Workspace.prototype = {
},
_fadeInWindowOverlay: function(clone, overlay) {
if (clone.inDrag)
return;
// This is a little messy and complicated because when we
// start the fade-in we may not have done the final positioning
// of the workspaces. (Tweener doesn't necessarily finish
@ -1209,8 +1191,10 @@ Workspace.prototype = {
},
_delayedWindowRepositioning: function() {
let [child, x, y, mask] =
Gdk.Screen.get_default().get_root_window().get_pointer();
if (this._windowIsZooming)
return true;
let [x, y, mask] = global.get_pointer();
let wsWidth = this.actor.width * this.scale;
let wsHeight = this.actor.height * this.scale;
@ -1282,8 +1266,7 @@ Workspace.prototype = {
}
// setup new handler
let [child, x, y, mask] =
Gdk.Screen.get_default().get_root_window().get_pointer();
let [x, y, mask] = global.get_pointer();
this._cursorX = x;
this._cursorY = y;
@ -1387,7 +1370,7 @@ Workspace.prototype = {
workspace_relative: this,
time: Overview.ANIMATION_TIME,
opacity: 255,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
} else {
// The window is hidden, make it shrink and fade it out
@ -1397,7 +1380,7 @@ Workspace.prototype = {
opacity: 0,
workspace_relative: this,
time: Overview.ANIMATION_TIME,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
}
}
@ -1420,7 +1403,7 @@ Workspace.prototype = {
scale_x: this.scale,
scale_y: this.scale,
time: Overview.ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: Lang.bind(this, this._fadeInAllOverlays)
});
},
@ -1440,7 +1423,7 @@ Workspace.prototype = {
scale_x: this.scale,
scale_y: this.scale,
time: Overview.ANIMATION_TIME,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
this._visible = true;
@ -1462,7 +1445,7 @@ Workspace.prototype = {
scale_x: this.scale,
scale_y: this.scale,
time: Overview.ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: onComplete
});
@ -1533,6 +1516,14 @@ Workspace.prototype = {
this.emit('window-drag-end', clone.actor);
overlay.show();
}));
clone.connect('zoom-start',
Lang.bind(this, function() {
this._windowIsZooming = true;
}));
clone.connect('zoom-end',
Lang.bind(this, function() {
this._windowIsZooming = false;
}));
this.actor.add_actor(clone.actor);

View File

@ -5,6 +5,7 @@ const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
@ -25,12 +26,12 @@ WorkspaceSwitcherPopup.prototype = {
y: 0,
width: global.screen_width,
height: global.screen_height });
global.stage.add_actor(this.actor);
Main.uiGroup.add_actor(this.actor);
this._scaleWidth = global.screen_width / global.screen_height;
this._container = new St.BoxLayout({ style_class: "workspace-switcher-container" });
this._list = new St.BoxLayout({ style_class: "workspace-switcher" });
this._container = new St.BoxLayout({ style_class: 'workspace-switcher-container' });
this._list = new St.BoxLayout({ style_class: 'workspace-switcher' });
this._container.add(this._list);
@ -72,7 +73,7 @@ WorkspaceSwitcherPopup.prototype = {
_show : function() {
Tweener.addTween(this._container, { opacity: 255,
time: ANIMATION_TIME,
transition: "easeOutQuad"
transition: 'easeOutQuad'
});
this._position();
this.actor.show();
@ -91,7 +92,7 @@ WorkspaceSwitcherPopup.prototype = {
this._timeoutId = 0;
Tweener.addTween(this._container, { opacity: 0.0,
time: ANIMATION_TIME,
transition: "easeOutQuad",
transition: 'easeOutQuad',
onComplete: function() { this.actor.hide(); },
onCompleteScope: this
});

File diff suppressed because it is too large Load Diff

View File

@ -27,5 +27,6 @@ sr
sr@latin
sv
tr
uk
vi
zh_CN

View File

@ -1,4 +1,6 @@
data/gnome-shell.desktop.in.in
data/gnome-shell-clock-preferences.desktop.in.in
[type: gettext/glade]data/clock-preferences.ui
js/ui/appDisplay.js
js/ui/appFavorites.js
js/ui/dash.js
@ -9,8 +11,8 @@ js/ui/panel.js
js/ui/placeDisplay.js
js/ui/runDialog.js
js/ui/statusMenu.js
js/ui/widget.js
js/ui/windowAttentionHandler.js
js/ui/workspacesView.js
src/gdmuser/gdm-user.c
src/shell-global.c
src/shell-uri-util.c

View File

@ -1 +1,2 @@
data/gnome-shell.desktop.in
data/gnome-shell-clock-preferences.desktop.in

243
po/ar.po
View File

@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: HEAD\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-01-17 11:29+0200\n"
"PO-Revision-Date: 2010-01-17 11:29+0300\n"
"POT-Creation-Date: 2010-05-15 23:40+0300\n"
"PO-Revision-Date: 2010-05-15 23:40+0300\n"
"Last-Translator: Khaled Hosny <khaledhosny@eglug.org>\n"
"Language-Team: Arabic <doc@arabeyes.org>\n"
"MIME-Version: 1.0\n"
@ -15,8 +15,8 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
"X-Generator: Virtaal 0.5.1\n"
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
"X-Generator: Virtaal 0.6.0\n"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
@ -26,97 +26,237 @@ msgstr "صدفة جنوم"
msgid "Window management and application launching"
msgstr "إدارة النوافذ وإطلاق التطبيقات"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "الساعة"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "طوّع ساعة اللوحة"
#. **** Applications ****
#: ../js/ui/appDisplay.js:252 ../js/ui/dash.js:865
#: ../js/ui/appDisplay.js:306 ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "التطبيقات"
#: ../js/ui/appDisplay.js:276
#: ../js/ui/appDisplay.js:338
msgid "PREFERENCES"
msgstr "التفضيلات"
#: ../js/ui/appDisplay.js:644
#: ../js/ui/appDisplay.js:705
msgid "New Window"
msgstr "نافذة جديدة"
#: ../js/ui/appDisplay.js:648
#: ../js/ui/appDisplay.js:709
msgid "Remove from Favorites"
msgstr "أزِل من المفضّلة"
#: ../js/ui/appDisplay.js:649
#: ../js/ui/appDisplay.js:710
msgid "Add to Favorites"
msgstr "أضِف إلى المفضّلة"
#: ../js/ui/appDisplay.js:1001
#: ../js/ui/appDisplay.js:1037
msgid "Drag here to add favorites"
msgstr "اسحب إلى هنا ليضاف إلى المفضّلة"
#: ../js/ui/dash.js:240
msgid "Find..."
msgstr "ابحث..."
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "أضيف %s إلى مفضلتك."
#: ../js/ui/dash.js:493
#: ../js/ui/appFavorites.js:107
#, c-format
msgid "%s has been removed from your favorites."
msgstr "أزيل %s من مفضّلتك."
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "ابحث"
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "يبحث..."
#: ../js/ui/dash.js:507
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "لا نتائج مطابقة."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:885 ../js/ui/placeDisplay.js:519
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "الأماكن والأجهزة"
#. **** Documents ****
#: ../js/ui/dash.js:892
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "العناصر الحديثة"
#: ../js/ui/lookingGlass.js:354
msgid "No extensions installed"
msgstr "لم تثبّت أية امتدادات"
#: ../js/ui/lookingGlass.js:391
msgid "Enabled"
msgstr "مفعّل"
#: ../js/ui/lookingGlass.js:393
msgid "Disabled"
msgstr "معطّل"
#: ../js/ui/lookingGlass.js:395
msgid "Error"
msgstr "خطأ"
#: ../js/ui/lookingGlass.js:397
msgid "Out of date"
msgstr "غير محدث"
#: ../js/ui/lookingGlass.js:422
msgid "View Source"
msgstr "اعرض المصدر"
#: ../js/ui/lookingGlass.js:428
msgid "Web Page"
msgstr "صفحة الوب"
#: ../js/ui/overview.js:161
msgid "Undo"
msgstr "تراجع"
#: ../js/ui/panel.js:535
msgid "Quit"
msgstr "أنهِ"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:336
#: ../js/ui/panel.js:740
msgid "Activities"
msgstr "الأنشطة"
#. Translators: This is a time format.
#: ../js/ui/panel.js:549
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:955
msgid "%a %b %e, %R:%S"
msgstr "%A %e %B، %R:%S"
#: ../js/ui/panel.js:956
msgid "%a %b %e, %R"
msgstr "%A %e %B، %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:960
msgid "%a %R:%S"
msgstr "%A %R:%S"
#: ../js/ui/panel.js:961
msgid "%a %R"
msgstr "%A %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:968
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%A %e %B، %l:%M:%S %p"
#: ../js/ui/panel.js:969
msgid "%a %b %e, %l:%M %p"
msgstr "%A %e %B، %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:973
msgid "%a %l:%M:%S %p"
msgstr "%A %l:%M:%S %p"
#: ../js/ui/panel.js:974
msgid "%a %l:%M %p"
msgstr "%A %Ol:%OM %p"
#: ../js/ui/placeDisplay.js:144
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "فشل فصْل '%s'"
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "أعد المحاولة"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "اتّصل ب‍..."
#: ../js/ui/runDialog.js:245
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "من فضلك اكتب أمرا:"
#: ../js/ui/runDialog.js:361
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "فشل تنفيذ '%s':"
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%OH:%OM"
#: ../js/ui/statusMenu.js:90
msgid "Available"
msgstr "متاح"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "التطبيقات"
#: ../js/ui/statusMenu.js:94
msgid "Busy"
msgstr "مشغول"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "المستندات الحديثة"
#: ../js/ui/statusMenu.js:98
msgid "Invisible"
msgstr "خفي"
#: ../src/shell-global.c:890
#: ../js/ui/statusMenu.js:105
msgid "Account Information..."
msgstr "معلومات الحساب..."
#: ../js/ui/statusMenu.js:109
msgid "System Preferences..."
msgstr "تفضيلات النظام..."
#: ../js/ui/statusMenu.js:116
msgid "Lock Screen"
msgstr "أوصد الشاشة"
#: ../js/ui/statusMenu.js:120
msgid "Switch User"
msgstr "بدّل المستخدم"
#: ../js/ui/statusMenu.js:125
msgid "Log Out..."
msgstr "اخرج..."
#: ../js/ui/statusMenu.js:129
msgid "Shut Down..."
msgstr "أطفئ..."
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "انتهى %s من البدء"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "'%s' جاهز"
#: ../js/ui/workspacesView.js:239
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr "تعذّر إضافة مساحة عمل جديدة، لتجاوز أقصى عدد من مساحات العمل."
#: ../js/ui/workspacesView.js:256
msgid "Can't remove the first workspace."
msgstr "لا يمكن حذف مساحة العمل الأولى."
#: ../src/shell-global.c:979
msgid "Less than a minute ago"
msgstr "منذ أقل من دقيقة"
#: ../src/shell-global.c:894
#: ../src/shell-global.c:983
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
@ -127,7 +267,7 @@ msgstr[3] "منذ %d دقائق"
msgstr[4] "منذ %d دقيقة"
msgstr[5] "منذ %d دقيقة"
#: ../src/shell-global.c:899
#: ../src/shell-global.c:988
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
@ -138,7 +278,7 @@ msgstr[3] "منذ %d ساعات"
msgstr[4] "منذ %d ساعة"
msgstr[5] "منذ %d ساعة"
#: ../src/shell-global.c:904
#: ../src/shell-global.c:993
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
@ -149,7 +289,7 @@ msgstr[3] "منذ %d أيام"
msgstr[4] "منذ %d يوما"
msgstr[5] "منذ %d يوم"
#: ../src/shell-global.c:909
#: ../src/shell-global.c:998
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -184,6 +324,15 @@ msgstr "ابحث"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "%H:%M"
#~ msgstr "%OH:%OM"
#~ msgid "Applications"
#~ msgstr "التطبيقات"
#~ msgid "Recent Documents"
#~ msgstr "المستندات الحديثة"
#~ msgid "Frequent"
#~ msgstr "متكرر"
@ -211,26 +360,8 @@ msgstr "%1$s: %2$s"
#~ msgid "Can't logout: %s"
#~ msgstr "تعذّر الخروج: %s"
#~ msgid "Account Information..."
#~ msgstr "معلومات الحساب..."
#~ msgid "Sidebar"
#~ msgstr "الشريط الجانبي"
#~ msgid "System Preferences..."
#~ msgstr "تفضيلات النظام..."
#~ msgid "Lock Screen"
#~ msgstr "أوصد الشاشة"
#~ msgid "Switch User"
#~ msgstr "بدّل المستخدم"
#~ msgid "Log Out..."
#~ msgstr "اخرج..."
#~ msgid "Shut Down..."
#~ msgstr "أطفئ..."
#~ msgid "Browse"
#~ msgstr "استعرض"

View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-20 03:11+0100\n"
"PO-Revision-Date: 2010-03-20 03:11+0100\n"
"POT-Creation-Date: 2010-03-29 00:49+0200\n"
"PO-Revision-Date: 2010-03-29 00:49+0200\n"
"Last-Translator: Petr Kovar <pknbe@volny.cz>\n"
"Language-Team: Czech <gnome-cs-list@gnome.org>\n"
"MIME-Version: 1.0\n"
@ -26,27 +26,27 @@ msgid "Window management and application launching"
msgstr "Správa oken a spouštění aplikací"
#. **** Applications ****
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:852
#: ../js/ui/appDisplay.js:312 ../js/ui/dash.js:855
msgid "APPLICATIONS"
msgstr "APLIKACE"
#: ../js/ui/appDisplay.js:343
#: ../js/ui/appDisplay.js:344
msgid "PREFERENCES"
msgstr "PŘEDVOLBY"
#: ../js/ui/appDisplay.js:728
#: ../js/ui/appDisplay.js:756
msgid "New Window"
msgstr "Nové okno"
#: ../js/ui/appDisplay.js:732
#: ../js/ui/appDisplay.js:760
msgid "Remove from Favorites"
msgstr "Odstranit z oblíbených"
#: ../js/ui/appDisplay.js:733
#: ../js/ui/appDisplay.js:761
msgid "Add to Favorites"
msgstr "Přidat mezi oblíbené"
#: ../js/ui/appDisplay.js:1085
#: ../js/ui/appDisplay.js:1113
msgid "Drag here to add favorites"
msgstr "Oblíbené přidáte přetažením sem"
@ -64,23 +64,23 @@ msgstr "%s byl odstraněn z oblíbených."
msgid "Find"
msgstr "Najít"
#: ../js/ui/dash.js:507
#: ../js/ui/dash.js:510
msgid "Searching..."
msgstr "Hledá se..."
#: ../js/ui/dash.js:521
#: ../js/ui/dash.js:524
msgid "No matching results."
msgstr "Neodpovídá ani jeden z výsledků."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:871 ../js/ui/placeDisplay.js:579
#: ../js/ui/dash.js:874 ../js/ui/placeDisplay.js:582
msgid "PLACES & DEVICES"
msgstr "MÍSTA A ZAŘÍZENÍ"
#. **** Documents ****
#: ../js/ui/dash.js:878 ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:881 ../js/ui/docDisplay.js:488
msgid "RECENT ITEMS"
msgstr "NEDÁVNÉ POLOŽKY"
@ -134,16 +134,16 @@ msgstr "%A, %R"
msgid "%a %l:%M %p"
msgstr "%A, %l:%M %p"
#: ../js/ui/placeDisplay.js:103
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Nelze odpojit \"%s\""
#: ../js/ui/placeDisplay.js:106
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Opakovat"
#: ../js/ui/placeDisplay.js:151
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Připojit se k..."
@ -151,7 +151,7 @@ msgstr "Připojit se k..."
msgid "Please enter a command:"
msgstr "Zadejte prosím příkaz:"
#: ../js/ui/runDialog.js:374
#: ../js/ui/runDialog.js:376
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Vykonání \"%s\" selhalo:"
@ -209,6 +209,16 @@ msgstr "Aplikace"
msgid "Recent Documents"
msgstr "Nedávné dokumenty"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "Spouštění %s dokončeno"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "Připraveno \"%s\""
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Před méně než minutou"

208
po/de.po
View File

@ -2,20 +2,22 @@
# Copyright (C) 2009 Free Software Foundation, Inc.
# This file is distributed under the same license as the gnome-shell package.
#
# workspace - Arbeitsfläche
#
# Hendrik Brandt <heb@gnome-de.org>, 2009.
# Hendrik Richter <hendrikr@gnome.org>, 2009.
# Christian Kirbach <Christian.Kirbach@googlemail.com>, 2009.
# Mario Blättermann <mariobl@gnome.org>, 2009, 2010.
# Christian Kirbach <Christian.Kirbach@googlemail.com>, 2009, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2010-03-20 22:48+0000\n"
"PO-Revision-Date: 2010-03-21 16:27+0100\n"
"POT-Creation-Date: 2010-05-17 18:24+0000\n"
"PO-Revision-Date: 2010-05-18 22:06+0100\n"
"Last-Translator: Mario Blättermann <mariobl@gnome.org>\n"
"Language-Team: German <gnome-de@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: 8bit\n"
@ -31,28 +33,66 @@ msgstr "GNOME-Shell"
msgid "Window management and application launching"
msgstr "Fenster verwalten und Anwendungen starten"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "Uhr"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "Die Uhr im Panel anpassen"
#: ../data/clock-preferences.ui.h:1
#| msgid "<b>Clock Format</b>"
msgid "Clock Format"
msgstr "Uhr-Format"
#: ../data/clock-preferences.ui.h:2
msgid "Clock Preferences"
msgstr "Uhr-Einstellungen"
#: ../data/clock-preferences.ui.h:3
#| msgid "<b>Panel Display</b>"
msgid "Panel Display"
msgstr "Panel-Anzeige"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "_Sekunden anzeigen"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
msgstr "_Datum anzeigen"
#: ../data/clock-preferences.ui.h:6
msgid "_12 hour format"
msgstr "_12-Stunden-Format"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "_24-Stunden-Format"
#. **** Applications ****
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:852
#: ../js/ui/appDisplay.js:306 ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "ANWENDUNGEN"
#: ../js/ui/appDisplay.js:343
#: ../js/ui/appDisplay.js:338
msgid "PREFERENCES"
msgstr "EINSTELLUNGEN"
#: ../js/ui/appDisplay.js:728
#: ../js/ui/appDisplay.js:705
msgid "New Window"
msgstr "Neues Fenster"
#: ../js/ui/appDisplay.js:732
#: ../js/ui/appDisplay.js:709
msgid "Remove from Favorites"
msgstr "Aus Favoriten entfernen"
#: ../js/ui/appDisplay.js:733
#: ../js/ui/appDisplay.js:710
msgid "Add to Favorites"
msgstr "Zu Favoriten hinzufügen"
#: ../js/ui/appDisplay.js:1085
#: ../js/ui/appDisplay.js:1037
msgid "Drag here to add favorites"
msgstr "Hier ablegen, um zu Favoriten hinzuzufügen"
@ -66,153 +106,170 @@ msgstr "%s wurde zu Ihren Favoriten hinzugefügt"
msgid "%s has been removed from your favorites."
msgstr "%s wurde aus Ihren Favoriten entfernt"
#: ../js/ui/dash.js:194
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "Suchen"
#: ../js/ui/dash.js:507
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "Suche läuft …"
#: ../js/ui/dash.js:521
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "Keine passenden Ergebnisse."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:871 ../js/ui/placeDisplay.js:579
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "ORTE UND GERÄTE"
#. **** Documents ****
#: ../js/ui/dash.js:878 ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "ZULETZT GEÖFFNETE DOKUMENTE"
#: ../js/ui/lookingGlass.js:363
#: ../js/ui/lookingGlass.js:466
msgid "No extensions installed"
msgstr "Keine Erweiterungen installiert"
#: ../js/ui/lookingGlass.js:400
#: ../js/ui/lookingGlass.js:503
msgid "Enabled"
msgstr "Aktiviert"
#: ../js/ui/lookingGlass.js:402
#: ../js/ui/lookingGlass.js:505
msgid "Disabled"
msgstr "Deaktiviert"
#: ../js/ui/lookingGlass.js:404
#: ../js/ui/lookingGlass.js:507
msgid "Error"
msgstr "Fehler"
#: ../js/ui/lookingGlass.js:406
#: ../js/ui/lookingGlass.js:509
msgid "Out of date"
msgstr "Veraltet"
#: ../js/ui/lookingGlass.js:431
#: ../js/ui/lookingGlass.js:534
msgid "View Source"
msgstr "Quelle zeigen"
#: ../js/ui/lookingGlass.js:437
#: ../js/ui/lookingGlass.js:540
msgid "Web Page"
msgstr "Webseite"
#: ../js/ui/overview.js:182
#: ../js/ui/overview.js:161
msgid "Undo"
msgstr "Rückgängig"
#: ../js/ui/panel.js:535
msgid "Quit"
msgstr "Beenden"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:385
#: ../js/ui/panel.js:740
msgid "Activities"
msgstr "Aktivitäten"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:616
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:955
msgid "%a %b %e, %R:%S"
msgstr "%a, %e. %b, %R:%S"
#: ../js/ui/panel.js:956
msgid "%a %b %e, %R"
msgstr "%a, %e. %b, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:960
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:961
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:619
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:968
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a, %e. %b, %H:%M:%S"
#: ../js/ui/panel.js:969
msgid "%a %b %e, %l:%M %p"
msgstr "%a, %e. %b, %H:%M"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:973
msgid "%a %l:%M:%S %p"
msgstr "%a %H:%M:%S"
#: ../js/ui/panel.js:974
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#: ../js/ui/placeDisplay.js:103
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "»%s« konnte nicht ausgehängt werden"
#: ../js/ui/placeDisplay.js:106
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Erneut versuchen"
#: ../js/ui/placeDisplay.js:151
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Verbinden mit …"
#: ../js/ui/runDialog.js:232
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "Bitte geben Sie einen Befehl ein:"
#: ../js/ui/runDialog.js:374
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Ausführung von »%s« ist gescheitert:"
#: ../js/ui/statusMenu.js:107
#: ../js/ui/statusMenu.js:90
msgid "Available"
msgstr "Verfügbar"
#: ../js/ui/statusMenu.js:112
#: ../js/ui/statusMenu.js:94
msgid "Busy"
msgstr "Beschäftigt"
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:98
msgid "Invisible"
msgstr "Unsichtbar"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:105
msgid "Account Information..."
msgstr "Benutzerinformationen …"
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Seitenleiste"
#: ../js/ui/statusMenu.js:142
#: ../js/ui/statusMenu.js:109
msgid "System Preferences..."
msgstr "Systemeinstellungen …"
#: ../js/ui/statusMenu.js:151
#: ../js/ui/statusMenu.js:116
msgid "Lock Screen"
msgstr "Bildschirm sperren"
#: ../js/ui/statusMenu.js:156
#: ../js/ui/statusMenu.js:120
msgid "Switch User"
msgstr "Benutzer wechseln"
#: ../js/ui/statusMenu.js:162
#: ../js/ui/statusMenu.js:125
msgid "Log Out..."
msgstr "Abmelden …"
#: ../js/ui/statusMenu.js:167
#: ../js/ui/statusMenu.js:129
msgid "Shut Down..."
msgstr "Ausschalten …"
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Anwendungen"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Zuletzt geöffnete Dokumente"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
@ -223,32 +280,43 @@ msgstr "Start von %s ist abgeschlossen"
msgid "'%s' is ready"
msgstr "»%s« ist bereit"
#: ../src/shell-global.c:967
#: ../js/ui/workspacesView.js:239
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"Es kann keine weitere Arbeitsfläche hinzugefügt werden, weil das Maximum an "
"Arbeitsflächen erreicht worden ist."
#: ../js/ui/workspacesView.js:256
msgid "Can't remove the first workspace."
msgstr "Die erste Arbeitsfläche kann nicht entfernt werden."
#: ../src/shell-global.c:976
msgid "Less than a minute ago"
msgstr "Vor weniger als einer Minute"
#: ../src/shell-global.c:971
#: ../src/shell-global.c:980
#, 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:976
#: ../src/shell-global.c:985
#, 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:981
#: ../src/shell-global.c:990
#, 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:986
#: ../src/shell-global.c:995
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -279,6 +347,18 @@ msgstr "Suchen"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Sidebar"
#~ msgstr "Seitenleiste"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"
#~ msgid "Applications"
#~ msgstr "Anwendungen"
#~ msgid "Recent Documents"
#~ msgstr "Zuletzt geöffnete Dokumente"
#~ msgid "Frequent"
#~ msgstr "Häufig"

312
po/el.po
View File

@ -7,10 +7,10 @@
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell.po.master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell&component=general\n"
"POT-Creation-Date: 2009-10-04 08:03+0000\n"
"PO-Revision-Date: 2009-10-04 10:25+0200\n"
"Last-Translator: Jennie Petoumenou <epetoumenou@gmail.com>\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-28 10:46+0300\n"
"PO-Revision-Date: 2010-03-28 10:53+0200\n"
"Last-Translator: Kostas Papadimas <pkst@gnome.org>\n"
"Language-Team: Greek <<team AT BLOCKSPAM gnome DOT gr>>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -26,151 +26,244 @@ msgstr "Κέλυφος GNOME"
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:461
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/dash.js:283
msgid "Find..."
msgstr "Εύρεση..."
#: ../js/ui/dash.js:400
msgid "More"
msgstr "Περισσότερα"
#: ../js/ui/dash.js:543
msgid "(see all)"
msgstr "(εμφάνιση όλων)"
#. **** Applications ****
#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
#: ../js/ui/appDisplay.js:312
#: ../js/ui/dash.js:855
msgid "APPLICATIONS"
msgstr "ΕΦΑΡΜΟΓΕΣ"
#: ../js/ui/appDisplay.js:344
msgid "PREFERENCES"
msgstr "ΠΡΟΤΙΜΗΣΕΙΣ"
#: ../js/ui/appDisplay.js:756
msgid "New Window"
msgstr "Νέο παράθυρο"
#: ../js/ui/appDisplay.js:760
msgid "Remove from Favorites"
msgstr "Αφαίρεση από τα αγαπημένα"
#: ../js/ui/appDisplay.js:761
msgid "Add to Favorites"
msgstr "Προσθήκη στα αγαπημένα"
#: ../js/ui/appDisplay.js:1113
msgid "Drag here to add favorites"
msgstr "Σύρετε εδώ για να προσθέσετε αγαπημένα"
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s προστέθηκε στα αγαπημένα σας"
#: ../js/ui/appFavorites.js:107
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s αφαιρέθηκε από τα αγαπημένα σας"
#: ../js/ui/dash.js:194
msgid "Find"
msgstr "Εύρεση"
#: ../js/ui/dash.js:510
msgid "Searching..."
msgstr "Αναζήτηση..."
#: ../js/ui/dash.js:524
msgid "No matching results."
msgstr "Δεν βρέθηκαν ταιριάσματα."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:783
msgid "PLACES"
msgstr "ΤΟΠΟΘΕΣΙΕΣ"
#: ../js/ui/dash.js:874
#: ../js/ui/placeDisplay.js:582
msgid "PLACES & DEVICES"
msgstr "ΤΟΠΟΘΕΣΙΕΣ $ ΣΥΣΚΕΥΕΣ"
#. **** Documents ****
#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
msgid "RECENT DOCUMENTS"
msgstr "ΠΡΟΣΦΑΤΑ ΕΓΓΡΑΦΑ"
#: ../js/ui/dash.js:881
#: ../js/ui/docDisplay.js:488
msgid "RECENT ITEMS"
msgstr "ΠΡΟΣΦΑΤΑ ΑΝΤΙΚΕΙΜΕΝΑ"
#. **** Search Results ****
#: ../js/ui/dash.js:815 ../js/ui/dash.js:955
msgid "SEARCH RESULTS"
msgstr "ΑΠΟΤΕΛΕΣΜΑΤΑ ΑΝΑΖΗΤΗΣΗΣ"
#: ../js/ui/lookingGlass.js:363
msgid "No extensions installed"
msgstr "Δεν υπάρχουν εγκατεστημένες επεκτάσεις"
#: ../js/ui/dash.js:830
msgid "PREFERENCES"
msgstr "ΠΡΟΤΙΜΗΣΕΙΣ"
#: ../js/ui/lookingGlass.js:400
msgid "Enabled"
msgstr ""
#: ../js/ui/runDialog.js:96
#: ../js/ui/lookingGlass.js:402
msgid "Disabled"
msgstr ""
#: ../js/ui/lookingGlass.js:404
msgid "Error"
msgstr "Σφάλμα"
#: ../js/ui/lookingGlass.js:406
msgid "Out of date"
msgstr ""
#: ../js/ui/lookingGlass.js:431
msgid "View Source"
msgstr "Προβολή πηγής"
#: ../js/ui/lookingGlass.js:437
msgid "Web Page"
msgstr "Ιστοσελίδα"
#: ../js/ui/overview.js:182
msgid "Undo"
msgstr "Αναίρεση"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:385
msgid "Activities"
msgstr "Δραστηριότητες"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:616
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:619
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Αποτυχία αποπροσάρτησης '%s'"
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Προσπάθεια ξανά"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Σύνδεση σε..."
#: ../js/ui/runDialog.js:232
msgid "Please enter a command:"
msgstr "Παρακαλώ εισάγετε μία εντολή:"
#: ../src/shell-global.c:812
#: ../js/ui/runDialog.js:376
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Η εκτέλεση του '%s' απέτυχε:"
#: ../js/ui/statusMenu.js:107
msgid "Available"
msgstr "Διαθέσιμος"
#: ../js/ui/statusMenu.js:112
msgid "Busy"
msgstr "Απασχολημένος"
#: ../js/ui/statusMenu.js:117
msgid "Invisible"
msgstr "Αόρατος"
#: ../js/ui/statusMenu.js:126
msgid "Account Information..."
msgstr "Πληροφορίες λογαριασμού..."
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Πλευρική στήλη"
#: ../js/ui/statusMenu.js:142
msgid "System Preferences..."
msgstr "Προστιμήσεις συστήματος..."
#: ../js/ui/statusMenu.js:151
msgid "Lock Screen"
msgstr "Κλείδωμα οθόνης"
#: ../js/ui/statusMenu.js:156
msgid "Switch User"
msgstr "Αλλαγή χρήστη"
#: ../js/ui/statusMenu.js:162
msgid "Log Out..."
msgstr "Αποσύνδεση..."
#: ../js/ui/statusMenu.js:167
msgid "Shut Down..."
msgstr "Τερματισμός..."
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr ""
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Εφαρμογές"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Πρόσφατα έγγραφα"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s ολοκλήρωσε την εκκίνηση "
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr ""
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Λιγότερο από ένα λεπτό πριν"
#: ../src/shell-global.c:815
#: ../src/shell-global.c:971
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d λεπτό πριν"
msgstr[1] "%d λεπτά πριν"
#: ../src/shell-global.c:818
#: ../src/shell-global.c:976
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d ώρα πριν"
msgstr[1] "%d ώρες πριν"
#: ../src/shell-global.c:821
#: ../src/shell-global.c:981
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d ημέρα πριν"
msgstr[1] "%d ημέρες πριν"
#: ../src/shell-global.c:824
#: ../src/shell-global.c:986
#, 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
#: ../src/shell-uri-util.c:89
msgid "Home Folder"
msgstr "Προσωπικός φάκελος"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
#: ../src/shell-uri-util.c:104
msgid "File System"
msgstr "Σύστημα αρχείων"
#: ../src/shell-uri-util.c:248
#: ../src/shell-uri-util.c:250
msgid "Search"
msgstr "Αναζήτηση"
@ -179,8 +272,27 @@ msgstr "Αναζήτηση"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#: ../src/shell-uri-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "More"
#~ msgstr "Περισσότερα"
#~ msgid "(see all)"
#~ msgstr "(εμφάνιση όλων)"
#~ msgid "PLACES"
#~ msgstr "ΤΟΠΟΘΕΣΙΕΣ"
#~ msgid "SEARCH RESULTS"
#~ msgstr "ΑΠΟΤΕΛΕΣΜΑΤΑ ΑΝΑΖΗΤΗΣΗΣ"
#~ msgid "Unknown"
#~ msgstr "Άγνωστο"
#~ msgid "Can't lock screen: %s"
#~ msgstr "Αδύνατο το κλείδωμα της οθόνης: %s"
#~ msgid "Can't temporarily set screensaver to blank screen: %s"
#~ msgstr ""
#~ "Δεν είναι δυνατή η προσωρινή ρύθμιση της προστασίας οθόνης σε κενή οθόνη: "
#~ "%s"
#~ msgid "Can't logout: %s"
#~ msgstr "Αδύνατη η αποσύνδεση: %s"

202
po/es.po
View File

@ -2,13 +2,14 @@
# 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, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2010-03-20 22:48+0000\n"
"PO-Revision-Date: 2010-03-21 16:48+0100\n"
"POT-Creation-Date: 2010-05-19 16:31+0000\n"
"PO-Revision-Date: 2010-05-25 18:28+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"
@ -24,28 +25,66 @@ msgstr "GNOME Shell"
msgid "Window management and application launching"
msgstr "Gestión de ventanas e inicio de aplicaciones"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "Reloj"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "Personalizar el reloj del panel"
#: ../data/clock-preferences.ui.h:1
#| msgid "<b>Clock Format</b>"
msgid "Clock Format"
msgstr "Formato del reloj"
#: ../data/clock-preferences.ui.h:2
msgid "Clock Preferences"
msgstr "Preferencias del reloj"
#: ../data/clock-preferences.ui.h:3
#| msgid "<b>Panel Display</b>"
msgid "Panel Display"
msgstr "Panel de visualización"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "Mostrar los segu_ndos"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
msgstr "Mostrar la _fecha"
#: ../data/clock-preferences.ui.h:6
msgid "_12 hour format"
msgstr "Formato _12 horas"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "Formato _24 horas"
#. **** Applications ****
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:852
#: ../js/ui/appDisplay.js:306 ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "APLICACIONES"
#: ../js/ui/appDisplay.js:343
#: ../js/ui/appDisplay.js:338
msgid "PREFERENCES"
msgstr "PREFERENCIAS"
#: ../js/ui/appDisplay.js:728
#: ../js/ui/appDisplay.js:705
msgid "New Window"
msgstr "Ventana nueva"
#: ../js/ui/appDisplay.js:732
#: ../js/ui/appDisplay.js:709
msgid "Remove from Favorites"
msgstr "Quitar de los favoritos"
#: ../js/ui/appDisplay.js:733
#: ../js/ui/appDisplay.js:710
msgid "Add to Favorites"
msgstr "Añadir a los favoritos"
#: ../js/ui/appDisplay.js:1085
#: ../js/ui/appDisplay.js:1037
msgid "Drag here to add favorites"
msgstr "Arrastrar aquí para añadir a los favoritos"
@ -59,153 +98,166 @@ msgstr "Se ha añadido %s a sus favoritos."
msgid "%s has been removed from your favorites."
msgstr "Se ha quitado %s de sus favoritos."
#: ../js/ui/dash.js:194
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "Buscar"
#: ../js/ui/dash.js:507
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "Buscando…"
#: ../js/ui/dash.js:521
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "No se encontró ningún resultado coincidente."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:871 ../js/ui/placeDisplay.js:579
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "LUGARES Y DISPOSITIVOS"
#. **** Documents ****
#: ../js/ui/dash.js:878 ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "ELEMENTOS RECIENTES"
#: ../js/ui/lookingGlass.js:363
#: ../js/ui/lookingGlass.js:466
msgid "No extensions installed"
msgstr "No hay extensiones instaladas"
#: ../js/ui/lookingGlass.js:400
#: ../js/ui/lookingGlass.js:503
msgid "Enabled"
msgstr "Activado"
#: ../js/ui/lookingGlass.js:402
#: ../js/ui/lookingGlass.js:505
msgid "Disabled"
msgstr "Desactivado"
#: ../js/ui/lookingGlass.js:404
#: ../js/ui/lookingGlass.js:507
msgid "Error"
msgstr "Error"
#: ../js/ui/lookingGlass.js:406
#: ../js/ui/lookingGlass.js:509
msgid "Out of date"
msgstr "Caducado"
#: ../js/ui/lookingGlass.js:431
#: ../js/ui/lookingGlass.js:534
msgid "View Source"
msgstr "Ver fuente"
#: ../js/ui/lookingGlass.js:437
#: ../js/ui/lookingGlass.js:540
msgid "Web Page"
msgstr "Página web"
#: ../js/ui/overview.js:182
#: ../js/ui/overview.js:161
msgid "Undo"
msgstr "Deshacer"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:385
#: ../js/ui/panel.js:774
msgid "Activities"
msgstr "Actividades"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:616
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:989
msgid "%a %b %e, %R:%S"
msgstr "%a %e de %b, %R:%S"
#: ../js/ui/panel.js:990
msgid "%a %b %e, %R"
msgstr "%a %e de %b, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:994
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:995
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:619
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:1002
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %e de %b, %H:%M:%S"
#: ../js/ui/panel.js:1003
msgid "%a %b %e, %l:%M %p"
msgstr "%a %e de %b, %H:%M"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:1007
msgid "%a %l:%M:%S %p"
msgstr "%a %H:%M:%S"
#: ../js/ui/panel.js:1008
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#: ../js/ui/placeDisplay.js:103
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Falló al desmontar «%s»"
#: ../js/ui/placeDisplay.js:106
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Reintentar"
#: ../js/ui/placeDisplay.js:151
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Conectar a…"
#: ../js/ui/runDialog.js:232
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "Introduzca un comando:"
#: ../js/ui/runDialog.js:374
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Falló la ejecución de «%s»:"
#: ../js/ui/statusMenu.js:107
#: ../js/ui/statusMenu.js:90
msgid "Available"
msgstr "Disponible"
#: ../js/ui/statusMenu.js:112
#: ../js/ui/statusMenu.js:94
msgid "Busy"
msgstr "Ocupado"
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:98
msgid "Invisible"
msgstr "Invisible"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:105
msgid "Account Information..."
msgstr "Información de la cuenta…"
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Barra lateral"
#: ../js/ui/statusMenu.js:142
#: ../js/ui/statusMenu.js:109
msgid "System Preferences..."
msgstr "Preferencias del sistema…"
#: ../js/ui/statusMenu.js:151
#: ../js/ui/statusMenu.js:116
msgid "Lock Screen"
msgstr "Bloquear la pantalla"
#: ../js/ui/statusMenu.js:156
#: ../js/ui/statusMenu.js:120
msgid "Switch User"
msgstr "Cambiar de usuario"
#: ../js/ui/statusMenu.js:162
#: ../js/ui/statusMenu.js:125
msgid "Log Out..."
msgstr "Salir…"
#: ../js/ui/statusMenu.js:167
#: ../js/ui/statusMenu.js:129
msgid "Shut Down..."
msgstr "Apagar…"
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Aplicaciones"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Documentos recientes"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
@ -216,32 +268,43 @@ msgstr "%s finalizó su lanzamiento"
msgid "'%s' is ready"
msgstr "«%s» está preparado"
#: ../src/shell-global.c:967
#: ../js/ui/workspacesView.js:239
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"No se puede añadir un área de trabajo nueva porque se ha llegado al límite "
"de áreas de trabajo."
#: ../js/ui/workspacesView.js:256
msgid "Can't remove the first workspace."
msgstr "No se puede quitar el primer área de trabajo."
#: ../src/shell-global.c:976
msgid "Less than a minute ago"
msgstr "Hace menos de un minuto"
#: ../src/shell-global.c:971
#: ../src/shell-global.c:980
#, 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:976
#: ../src/shell-global.c:985
#, 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:981
#: ../src/shell-global.c:990
#, 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:986
#: ../src/shell-global.c:995
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -272,6 +335,21 @@ msgstr "Buscar"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Quit"
#~ msgstr "Salir"
#~ msgid "Sidebar"
#~ msgstr "Barra lateral"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"
#~ msgid "Applications"
#~ msgstr "Aplicaciones"
#~ msgid "Recent Documents"
#~ msgstr "Documentos recientes"
#~ msgid "PLACES"
#~ msgstr "LUGARES"

203
po/fr.po
View File

@ -11,7 +11,7 @@ msgstr ""
"Project-Id-Version: gnome-shell master fr\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2010-03-08 23:07+0000\n"
"POT-Creation-Date: 2010-05-15 22:41+0000\n"
"PO-Revision-Date: 2010-03-09 22:55+0100\n"
"Last-Translator: Claude Paroz <claude@2xlibre.net>\n"
"Language-Team: GNOME French Team <gnomefr@traduc.org>\n"
@ -28,28 +28,64 @@ msgstr "GNOME Shell"
msgid "Window management and application launching"
msgstr "Gestion des fenêtres et lancement des applications"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "Horloge"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "Personnaliser l'horloge du tableau de bord"
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
msgstr "Format de l'horloge"
#: ../data/clock-preferences.ui.h:2
msgid "Panel Display"
msgstr "Affichage dans le tableau de bord"
#: ../data/clock-preferences.ui.h:3
msgid "Clock Preferences"
msgstr "Préférences de l'horloge"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "Afficher les _secondes"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
msgstr "Afficher la _date"
#: ../data/clock-preferences.ui.h:6
msgid "_12 hour format"
msgstr "Format _12 heures"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "Format _24 heures"
#. **** Applications ****
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:886
#: ../js/ui/appDisplay.js:306 ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "APPLICATIONS"
#: ../js/ui/appDisplay.js:343
#: ../js/ui/appDisplay.js:338
msgid "PREFERENCES"
msgstr "PRÉFÉRENCES"
#: ../js/ui/appDisplay.js:728
#: ../js/ui/appDisplay.js:705
msgid "New Window"
msgstr "Nouvelle fenêtre"
#: ../js/ui/appDisplay.js:732
#: ../js/ui/appDisplay.js:709
msgid "Remove from Favorites"
msgstr "Enlever des favoris"
#: ../js/ui/appDisplay.js:733
#: ../js/ui/appDisplay.js:710
msgid "Add to Favorites"
msgstr "Ajouter aux favoris"
#: ../js/ui/appDisplay.js:1085
#: ../js/ui/appDisplay.js:1037
msgid "Drag here to add favorites"
msgstr "Glisser ici pour ajouter aux favoris"
@ -63,170 +99,217 @@ msgstr "%s a été ajouté à vos favoris."
msgid "%s has been removed from your favorites."
msgstr "%s a été supprimé de vos favoris."
#: ../js/ui/dash.js:235
msgid "Find..."
msgstr "Rechercher..."
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "Rechercher"
#: ../js/ui/dash.js:511
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "Recherche en cours..."
#: ../js/ui/dash.js:525
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "Aucun résultat correspondant."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:905 ../js/ui/placeDisplay.js:529
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "RACCOURCIS et PÉRIPHÉRIQUES"
#. **** Documents ****
#: ../js/ui/dash.js:912 ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "ÉLÉMENTS RÉCENTS"
#: ../js/ui/lookingGlass.js:363
#: ../js/ui/lookingGlass.js:354
msgid "No extensions installed"
msgstr "Aucune extension installée"
#: ../js/ui/lookingGlass.js:400
#: ../js/ui/lookingGlass.js:391
msgid "Enabled"
msgstr "Activé"
#: ../js/ui/lookingGlass.js:402
#: ../js/ui/lookingGlass.js:393
msgid "Disabled"
msgstr "Désactivé"
#: ../js/ui/lookingGlass.js:404
#: ../js/ui/lookingGlass.js:395
msgid "Error"
msgstr "Erreur"
#: ../js/ui/lookingGlass.js:406
#: ../js/ui/lookingGlass.js:397
msgid "Out of date"
msgstr "Périmé"
#: ../js/ui/lookingGlass.js:431
#: ../js/ui/lookingGlass.js:422
msgid "View Source"
msgstr "Afficher la source"
#: ../js/ui/lookingGlass.js:437
#: ../js/ui/lookingGlass.js:428
msgid "Web Page"
msgstr "Page Web"
#: ../js/ui/overview.js:92
#: ../js/ui/overview.js:161
msgid "Undo"
msgstr "Annuler"
#: ../js/ui/panel.js:535
msgid "Quit"
msgstr "Quitter"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:399
#: ../js/ui/panel.js:740
msgid "Activities"
msgstr "Activités"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:630
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:955
msgid "%a %b %e, %R:%S"
msgstr "%a %e %b, %R:%S"
#: ../js/ui/panel.js:956
msgid "%a %b %e, %R"
msgstr "%a %e %b, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:960
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:961
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:633
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:968
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %e %b, %l:%M:%S %p"
#: ../js/ui/placeDisplay.js:144
#: ../js/ui/panel.js:969
msgid "%a %b %e, %l:%M %p"
msgstr "%a %e %b, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:973
msgid "%a %l:%M:%S %p"
msgstr "%a %l:%M:%S %p"
#: ../js/ui/panel.js:974
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Impossible de monter « %s »"
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Réessayer"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Connexion à..."
#: ../js/ui/runDialog.js:221
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "Veuillez saisir une commande :"
#: ../js/ui/runDialog.js:344
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Exécution de « %s » impossible :"
#: ../js/ui/statusMenu.js:107
#: ../js/ui/statusMenu.js:90
msgid "Available"
msgstr "Disponible"
#: ../js/ui/statusMenu.js:112
#: ../js/ui/statusMenu.js:94
msgid "Busy"
msgstr "Occupé"
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:98
msgid "Invisible"
msgstr "Invisible"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:105
msgid "Account Information..."
msgstr "Informations personnelles..."
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Barre latérale"
#: ../js/ui/statusMenu.js:142
#: ../js/ui/statusMenu.js:109
msgid "System Preferences..."
msgstr "Préférences du système..."
#: ../js/ui/statusMenu.js:151
#: ../js/ui/statusMenu.js:116
msgid "Lock Screen"
msgstr "Verrouiller l'écran"
#: ../js/ui/statusMenu.js:156
#: ../js/ui/statusMenu.js:120
msgid "Switch User"
msgstr "Changer d'utilisateur"
#: ../js/ui/statusMenu.js:162
#: ../js/ui/statusMenu.js:125
msgid "Log Out..."
msgstr "Fermer la session..."
#: ../js/ui/statusMenu.js:167
#: ../js/ui/statusMenu.js:129
msgid "Shut Down..."
msgstr "Éteindre..."
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "Lancement de %s terminé"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Applications"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "« %s » est prêt"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Documents récents"
#: ../js/ui/workspacesView.js:239
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"Impossible d'ajouter un espace de travail car le nombre maximum d'espaces de "
"travail est atteint."
#: ../src/shell-global.c:967
#: ../js/ui/workspacesView.js:256
msgid "Can't remove the first workspace."
msgstr "Impossible de supprimer le premier espace de travail."
#: ../src/shell-global.c:979
msgid "Less than a minute ago"
msgstr "Il y a moins d'une minute"
#: ../src/shell-global.c:971
#: ../src/shell-global.c:983
#, 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:976
#: ../src/shell-global.c:988
#, 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:981
#: ../src/shell-global.c:993
#, 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:986
#: ../src/shell-global.c:998
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"

223
po/gl.po
View File

@ -1,17 +1,17 @@
# 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.
# Anton Meixome <certima@certima.net>, 2009.
# Antón Méixome <meixome@certima.net>, 2009.
# Fran Diéguez <frandieguez@ubuntu.com>, 2009, 2010.
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-12-28 17:07+0100\n"
"PO-Revision-Date: 2009-12-28 08:11+0100\n"
"Last-Translator: Antón Méixome <meixome@certima.net>\n"
"Language-Team: Galician Proxecto Trasno <proxecto@trasno.net>\n"
"POT-Creation-Date: 2010-04-09 19:17+0200\n"
"PO-Revision-Date: 2010-04-09 19:40+0200\n"
"Last-Translator: Fran Diéguez <frandieguez@ubuntu.com>\n"
"Language-Team: Galician <gnome@g11n.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -25,116 +25,209 @@ msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Xestor de xanelas e lanzamento de aplicativos"
msgstr "Xestor de xanelas e inicio de aplicativos"
#. **** Applications ****
#: ../js/ui/appDisplay.js:252 ../js/ui/dash.js:858
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "APLICATIVOS"
#: ../js/ui/appDisplay.js:276
#: ../js/ui/appDisplay.js:343
msgid "PREFERENCES"
msgstr "PREFERENCIAS"
#: ../js/ui/appDisplay.js:707 ../js/ui/appIcon.js:425
#: ../js/ui/appDisplay.js:723
msgid "New Window"
msgstr "Xanela nova"
#: ../js/ui/appDisplay.js:711 ../js/ui/appIcon.js:429
#: ../js/ui/appDisplay.js:727
msgid "Remove from Favorites"
msgstr "Eliminar de Favoritos"
msgstr "Eliminar dos favoritos"
#: ../js/ui/appDisplay.js:712 ../js/ui/appIcon.js:430
#: ../js/ui/appDisplay.js:728
msgid "Add to Favorites"
msgstr "Engadir a Favoritos"
msgstr "Engadir aos favoritos"
#: ../js/ui/appDisplay.js:1064
#: ../js/ui/appDisplay.js:1055
msgid "Drag here to add favorites"
msgstr "Arrastra aquí para engadir favoritos"
msgstr "Arrastre aquí para engadir aos favoritos"
#: ../js/ui/dash.js:240
msgid "Find..."
msgstr "Buscar..."
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s foi engadido aos seus favoritos."
#: ../js/ui/dash.js:437
#: ../js/ui/appFavorites.js:107
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s foi eliminado dos seus favoritos."
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "Buscar"
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "Buscando..."
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "Non hai resultados que coincidan."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:878 ../js/ui/placeDisplay.js:519
msgid "PLACES"
msgstr "LUGARES"
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "LUGARES e DISPOSITIVOS"
#. **** Documents ****
#: ../js/ui/dash.js:885
msgid "RECENT DOCUMENTS"
msgstr "DOCUMENTOS RECENTES"
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "ELEMENTOS RECENTES"
#: ../js/ui/lookingGlass.js:362
msgid "No extensions installed"
msgstr "Non hai ningunha extensión instalada"
#: ../js/ui/lookingGlass.js:399
msgid "Enabled"
msgstr "Activado"
#: ../js/ui/lookingGlass.js:401
msgid "Disabled"
msgstr "Desactivado"
#: ../js/ui/lookingGlass.js:403
msgid "Error"
msgstr "Erro"
#: ../js/ui/lookingGlass.js:405
msgid "Out of date"
msgstr "Desactualizado"
#: ../js/ui/lookingGlass.js:430
msgid "View Source"
msgstr "Ver fonte"
#: ../js/ui/lookingGlass.js:436
msgid "Web Page"
msgstr "Páxina web"
#: ../js/ui/overview.js:181
msgid "Undo"
msgstr "Desfacer"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:227
#: ../js/ui/panel.js:374
msgid "Activities"
msgstr "Actividades"
#. Translators: This is a time format.
#: ../js/ui/panel.js:440
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:594
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:597
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/placeDisplay.js:144
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Produciuse un fallo ao montar '%s'"
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Reintentar"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Conectar con..."
#: ../js/ui/runDialog.js:235
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "Insira unha orde:"
#: ../js/ui/runDialog.js:351
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Fallou a execución de %s"
msgstr "Produciuse un fallo na execución de %s"
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/statusMenu.js:105
msgid "Available"
msgstr "Dispoñíbel"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Aplicativos"
#: ../js/ui/statusMenu.js:110
msgid "Busy"
msgstr "Ocupado"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Documentos recentes"
#: ../js/ui/statusMenu.js:115
msgid "Invisible"
msgstr "Invisíbel"
#: ../src/shell-global.c:890
#: ../js/ui/statusMenu.js:124
msgid "Account Information..."
msgstr "Información da conta..."
#: ../js/ui/statusMenu.js:129
msgid "System Preferences..."
msgstr "Preferencias do sistema..."
#: ../js/ui/statusMenu.js:138
msgid "Lock Screen"
msgstr "Bloquear pantalla"
#: ../js/ui/statusMenu.js:143
msgid "Switch User"
msgstr "Cambiar de usuario"
#: ../js/ui/statusMenu.js:149
msgid "Log Out..."
msgstr "Saír da sesión..."
#: ../js/ui/statusMenu.js:154
msgid "Shut Down..."
msgstr "Apagar..."
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s rematou de iniarse"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "'%s' está preparado"
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Hai menos dun minuto"
#: ../src/shell-global.c:893
#: ../src/shell-global.c:971
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "hai %d minuto"
msgstr[1] "hai %d minutos"
#: ../src/shell-global.c:896
#: ../src/shell-global.c:976
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "hai %d hora"
msgstr[1] "hai %d horas"
#: ../src/shell-global.c:899
#: ../src/shell-global.c:981
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "hai %d día"
msgstr[1] "hai %d días"
#: ../src/shell-global.c:902
#: ../src/shell-global.c:986
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -165,6 +258,21 @@ msgstr "Buscar"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Sidebar"
#~ msgstr "Barra lateral"
#~ msgid "%H:%M"
#~ msgstr "%M:%H"
#~ msgid "Applications"
#~ msgstr "Aplicativos"
#~ msgid "Recent Documents"
#~ msgstr "Documentos recentes"
#~ msgid "PLACES"
#~ msgstr "LUGARES"
#~ msgid "SEARCH RESULTS"
#~ msgstr "RESULTADOS DA BUSCA"
@ -182,27 +290,6 @@ msgstr "%1$s: %2$s"
#~ msgid "Can't logout: %s"
#~ msgstr "Non foi posíbel pechar a sesión: %s"
#~ msgid "Account Information..."
#~ msgstr "Información da conta..."
#~ msgid "Sidebar"
#~ msgstr "Barra lateral"
#~ msgid "System Preferences..."
#~ msgstr "Preferencias do sistema..."
#~ msgid "Lock Screen"
#~ msgstr "Bloquear pantalla"
#~ msgid "Switch User"
#~ msgstr "Cambiar de usuario"
#~ msgid "Log Out..."
#~ msgstr "Saír da sesión..."
#~ msgid "Shut Down..."
#~ msgstr "Apagar..."
#~ msgid "Browse"
#~ msgstr "Explorar"

View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-02-16 10:04+0100\n"
"PO-Revision-Date: 2010-02-16 10:10+0100\n"
"POT-Creation-Date: 2010-03-24 14:25+0100\n"
"PO-Revision-Date: 2010-03-24 14:26+0100\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"
@ -26,27 +26,27 @@ msgid "Window management and application launching"
msgstr "Ablakkezelés és alkalmazásindítás"
#. **** Applications ****
#: ../js/ui/appDisplay.js:252 ../js/ui/dash.js:880
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:852
msgid "APPLICATIONS"
msgstr "ALKALMAZÁSOK"
#: ../js/ui/appDisplay.js:276
#: ../js/ui/appDisplay.js:343
msgid "PREFERENCES"
msgstr "BEÁLLÍTÁSOK"
#: ../js/ui/appDisplay.js:649
#: ../js/ui/appDisplay.js:729
msgid "New Window"
msgstr "Új ablak"
#: ../js/ui/appDisplay.js:653
#: ../js/ui/appDisplay.js:733
msgid "Remove from Favorites"
msgstr "Eltávolítás a Kedvencek közül"
#: ../js/ui/appDisplay.js:654
#: ../js/ui/appDisplay.js:734
msgid "Add to Favorites"
msgstr "Hozzáadás a Kedvencekhez"
#: ../js/ui/appDisplay.js:1006
#: ../js/ui/appDisplay.js:1086
msgid "Drag here to add favorites"
msgstr "Ide húzással kedvenceket vehet fel"
@ -60,87 +60,96 @@ msgstr "%s felvéve a Kedvencek közé."
msgid "%s has been removed from your favorites."
msgstr "%s eltávolítva a Kedvencek közül"
#: ../js/ui/dash.js:241
msgid "Find..."
msgstr "Keresés"
#: ../js/ui/dash.js:194
msgid "Find"
msgstr "Keresés"
#: ../js/ui/dash.js:508
#: ../js/ui/dash.js:507
msgid "Searching..."
msgstr "Keresés…"
#: ../js/ui/dash.js:522
#: ../js/ui/dash.js:521
msgid "No matching results."
msgstr "Nincs találat."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:900 ../js/ui/placeDisplay.js:529
#: ../js/ui/dash.js:871 ../js/ui/placeDisplay.js:580
msgid "PLACES & DEVICES"
msgstr "HELYEK ÉS ESZKÖZÖK"
#. **** Documents ****
#: ../js/ui/dash.js:907 ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:878 ../js/ui/docDisplay.js:488
msgid "RECENT ITEMS"
msgstr "LEGUTÓBBI ELEMEK"
#: ../js/ui/lookingGlass.js:356
#: ../js/ui/lookingGlass.js:363
msgid "No extensions installed"
msgstr "Nincsenek kiterjesztések telepítve"
#: ../js/ui/lookingGlass.js:393
#: ../js/ui/lookingGlass.js:400
msgid "Enabled"
msgstr "Engedélyezve"
#: ../js/ui/lookingGlass.js:395
#: ../js/ui/lookingGlass.js:402
msgid "Disabled"
msgstr "Tiltva"
#: ../js/ui/lookingGlass.js:397
#: ../js/ui/lookingGlass.js:404
msgid "Error"
msgstr "Hiba"
#: ../js/ui/lookingGlass.js:399
#: ../js/ui/lookingGlass.js:406
msgid "Out of date"
msgstr "Elavult"
#: ../js/ui/lookingGlass.js:424
#: ../js/ui/lookingGlass.js:431
msgid "View Source"
msgstr "Forrás megtekintése"
#: ../js/ui/lookingGlass.js:430
#: ../js/ui/lookingGlass.js:437
msgid "Web Page"
msgstr "Weblap"
#: ../js/ui/overview.js:92
#: ../js/ui/overview.js:182
msgid "Undo"
msgstr "Visszavonás"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:336
#: ../js/ui/panel.js:385
msgid "Activities"
msgstr "Tevékenységek"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:560
#: ../js/ui/panel.js:616
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:563
#: ../js/ui/panel.js:619
msgid "%a %l:%M %p"
msgstr "%a, %p %l.%M"
#: ../js/ui/placeDisplay.js:144
#: ../js/ui/placeDisplay.js:103
#, c-format
msgid "Failed to unmount '%s'"
msgstr "„%s” leválasztása meghiúsult"
#: ../js/ui/placeDisplay.js:106
msgid "Retry"
msgstr "Újra"
#: ../js/ui/placeDisplay.js:151
msgid "Connect to..."
msgstr "Kapcsolódás…"
#: ../js/ui/runDialog.js:245
#: ../js/ui/runDialog.js:232
msgid "Please enter a command:"
msgstr "Adjon meg egy parancsot:"
#: ../js/ui/runDialog.js:361
#: ../js/ui/runDialog.js:376
#, c-format
msgid "Execution of '%s' failed:"
msgstr "„%s” végrehajtása meghiúsult:"
@ -198,32 +207,42 @@ msgstr "Alkalmazások"
msgid "Recent Documents"
msgstr "Legutóbbi dokumentumok"
#: ../src/shell-global.c:976
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s indítása befejeződött"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "„%s” kész"
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Kevesebb, mint egy perce"
#: ../src/shell-global.c:980
#: ../src/shell-global.c:971
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d perce"
msgstr[1] "%d perce"
#: ../src/shell-global.c:985
#: ../src/shell-global.c:976
#, 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:990
#: ../src/shell-global.c:981
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d napja"
msgstr[1] "%d napja"
#: ../src/shell-global.c:995
#: ../src/shell-global.c:986
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"

216
po/it.po
View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-02-10 22:30+0100\n"
"PO-Revision-Date: 2010-02-10 22:31+0100\n"
"POT-Creation-Date: 2010-04-06 21:27+0200\n"
"PO-Revision-Date: 2010-04-06 22:51+0200\n"
"Last-Translator: Milo Casagrande <milo@ubuntu.com>\n"
"Language-Team: Italian <tp@lists.linux.it>\n"
"MIME-Version: 1.0\n"
@ -25,118 +25,211 @@ msgid "Window management and application launching"
msgstr "Gestione finestre e avvio applicazioni"
#. **** Applications ****
#: ../js/ui/appDisplay.js:252 ../js/ui/dash.js:880
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "Applicazioni"
#: ../js/ui/appDisplay.js:276
#: ../js/ui/appDisplay.js:343
msgid "PREFERENCES"
msgstr "Preferenze"
#: ../js/ui/appDisplay.js:649
#: ../js/ui/appDisplay.js:723
msgid "New Window"
msgstr "Nuova finestra"
#: ../js/ui/appDisplay.js:653
#: ../js/ui/appDisplay.js:727
msgid "Remove from Favorites"
msgstr "Rimuovi dai preferiti"
#: ../js/ui/appDisplay.js:654
#: ../js/ui/appDisplay.js:728
msgid "Add to Favorites"
msgstr "Aggiungi ai preferiti"
#: ../js/ui/appDisplay.js:1006
#: ../js/ui/appDisplay.js:1055
msgid "Drag here to add favorites"
msgstr "Trascinare qui per aggiungere ai preferiti"
#: ../js/ui/dash.js:241
msgid "Find..."
msgstr "Trova..."
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s è stato aggiunto ai preferiti."
#: ../js/ui/dash.js:508
#: ../js/ui/appFavorites.js:107
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s è stato rimosso dai preferiti."
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "Trova"
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "Ricerca..."
#: ../js/ui/dash.js:522
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "Nessun risultato."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:900 ../js/ui/placeDisplay.js:529
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "Risorse e dispositivi"
#. **** Documents ****
#: ../js/ui/dash.js:907
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "Elementi recenti"
#: ../js/ui/lookingGlass.js:362
msgid "No extensions installed"
msgstr "Nessuna estensione installata"
# (ndt) o abilitata?
#: ../js/ui/lookingGlass.js:399
msgid "Enabled"
msgstr "Abilitato"
# (ndt) o disabilitata?
#: ../js/ui/lookingGlass.js:401
msgid "Disabled"
msgstr "Disabilitato"
#: ../js/ui/lookingGlass.js:403
msgid "Error"
msgstr "Errore"
#: ../js/ui/lookingGlass.js:405
msgid "Out of date"
msgstr "Non aggiornato"
#: ../js/ui/lookingGlass.js:430
msgid "View Source"
msgstr "Visualizza sorgente"
#: ../js/ui/lookingGlass.js:436
msgid "Web Page"
msgstr "Pagina web"
#: ../js/ui/overview.js:181
msgid "Undo"
msgstr "Annulla"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:336
#: ../js/ui/panel.js:374
msgid "Activities"
msgstr "Attività"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:594
msgid "%a %R"
msgstr "%a %k.%M"
# (ndt) proviamo col k, se non funge, sappiamo il perché...
#. Translators: This is a time format.
#: ../js/ui/panel.js:557
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:597
msgid "%a %l:%M %p"
msgstr "%a %k.%M"
#: ../js/ui/placeDisplay.js:144
# (ndt) libera, ma unmount non si può proprio vedere...
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Impossibile scollegare «%s»"
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Riprova"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Connetti a..."
#: ../js/ui/runDialog.js:245
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "Inserire un comando:"
#: ../js/ui/runDialog.js:361
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Esecuzione di «%s» non riuscita:"
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%k.%M"
#: ../js/ui/statusMenu.js:105
msgid "Available"
msgstr "Disponibile"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Applicazioni"
#: ../js/ui/statusMenu.js:110
msgid "Busy"
msgstr "Non disponibile"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Documenti recenti"
#: ../js/ui/statusMenu.js:115
msgid "Invisible"
msgstr "Invisibile"
#: ../src/shell-global.c:976
#: ../js/ui/statusMenu.js:124
msgid "Account Information..."
msgstr "Informazioni account..."
#: ../js/ui/statusMenu.js:129
msgid "System Preferences..."
msgstr "Preferenze di sistema..."
#: ../js/ui/statusMenu.js:138
msgid "Lock Screen"
msgstr "Blocca schermo"
#: ../js/ui/statusMenu.js:143
msgid "Switch User"
msgstr "Cambia utente"
#: ../js/ui/statusMenu.js:149
msgid "Log Out..."
msgstr "Termina sessione..."
#: ../js/ui/statusMenu.js:154
msgid "Shut Down..."
msgstr "Arresta..."
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "Avvio di %s completato"
# (ndt) dovrebbe essere il nome dell'applicazione
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "«%s» è pronto"
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Meno di un minuto fa"
#: ../src/shell-global.c:980
#: ../src/shell-global.c:971
#, 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:985
#: ../src/shell-global.c:976
#, 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:990
#: ../src/shell-global.c:981
#, 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:995
#: ../src/shell-global.c:986
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -167,54 +260,3 @@ msgstr "Cerca"
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "PLACES"
#~ msgstr "Risorse"
#~ msgid "Frequent"
#~ msgstr "Frequente"
#~ msgid "More"
#~ msgstr "Altro"
#~ msgid "(see all)"
#~ msgstr "(vedi tutto)"
#~ msgid "SEARCH RESULTS"
#~ msgstr "Risultati ricerca"
# (ndt) valutare se vada al femminile
#~ msgid "Unknown"
#~ msgstr "Sconosciuto"
#~ msgid "Can't lock screen: %s"
#~ msgstr "Impossibile bloccare lo schermo: %s"
#~ msgid "Can't temporarily set screensaver to blank screen: %s"
#~ msgstr ""
#~ "Impossibile impostare temporaneamente il salva schermo a schermo nero: %s "
#~ msgid "Can't logout: %s"
#~ msgstr "Impossibile terminare la sessione: %s"
#~ msgid "Account Information..."
#~ msgstr "Informazioni account..."
#~ msgid "Sidebar"
#~ msgstr "Barra laterale"
#~ msgid "System Preferences..."
#~ msgstr "Preferenze di sistema..."
#~ msgid "Lock Screen"
#~ msgstr "Blocca schermo"
#~ msgid "Switch User"
#~ msgstr "Cambia utente"
#~ msgid "Log Out..."
#~ msgstr "Termina sessione..."
# (ndt) da valutare... pare che ora anche Windows usi 'Arresta...'...
#~ msgid "Shut Down..."
#~ msgstr "Spegni..."

199
po/nb.po
View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell 2.28.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-03-09 17:45+0100\n"
"PO-Revision-Date: 2010-03-09 17:47+0100\n"
"POT-Creation-Date: 2010-05-24 16:28+0200\n"
"PO-Revision-Date: 2010-05-24 16:29+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"
@ -24,28 +24,64 @@ msgstr "GNOME Shell"
msgid "Window management and application launching"
msgstr "Vindushåndtering og oppstart av programmer"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "Klokke"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "Tilpass klokken på panelet"
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
msgstr "Klokkeformat"
#: ../data/clock-preferences.ui.h:2
msgid "Clock Preferences"
msgstr "Brukervalg for klokke"
#: ../data/clock-preferences.ui.h:3
msgid "Panel Display"
msgstr "Panelvisning"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "Vis seku_nder"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
msgstr "Vis _dato"
#: ../data/clock-preferences.ui.h:6
msgid "_12 hour format"
msgstr "_12-timers format"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "_24-timers format"
#. **** Applications ****
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:886
#: ../js/ui/appDisplay.js:306 ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "PROGRAMMER"
#: ../js/ui/appDisplay.js:343
#: ../js/ui/appDisplay.js:338
msgid "PREFERENCES"
msgstr "BRUKERVALG"
#: ../js/ui/appDisplay.js:728
#: ../js/ui/appDisplay.js:705
msgid "New Window"
msgstr "Nytt vindu"
#: ../js/ui/appDisplay.js:732
#: ../js/ui/appDisplay.js:709
msgid "Remove from Favorites"
msgstr "Fjern fra favoritter"
#: ../js/ui/appDisplay.js:733
#: ../js/ui/appDisplay.js:710
msgid "Add to Favorites"
msgstr "Legg til i favoritter"
#: ../js/ui/appDisplay.js:1085
#: ../js/ui/appDisplay.js:1037
msgid "Drag here to add favorites"
msgstr "Dra hit for å legge til favoritter"
@ -59,170 +95,211 @@ msgstr "%s ble lagt til i dine favoritter."
msgid "%s has been removed from your favorites."
msgstr "%s ble fjernet fra dine favoritter."
#: ../js/ui/dash.js:235
msgid "Find..."
msgstr "Finn..."
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "Finn"
#: ../js/ui/dash.js:511
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "Søker..."
#: ../js/ui/dash.js:525
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "Ingen treff."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:905 ../js/ui/placeDisplay.js:529
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "STEDER & ENHETER"
#. **** Documents ****
#: ../js/ui/dash.js:912 ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "SISTE OPPFØRINGER"
#: ../js/ui/lookingGlass.js:363
#: ../js/ui/lookingGlass.js:466
msgid "No extensions installed"
msgstr "Ingen utvidelser installert"
#: ../js/ui/lookingGlass.js:400
#: ../js/ui/lookingGlass.js:503
msgid "Enabled"
msgstr "Aktivert"
#: ../js/ui/lookingGlass.js:402
#: ../js/ui/lookingGlass.js:505
msgid "Disabled"
msgstr "Deaktivert"
#: ../js/ui/lookingGlass.js:404
#: ../js/ui/lookingGlass.js:507
msgid "Error"
msgstr "Feil"
#: ../js/ui/lookingGlass.js:406
#: ../js/ui/lookingGlass.js:509
msgid "Out of date"
msgstr "Utdatert"
#: ../js/ui/lookingGlass.js:431
#: ../js/ui/lookingGlass.js:534
msgid "View Source"
msgstr "Vis kildekode"
#: ../js/ui/lookingGlass.js:437
#: ../js/ui/lookingGlass.js:540
msgid "Web Page"
msgstr "Nettside"
#: ../js/ui/overview.js:92
#: ../js/ui/overview.js:161
msgid "Undo"
msgstr "Angre"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:399
#: ../js/ui/panel.js:887
msgid "Activities"
msgstr "Aktiviteter"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:630
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:1102
msgid "%a %b %e, %R:%S"
msgstr "%a %e %b, %R.%S"
#: ../js/ui/panel.js:1103
msgid "%a %b %e, %R"
msgstr "%a %e %b, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:1107
msgid "%a %R:%S"
msgstr "%a %R.%S"
#: ../js/ui/panel.js:1108
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:633
msgid "%a %l:%M %p"
msgstr "%a %H:%M"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:1115
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %e %b, %l.%M.%S %p"
#: ../js/ui/placeDisplay.js:144
#: ../js/ui/panel.js:1116
msgid "%a %b %e, %l:%M %p"
msgstr "%a %e %b, %l.%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:1120
msgid "%a %l:%M:%S %p"
msgstr "%a %l.%M.%S %p"
#: ../js/ui/panel.js:1121
msgid "%a %l:%M %p"
msgstr "%a %l.%M %p"
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Klarte ikke å avmontere «%s»"
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Prøv igjen"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Koble til..."
#: ../js/ui/runDialog.js:221
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "Oppgi en kommando:"
#: ../js/ui/runDialog.js:344
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Kjøring av «%s» feilet:"
#: ../js/ui/statusMenu.js:107
#: ../js/ui/statusMenu.js:90
msgid "Available"
msgstr "Tilgjengelig"
#: ../js/ui/statusMenu.js:112
#: ../js/ui/statusMenu.js:94
msgid "Busy"
msgstr "Opptatt"
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:98
msgid "Invisible"
msgstr "Usynlig"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:105
msgid "Account Information..."
msgstr "Kontoinformasjon..."
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Sidelinje"
#: ../js/ui/statusMenu.js:142
#: ../js/ui/statusMenu.js:109
msgid "System Preferences..."
msgstr "Brukervalg for systemet..."
#: ../js/ui/statusMenu.js:151
#: ../js/ui/statusMenu.js:116
msgid "Lock Screen"
msgstr "Lås skjerm"
#: ../js/ui/statusMenu.js:156
#: ../js/ui/statusMenu.js:120
msgid "Switch User"
msgstr "Bytt bruker"
#: ../js/ui/statusMenu.js:162
#: ../js/ui/statusMenu.js:125
msgid "Log Out..."
msgstr "Logg ut..."
#: ../js/ui/statusMenu.js:167
#: ../js/ui/statusMenu.js:129
msgid "Shut Down..."
msgstr "Avslutt..."
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s er ferdig startet"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Programmer"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "«%s» er klar"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Siste dokumenter"
#: ../js/ui/workspacesView.js:239
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr "Kan ikke legge til nytt arbeidsområde fordi grensen for maksimalt antall arbeidsområder er nådd."
#: ../src/shell-global.c:967
#: ../js/ui/workspacesView.js:256
msgid "Can't remove the first workspace."
msgstr "Kan ikke fjerne første arbeidsområde"
#: ../src/shell-global.c:1027
msgid "Less than a minute ago"
msgstr "Mindre enn ett minutt siden"
#: ../src/shell-global.c:971
#: ../src/shell-global.c:1031
#, 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:976
#: ../src/shell-global.c:1036
#, 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:981
#: ../src/shell-global.c:1041
#, 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:986
#: ../src/shell-global.c:1046
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"

292
po/nl.po
View File

@ -2,13 +2,13 @@
#
# This file is distributed under the same license as the gnome-shell package.
#
# Sander Dijkhuis <sander.dijkhuis@gmail.com>, 2009.
# Sander Dijkhuis <sander.dijkhuis@gmail.com>, 2009, 2010.
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"
"POT-Creation-Date: 2010-03-31 13:34+0200\n"
"PO-Revision-Date: 2010-04-02 22:18+0200\n"
"Last-Translator: Sander Dijkhuis <sander.dijkhuis@gmail.com>\n"
"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
"MIME-Version: 1.0\n"
@ -18,153 +18,247 @@ msgstr ""
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "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
#: ../js/ui/appDisplay.js:312 ../js/ui/dash.js:855
msgid "APPLICATIONS"
msgstr "TOEPASSINGEN"
#: ../js/ui/appDisplay.js:344
msgid "PREFERENCES"
msgstr "VOORKEUREN"
#: ../js/ui/appDisplay.js:734
msgid "New Window"
msgstr "Nieuw venster"
#: ../js/ui/appDisplay.js:738
msgid "Remove from Favorites"
msgstr "Uit favorieten verwijderen"
#: ../js/ui/appDisplay.js:739
msgid "Add to Favorites"
msgstr "Aan favorieten toevoegen"
#: ../js/ui/appDisplay.js:1091
msgid "Drag here to add favorites"
msgstr "Hierheen slepen om favorieten toe te voegen"
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s is toegevoegd aan uw favorieten."
#: ../js/ui/appFavorites.js:107
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s is verwijderd uit uw favorieten."
#: ../js/ui/dash.js:194
msgid "Find"
msgstr "Zoeken"
#: ../js/ui/dash.js:510
msgid "Searching..."
msgstr "Zoeken…"
#: ../js/ui/dash.js:524
msgid "No matching results."
msgstr "Geen overeenkomende resultaten."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:654
msgid "PLACES"
msgstr "LOCATIES"
#: ../js/ui/dash.js:874 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "LOCATIES & APPARATEN"
#. **** Documents ****
#: ../js/ui/dash.js:661 ../js/ui/dash.js:694
msgid "RECENT DOCUMENTS"
msgstr "RECENTE DOCUMENTEN"
#: ../js/ui/dash.js:881 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "RECENTE ITEMS"
#. **** Search Results ****
#: ../js/ui/dash.js:680
msgid "SEARCH RESULTS"
msgstr "ZOEKRESULTATEN"
#: ../js/ui/lookingGlass.js:363
msgid "No extensions installed"
msgstr "Geen uitbreidingen geïnstalleerd"
#: ../js/ui/runDialog.js:82
#: ../js/ui/lookingGlass.js:400
msgid "Enabled"
msgstr "Ingeschakeld"
#: ../js/ui/lookingGlass.js:402
msgid "Disabled"
msgstr "Uitgeschakeld"
#: ../js/ui/lookingGlass.js:404
msgid "Error"
msgstr "Fout"
#: ../js/ui/lookingGlass.js:406
msgid "Out of date"
msgstr "Gedateerd"
#: ../js/ui/lookingGlass.js:431
msgid "View Source"
msgstr "Broncode weergeven"
#: ../js/ui/lookingGlass.js:437
msgid "Web Page"
msgstr "Webpagina"
#: ../js/ui/overview.js:182
msgid "Undo"
msgstr "Ongedaan maken"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:388
msgid "Activities"
msgstr "Activiteiten"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:619
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:622
msgid "%a %l:%M %p"
msgstr "%a %k:%M %p"
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Ontkoppelen van %s mislukt"
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Opnieuw"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Verbinding maken met…"
#: ../js/ui/runDialog.js:232
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"
#: ../js/ui/runDialog.js:376
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Uitvoeren van %s mislukt:"
#: ../src/shell-global.c:843
#: ../js/ui/statusMenu.js:107
msgid "Available"
msgstr "Beschikbaar"
#: ../js/ui/statusMenu.js:112
msgid "Busy"
msgstr "Bezig"
#: ../js/ui/statusMenu.js:117
msgid "Invisible"
msgstr "Onzichtbaar"
#: ../js/ui/statusMenu.js:126
msgid "Account Information..."
msgstr "Accountinformatie…"
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Zijbalk"
#: ../js/ui/statusMenu.js:142
msgid "System Preferences..."
msgstr "Systeemvoorkeuren…"
#: ../js/ui/statusMenu.js:151
msgid "Lock Screen"
msgstr "Scherm vergrendelen"
#: ../js/ui/statusMenu.js:156
msgid "Switch User"
msgstr "Gebruiker wisselen"
#: ../js/ui/statusMenu.js:162
msgid "Log Out..."
msgstr "Afmelden…"
#: ../js/ui/statusMenu.js:167
msgid "Shut Down..."
msgstr "Afsluiten…"
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Toepassingen"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Recente documenten"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s is opgestart"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "%s is klaar"
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Minder dan een minuut geleden"
#: ../src/shell-global.c:971
#, 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
#: ../src/shell-global.c:976
#, 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
#: ../src/shell-global.c:981
#, 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
#: ../src/shell-global.c:986
#, 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
#: ../src/shell-uri-util.c:89
msgid "Home Folder"
msgstr "Persoonlijke map"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
#: ../src/shell-uri-util.c:104
msgid "File System"
msgstr "Bestandssysteem"
#: ../src/shell-uri-util.c:248
#: ../src/shell-uri-util.c:250
msgid "Search"
msgstr "Zoeken"
@ -173,7 +267,7 @@ msgstr "Zoeken"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#: ../src/shell-uri-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

376
po/pa.po
View File

@ -2,14 +2,14 @@
# 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.
# A S Alam <aalam@users.sf.net>, 2009, 2010.
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug."
"cgi?product=gnome-shell&component=general\n"
"POT-Creation-Date: 2009-10-09 22:10+0000\n"
"PO-Revision-Date: 2009-10-15 06:18+0530\n"
"POT-Creation-Date: 2010-05-19 16:31+0000\n"
"PO-Revision-Date: 2010-05-25 19:31+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"
@ -26,190 +26,307 @@ msgstr "ਗਨੋਮ ਸ਼ੈਲ"
msgid "Window management and application launching"
msgstr "ਵਿੰਡੋ ਪਰਬੰਧ ਅਤੇ ਐਪਲੀਕੇਸ਼ਨ ਚਲਾਓ"
#: ../js/ui/appDisplay.js:335
msgid "Frequent"
msgstr "ਅਕਸਰ"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "ਘੜੀ"
#: ../js/ui/appIcon.js:462
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "ਪੈਨਲ ਘੜੀ ਕਸਟਮਾਈਜ਼ ਕਰੋ"
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
msgstr "ਘੜੀ ਫਾਰਮੈਟ"
#: ../data/clock-preferences.ui.h:2
#| msgid "System Preferences..."
msgid "Clock Preferences"
msgstr "ਘੜੀ ਪਸੰਦ"
#: ../data/clock-preferences.ui.h:3
msgid "Panel Display"
msgstr "ਪੈਨਲ ਦਿੱਖ"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "ਸਕਿੰਟ ਵੇਖੋ(_n)"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
msgstr "ਮਿਤੀ ਵੇਖੋ(_d)"
#: ../data/clock-preferences.ui.h:6
msgid "_12 hour format"
msgstr "_੨ ਘੰਟੇ ਫਾਰਮੈਟ"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "_੨ ਘੰਟੇ ਫਾਰਮੈਟ"
#. **** Applications ****
#: ../js/ui/appDisplay.js:306 ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "ਐਪਲੀਕੇਸ਼ਨ"
#: ../js/ui/appDisplay.js:338
msgid "PREFERENCES"
msgstr "ਪਸੰਦ"
#: ../js/ui/appDisplay.js:705
msgid "New Window"
msgstr "ਨਵੀਂ ਵਿੰਡੋ"
#: ../js/ui/appIcon.js:475
#: ../js/ui/appDisplay.js:709
msgid "Remove from Favorites"
msgstr "ਪਸੰਦ ਵਿੱਚੋਂ ਹਟਾਓ"
#: ../js/ui/appIcon.js:476
#: ../js/ui/appDisplay.js:710
msgid "Add to Favorites"
msgstr "ਪਸੰਦ 'ਚ ਸ਼ਾਮਲ ਕਰੋ"
#: ../js/ui/dash.js:283
msgid "Find..."
msgstr "ਖੋਜ..."
#: ../js/ui/appDisplay.js:1037
msgid "Drag here to add favorites"
msgstr "ਪਸੰਦ ਵਿੱਚ ਜੋੜਨ ਲਈ ਇੱਥੇ ਸੁੱਟੋ"
#: ../js/ui/dash.js:400
msgid "More"
msgstr "ਹੋਰ"
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s ਨੂੰ ਤੁਹਾਡੀ ਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।"
#: ../js/ui/dash.js:543
msgid "(see all)"
msgstr "(ਸਭ ਵੇਖੋ)"
#: ../js/ui/appFavorites.js:107
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s ਨੂੰ ਤੁਹਾਡੀ ਪਸੰਦ ਤੋਂ ਹਟਾਇਆ ਜਾ ਚੁੱਕਿਆ ਹੈ।"
#. **** Applications ****
#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
msgid "APPLICATIONS"
msgstr "ਐਪਲੀਕੇਸ਼ਨ"
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "ਖੋਜ"
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "ਖੋਜ ਜਾਰੀ ਹੈ..."
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "ਕੋਈ ਨਤੀਜਾ ਨਹੀਂ ਲੱਭਿਆ।"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:783
msgid "PLACES"
msgstr "ਥਾਵਾਂ"
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "ਥਾਵਾਂ ਤੇ ਜੰਤਰ"
#. **** Documents ****
#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
msgid "RECENT DOCUMENTS"
msgstr "ਤਾਜ਼ਾ ਡੌਕੂਮੈਂਟ"
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "ਤਾਜ਼ਾ ਆਈਟਮਾਂ"
#. **** Search Results ****
#: ../js/ui/dash.js:815 ../js/ui/dash.js:955
msgid "SEARCH RESULTS"
msgstr "ਖੋਜ ਨਤੀਜੇ"
#: ../js/ui/lookingGlass.js:466
msgid "No extensions installed"
msgstr "ਕੋਈ ਇਕਸਟੈਨਸ਼ਨ ਇੰਸਟਾਲ ਨਹੀਂ ਹੈ"
#: ../js/ui/dash.js:830
msgid "PREFERENCES"
msgstr "ਪਸੰਦ"
#: ../js/ui/lookingGlass.js:503
msgid "Enabled"
msgstr "ਚਾਲੂ ਹੈ"
#: ../js/ui/lookingGlass.js:505
msgid "Disabled"
msgstr "ਬੰਦ ਹੈ"
#: ../js/ui/lookingGlass.js:507
msgid "Error"
msgstr "ਗਲਤੀ"
#: ../js/ui/lookingGlass.js:509
msgid "Out of date"
msgstr "ਪੁਰਾਣਾ"
#: ../js/ui/lookingGlass.js:534
msgid "View Source"
msgstr "ਸਰੋਤ ਵੇਖੋ"
#: ../js/ui/lookingGlass.js:540
msgid "Web Page"
msgstr "ਵੈੱਬ ਪੇਜ਼"
#: ../js/ui/overview.js:161
msgid "Undo"
msgstr "ਵਾਪਸ"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:272
#: ../js/ui/panel.js:774
msgid "Activities"
msgstr "ਸਰਗਰਮੀਆਂ"
#. Translators: This is a time format.
#: ../js/ui/panel.js:464
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:989
msgid "%a %b %e, %R:%S"
msgstr "%a, %e %b %R:%S"
#: ../js/ui/panel.js:990
#| msgid "%a %l:%M %p"
msgid "%a %b %e, %R"
msgstr "%a %e %b, %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:994
#| msgid "%a %R"
msgid "%a %R:%S"
msgstr "%a %R:%S"
#: ../js/ui/panel.js:995
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:1002
#| msgid "%a %l:%M %p"
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a %e %b, %l:%M:%S %p"
#: ../js/ui/panel.js:1003
#| msgid "%a %l:%M %p"
msgid "%a %b %e, %l:%M %p"
msgstr "%a %e %b, %l:%M %p"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:1007
#| msgid "%a %l:%M %p"
msgid "%a %l:%M:%S %p"
msgstr "%a %l:%M:%S %p"
#: ../js/ui/panel.js:1008
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/places.js:178
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "'%s' ਅਣ-ਮਾਊਂਟ ਕਰਨ ਲਈ ਫੇਲ੍ਹ"
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "ਮੁੜ-ਕੋਸ਼ਿਸ਼"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "...ਨਾਲ ਕੁਨੈਕਟ ਕਰੋ"
#: ../js/ui/runDialog.js:96
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "ਕਮਾਂਡ ਦਿਓ ਜੀ:"
#: ../js/ui/runDialog.js:173
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "'%s' ਚਲਾਉਣ ਲਈ ਫੇਲ੍ਹ:"
#. Translators: This is a time format.
#: ../js/ui/widget.js:162
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/statusMenu.js:90
msgid "Available"
msgstr "ਉਪਲੱਬਧ"
#: ../js/ui/widget.js:316
msgid "Applications"
msgstr "ਐਪਲੀਕੇਸ਼ਨ"
#: ../js/ui/statusMenu.js:94
msgid "Busy"
msgstr "ਰੁਝਿਆ"
#: ../js/ui/widget.js:341
msgid "Recent Documents"
msgstr "ਤਾਜ਼ਾ ਡੌਕੂਮੈਂਟ"
#: ../js/ui/statusMenu.js:98
msgid "Invisible"
msgstr "ਅਦਿੱਖ"
#: ../src/shell-global.c:812
#: ../js/ui/statusMenu.js:105
msgid "Account Information..."
msgstr "ਅਕਾਊਂਟ ਜਾਣਕਾਰੀ..."
#: ../js/ui/statusMenu.js:109
msgid "System Preferences..."
msgstr "ਸਿਸਟਮ ਪਸੰਦ..."
#: ../js/ui/statusMenu.js:116
msgid "Lock Screen"
msgstr "ਸਕਰੀਨ ਲਾਕ ਕਰੋ"
#: ../js/ui/statusMenu.js:120
msgid "Switch User"
msgstr "ਯੂਜ਼ਰ ਬਦਲੋ"
#: ../js/ui/statusMenu.js:125
msgid "Log Out..."
msgstr "ਲਾਗਆਉਟ..."
#: ../js/ui/statusMenu.js:129
msgid "Shut Down..."
msgstr "ਬੰਦ ਕਰੋ..."
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s ਸ਼ੁਰੂ ਹੋਣਾ ਖਤਮ ਹੋਇਆ"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "'%s' ਤਿਆਰ ਹੈ"
#: ../js/ui/workspacesView.js:239
msgid ""
"Can't add a new workspace because maximum workspaces limit has been reached."
msgstr ""
"ਨਵਾਂ ਵਰਕਸਪੇਸ ਜੋੜਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ, ਕਿਉਂਕਿ ਵਰਕਸਪੇਸਾਂ ਦੀ ਵੱਧੋ-ਵੱਧ ਗਿਣਤੀ ਪੂਰੀ ਹੋ "
"ਚੁੱਕੀ ਹੈ।"
#: ../js/ui/workspacesView.js:256
msgid "Can't remove the first workspace."
msgstr "ਪਹਿਲਾਂ ਵਰਕਸਪੇਸ ਨਹੀਂ ਹਟਾਇਆ ਜਾ ਸਕਦਾ।"
#: ../src/shell-global.c:976
msgid "Less than a minute ago"
msgstr "ਇੱਕ ਮਿੰਟ ਤੋਂ ਘੱਟ ਚਿਰ ਪਹਿਲਾਂ"
#: ../src/shell-global.c:815
#: ../src/shell-global.c:980
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d ਮਿੰਟ ਪਹਿਲਾਂ"
msgstr[1] "%d ਮਿੰਟ ਪਹਿਲਾਂ"
#: ../src/shell-global.c:818
#: ../src/shell-global.c:985
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d ਘੰਟਾ ਪਹਿਲਾਂ"
msgstr[1] "%d ਘੰਟੇ ਪਹਿਲਾਂ"
#: ../src/shell-global.c:821
#: ../src/shell-global.c:990
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d ਦਿਨ ਪਹਿਲਾਂ"
msgstr[1] "%d ਦਿਨ ਪਹਿਲਾਂ"
#: ../src/shell-global.c:824
#: ../src/shell-global.c:995
#, 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
#: ../src/shell-uri-util.c:89
msgid "Home Folder"
msgstr "ਘਰ ਫੋਲਡਰ"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
#: ../src/shell-uri-util.c:104
msgid "File System"
msgstr "ਫਾਇਲ ਸਿਸਟਮ"
#: ../src/shell-uri-util.c:248
#: ../src/shell-uri-util.c:250
msgid "Search"
msgstr "ਖੋਜ"
@ -218,10 +335,49 @@ msgstr "ਖੋਜ"
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:298
#: ../src/shell-uri-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Sidebar"
#~ msgstr "ਬਾਹੀ"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"
#~ msgid "Applications"
#~ msgstr "ਐਪਲੀਕੇਸ਼ਨ"
#~ msgid "Recent Documents"
#~ msgstr "ਤਾਜ਼ਾ ਡੌਕੂਮੈਂਟ"
#~ msgid "Frequent"
#~ msgstr "ਅਕਸਰ"
#~ msgid "More"
#~ msgstr "ਹੋਰ"
#~ msgid "(see all)"
#~ msgstr "(ਸਭ ਵੇਖੋ)"
#~ msgid "PLACES"
#~ msgstr "ਥਾਵਾਂ"
#~ msgid "SEARCH RESULTS"
#~ msgstr "ਖੋਜ ਨਤੀਜੇ"
#~ msgid "Unknown"
#~ msgstr "ਅਣਜਾਣ"
#~ msgid "Can't lock screen: %s"
#~ msgstr "ਸਕਰੀਨ ਲਾਕ ਨਹੀਂ ਹੋ ਸਕਦੀ: %s"
#~ msgid "Can't temporarily set screensaver to blank screen: %s"
#~ msgstr "ਸਕਰੀਨ ਬੰਦ ਕਰਨ ਲਈ ਆਰਜ਼ੀ ਰੂਪ ਵਿੱਚ ਸਕਰੀਨ-ਸੇਵਰ ਨਹੀਂ ਸੈੱਟ ਕੀਤਾ ਜਾ ਸਕਦਾ: %s"
#~ msgid "Can't logout: %s"
#~ msgstr "ਲਾਗਆਉਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ: %s"
#~ msgid "Browse"
#~ msgstr "ਝਲਕ"

View File

@ -3,15 +3,15 @@
# This file is distributed under the same license as the gnome-shell package.
# Og Maciel <ogmaciel@gnome.org>, 2009.
# Rodrigo Flores <mail@rodrigoflores.org>, 2009.
# Felipe Borges <felipe10borges@gmail.com>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2009-11-12 21:33+0000\n"
"PO-Revision-Date: 2009-11-14 11:53-0200\n"
"Last-Translator: Amanda Magalhães <amandinhakee@gmail.com>\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-04-17 14:02-0300\n"
"PO-Revision-Date: 2010-03-02 20:59-0300\n"
"Last-Translator: Rodrigo Flores <rlmflores@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"
@ -24,197 +24,269 @@ msgstr "GNOME Shell"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
msgstr "Gerenciamento de janelas e lançador de aplicações"
msgstr "Gerenciamento de janelas e lançador de aplicativos"
#: ../js/ui/appDisplay.js:696
msgid "Drag here to add favorites"
msgstr "Arraste até aqui para adicionar aos favoritos"
#. **** Applications ****
#: ../js/ui/appDisplay.js:306 ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "APLICATIVOS"
#: ../js/ui/appIcon.js:425
#: ../js/ui/appDisplay.js:338
msgid "PREFERENCES"
msgstr "PREFERÊNCIAS"
#: ../js/ui/appDisplay.js:697
msgid "New Window"
msgstr "Nova janela"
#: ../js/ui/appIcon.js:429
#: ../js/ui/appDisplay.js:701
msgid "Remove from Favorites"
msgstr "Remover dos Favoritos"
#: ../js/ui/appIcon.js:430
#: ../js/ui/appDisplay.js:702
msgid "Add to Favorites"
msgstr "Adicionar aos Favoritos"
#: ../js/ui/dash.js:237
msgid "Find..."
msgstr "Procurar..."
#: ../js/ui/appDisplay.js:1029
msgid "Drag here to add favorites"
msgstr "Arraste até aqui para adicionar aos favoritos"
#. **** Applications ****
#: ../js/ui/dash.js:656 ../js/ui/dash.js:718
msgid "APPLICATIONS"
msgstr "APLICATIVOS"
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s foi adicionado aos seus favoritos."
#: ../js/ui/appFavorites.js:107
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s foi removido dos seus favoritos."
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "Localizar"
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "Pesquisando..."
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "Nenhum resultado encontrado."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:676 ../js/ui/dash.js:733
msgid "PLACES"
msgstr "LOCAIS"
#: ../js/ui/dash.js:869 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "LOCAIS & DISPOSITIVOS"
#. **** Documents ****
#: ../js/ui/dash.js:683 ../js/ui/dash.js:728
msgid "RECENT DOCUMENTS"
#: ../js/ui/dash.js:876 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "DOCUMENTOS RECENTES"
#. **** Search Results ****
#: ../js/ui/dash.js:708 ../js/ui/dash.js:898
msgid "SEARCH RESULTS"
msgstr "RESULTADOS DA BUSCA"
#: ../js/ui/lookingGlass.js:362
msgid "No extensions installed"
msgstr "Nenhuma extensão instalada"
#: ../js/ui/dash.js:723
msgid "PREFERENCES"
msgstr "PREFERÊNCIAS"
#: ../js/ui/lookingGlass.js:399
msgid "Enabled"
msgstr "Habilitado"
#: ../js/ui/lookingGlass.js:401
msgid "Disabled"
msgstr "Desabilitado"
#: ../js/ui/lookingGlass.js:403
msgid "Error"
msgstr "Erro"
#: ../js/ui/lookingGlass.js:405
msgid "Out of date"
msgstr "Expirado"
#: ../js/ui/lookingGlass.js:430
msgid "View Source"
msgstr "Ver fonte"
#: ../js/ui/lookingGlass.js:436
msgid "Web Page"
msgstr "Página Web"
#: ../js/ui/overview.js:181
msgid "Undo"
msgstr "Desfazer"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:274
#: ../js/ui/panel.js:346
msgid "Activities"
msgstr "Atividades"
#. Translators: This is a time format.
#: ../js/ui/panel.js:491
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:566
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:569
msgid "%a %l:%M %p"
msgstr "%a %l:%M %p"
#: ../js/ui/placeDisplay.js:84
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Erro ao desmontar \"%s\""
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Tentar novamente"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Conectar ao..."
#: ../js/ui/runDialog.js:96
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "Por favor digite um comando:"
#: ../js/ui/runDialog.js:173
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "A execução de \"%s\" falhou:"
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/statusMenu.js:105
msgid "Available"
msgstr "Disponível"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Aplicações"
#: ../js/ui/statusMenu.js:110
msgid "Busy"
msgstr "Ocupado"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Documentos Recentes"
#: ../js/ui/statusMenu.js:115
msgid "Invisible"
msgstr "Invisível"
#: ../src/shell-global.c:821
#: ../js/ui/statusMenu.js:124
msgid "Account Information..."
msgstr "Informação da conta..."
#: ../js/ui/statusMenu.js:129
msgid "System Preferences..."
msgstr "Preferências do sistema..."
#: ../js/ui/statusMenu.js:138
msgid "Lock Screen"
msgstr "Travar a tela"
#: ../js/ui/statusMenu.js:143
msgid "Switch User"
msgstr "Alternar usuário"
#: ../js/ui/statusMenu.js:149
msgid "Log Out..."
msgstr "Encerrar sessão..."
#: ../js/ui/statusMenu.js:154
msgid "Shut Down..."
msgstr "Desligar..."
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s terminou sua inicialização"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "\"%s\" está pronto"
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Menos de um minuto atrás"
#: ../src/shell-global.c:824
#: ../src/shell-global.c:971
#, 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:827
#: ../src/shell-global.c:976
#, 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:830
#: ../src/shell-global.c:981
#, 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:833
#: ../src/shell-global.c:986
#, 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..."
#: ../src/shell-uri-util.c:87
#: ../src/shell-uri-util.c:89
msgid "Home Folder"
msgstr "Pasta home"
msgstr "Pasta pessoal"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:102
#: ../src/shell-uri-util.c:104
msgid "File System"
msgstr "Sistema de arquivos"
#: ../src/shell-uri-util.c:248
#: ../src/shell-uri-util.c:250
msgid "Search"
msgstr "Procurar"
msgstr "Pesquisar"
#. 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
#: ../src/shell-uri-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Sidebar"
#~ msgstr "Barra lateral"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"
#~ msgid "Applications"
#~ msgstr "Aplicativos"
#~ msgid "Recent Documents"
#~ msgstr "Documentos recentes"
#~ msgid "PLACES"
#~ msgstr "LOCAIS"
#~ msgid "SEARCH RESULTS"
#~ msgstr "RESULTADOS DA BUSCA"
#~ msgid "Unknown"
#~ msgstr "Desconhecido"
#~ msgid "Can't lock screen: %s"
#~ msgstr "Não foi possível travar a tela: %s"
#~ 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"
#~ msgid "Can't logout: %s"
#~ msgstr "Não foi possível encerrar a sessão: %s"
#~ msgid "Browse"
#~ msgstr "Navegar"

199
po/sl.po
View File

@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell&component=general\n"
"POT-Creation-Date: 2010-03-21 15:49+0000\n"
"PO-Revision-Date: 2010-03-21 21:59+0100\n"
"POT-Creation-Date: 2010-05-21 16:35+0000\n"
"PO-Revision-Date: 2010-05-21 20:03+0100\n"
"Last-Translator: Matej Urbančič <mateju@svn.gnome.org>\n"
"Language-Team: Slovenian GNOME Translation Team <gnome-si@googlegroups.com>\n"
"MIME-Version: 1.0\n"
@ -29,29 +29,65 @@ msgstr "Gnome Lupina"
msgid "Window management and application launching"
msgstr "Upravljanje oken in zaganjanje programov"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:1
msgid "Clock"
msgstr "Ura"
#: ../data/gnome-shell-clock-preferences.desktop.in.in.h:2
msgid "Customize the panel clock"
msgstr "Prilagodi uro pladnja"
#: ../data/clock-preferences.ui.h:1
msgid "Clock Format"
msgstr "Zapis ure"
#: ../data/clock-preferences.ui.h:2
msgid "Clock Preferences"
msgstr "Možnosti ure"
#: ../data/clock-preferences.ui.h:3
msgid "Panel Display"
msgstr "Prikazovanje pladnja"
#: ../data/clock-preferences.ui.h:4
msgid "Show seco_nds"
msgstr "Pokaži _sekunde"
#: ../data/clock-preferences.ui.h:5
msgid "Show the _date"
msgstr "Pokaži _datum"
#: ../data/clock-preferences.ui.h:6
msgid "_12 hour format"
msgstr "_12-urni zapis časa"
#: ../data/clock-preferences.ui.h:7
msgid "_24 hour format"
msgstr "_24-urni zapis časa"
#. **** Applications ****
#: ../js/ui/appDisplay.js:311
#: ../js/ui/dash.js:852
#: ../js/ui/appDisplay.js:306
#: ../js/ui/dash.js:850
msgid "APPLICATIONS"
msgstr "Programi"
#: ../js/ui/appDisplay.js:343
#: ../js/ui/appDisplay.js:338
msgid "PREFERENCES"
msgstr "Možnosti"
#: ../js/ui/appDisplay.js:728
#: ../js/ui/appDisplay.js:705
msgid "New Window"
msgstr "Novo okno"
#: ../js/ui/appDisplay.js:732
#: ../js/ui/appDisplay.js:709
msgid "Remove from Favorites"
msgstr "Odstrani iz priljubljenih"
#: ../js/ui/appDisplay.js:733
#: ../js/ui/appDisplay.js:710
msgid "Add to Favorites"
msgstr "Dodaj med priljubljene"
#: ../js/ui/appDisplay.js:1085
#: ../js/ui/appDisplay.js:1037
msgid "Drag here to add favorites"
msgstr "S potegom na to mesto se izbor doda med priljubljene"
@ -65,155 +101,168 @@ msgstr "Program \"%s\" je dodan med priljubljeno."
msgid "%s has been removed from your favorites."
msgstr "Program \"%s\" je odstranjen iz priljubljenih."
#: ../js/ui/dash.js:194
#: ../js/ui/dash.js:189
msgid "Find"
msgstr "Najdi"
#: ../js/ui/dash.js:507
#: ../js/ui/dash.js:505
msgid "Searching..."
msgstr "Iskanje ..."
#: ../js/ui/dash.js:521
#: ../js/ui/dash.js:519
msgid "No matching results."
msgstr "Ni zadetkov iskanja"
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:871
#: ../js/ui/placeDisplay.js:579
#: ../js/ui/dash.js:869
#: ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "Mesta in naprave"
#. **** Documents ****
#: ../js/ui/dash.js:878
#: ../js/ui/docDisplay.js:488
#: ../js/ui/dash.js:876
#: ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "Nedavni predmeti"
#: ../js/ui/lookingGlass.js:363
#: ../js/ui/lookingGlass.js:466
msgid "No extensions installed"
msgstr "Ni nameščenih razširitev"
#: ../js/ui/lookingGlass.js:400
#: ../js/ui/lookingGlass.js:503
msgid "Enabled"
msgstr "Omogočeno"
#: ../js/ui/lookingGlass.js:402
#: ../js/ui/lookingGlass.js:505
msgid "Disabled"
msgstr "Onemogočeno"
#: ../js/ui/lookingGlass.js:404
#: ../js/ui/lookingGlass.js:507
msgid "Error"
msgstr "Napaka"
#: ../js/ui/lookingGlass.js:406
#: ../js/ui/lookingGlass.js:509
msgid "Out of date"
msgstr "Zastarelo"
#: ../js/ui/lookingGlass.js:431
#: ../js/ui/lookingGlass.js:534
msgid "View Source"
msgstr "Poglej vir"
#: ../js/ui/lookingGlass.js:437
#: ../js/ui/lookingGlass.js:540
msgid "Web Page"
msgstr "Spletna stran"
#: ../js/ui/overview.js:182
#: ../js/ui/overview.js:161
msgid "Undo"
msgstr "Razveljavi"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:385
#: ../js/ui/panel.js:887
msgid "Activities"
msgstr "Dejavnosti"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:616
#. Translators: This is the time format with date used
#. in 24-hour mode.
#: ../js/ui/panel.js:1102
msgid "%a %b %e, %R:%S"
msgstr "%a. %e. %b., %R:%S"
#: ../js/ui/panel.js:1103
msgid "%a %b %e, %R"
msgstr "%a, %e. %b., %R"
#. Translators: This is the time format without date used
#. in 24-hour mode.
#: ../js/ui/panel.js:1107
msgid "%a %R:%S"
msgstr "%a. %R:%S"
#: ../js/ui/panel.js:1108
msgid "%a %R"
msgstr "%a. %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:619
#. Translators: This is a time format with date used
#. for AM/PM.
#: ../js/ui/panel.js:1115
msgid "%a %b %e, %l:%M:%S %p"
msgstr "%a. %e. %b., %H:%M:%S"
#: ../js/ui/panel.js:1116
msgid "%a %b %e, %l:%M %p"
msgstr "%a. %e. %b., %H:%M"
#. Translators: This is a time format without date used
#. for AM/PM.
#: ../js/ui/panel.js:1120
msgid "%a %l:%M:%S %p"
msgstr "%a, %H:%M:%S"
#: ../js/ui/panel.js:1121
msgid "%a %l:%M %p"
msgstr "%a, %H:%M"
#: ../js/ui/placeDisplay.js:103
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Ni mogoče odklopiti '%s'"
#: ../js/ui/placeDisplay.js:106
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Poskusi znova"
#: ../js/ui/placeDisplay.js:151
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "Povezava z ..."
#: ../js/ui/runDialog.js:232
#: ../js/ui/runDialog.js:231
msgid "Please enter a command:"
msgstr "Vnos ukaza:"
#: ../js/ui/runDialog.js:374
#: ../js/ui/runDialog.js:375
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Izvajanje '%s' je spodletelo:"
#: ../js/ui/statusMenu.js:107
#: ../js/ui/statusMenu.js:90
msgid "Available"
msgstr "Razpoložljivo"
msgstr "Na voljo"
#: ../js/ui/statusMenu.js:112
#: ../js/ui/statusMenu.js:94
msgid "Busy"
msgstr "Zasedeno"
#: ../js/ui/statusMenu.js:117
#: ../js/ui/statusMenu.js:98
msgid "Invisible"
msgstr "Nevidno"
#: ../js/ui/statusMenu.js:126
#: ../js/ui/statusMenu.js:105
msgid "Account Information..."
msgstr "Podrobnosti računa ..."
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Stranska vrstica"
#: ../js/ui/statusMenu.js:142
#: ../js/ui/statusMenu.js:109
msgid "System Preferences..."
msgstr "Sistemske možnosti ..."
#: ../js/ui/statusMenu.js:151
#: ../js/ui/statusMenu.js:116
msgid "Lock Screen"
msgstr "Zakleni zaslon"
#: ../js/ui/statusMenu.js:156
#: ../js/ui/statusMenu.js:120
msgid "Switch User"
msgstr "Preklop uporabnika"
#: ../js/ui/statusMenu.js:162
#: ../js/ui/statusMenu.js:125
msgid "Log Out..."
msgstr "Odjava ..."
#: ../js/ui/statusMenu.js:167
#: ../js/ui/statusMenu.js:129
msgid "Shut Down..."
msgstr "Izklopi ..."
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Programi"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Nedavni dokumenti"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
@ -224,11 +273,19 @@ msgstr "%s je končal začenjanje"
msgid "'%s' is ready"
msgstr "'%s' storitev je pripravljena"
#: ../src/shell-global.c:967
#: ../js/ui/workspacesView.js:239
msgid "Can't add a new workspace because maximum workspaces limit has been reached."
msgstr "Ni mogoče dodati nove delovne površine, ker je doseženo njihovo največje dovoljeno število."
#: ../js/ui/workspacesView.js:256
msgid "Can't remove the first workspace."
msgstr "Ni mogoče odstraniti prve delovne površine."
#: ../src/shell-global.c:1011
msgid "Less than a minute ago"
msgstr "Pred manj kot eno minuto"
#: ../src/shell-global.c:971
#: ../src/shell-global.c:1015
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
@ -237,7 +294,7 @@ msgstr[1] "Pred %d minuto"
msgstr[2] "Pred %d minutama"
msgstr[3] "Pred %d minutami"
#: ../src/shell-global.c:976
#: ../src/shell-global.c:1020
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
@ -246,7 +303,7 @@ msgstr[1] "Pred %d uro"
msgstr[2] "Pred %d urama"
msgstr[3] "Pred %d urami"
#: ../src/shell-global.c:981
#: ../src/shell-global.c:1025
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
@ -255,7 +312,7 @@ msgstr[1] "Pred %d dnevom"
msgstr[2] "Pred %d dnevoma"
msgstr[3] "Pred %d dnevi"
#: ../src/shell-global.c:986
#: ../src/shell-global.c:1030
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
@ -288,6 +345,16 @@ msgstr "Poišči"
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"
#~ msgid "Quit"
#~ msgstr "Končaj"
#~ msgid "Sidebar"
#~ msgstr "Stranska vrstica"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"
#~ msgid "Applications"
#~ msgstr "Programi"
#~ msgid "Recent Documents"
#~ msgstr "Nedavni dokumenti"
#~ msgid "PLACES"
#~ msgstr "Mesta"
#~ msgid "SEARCH RESULTS"

161
po/sr.po
View File

@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2010-01-18 20:13+0000\n"
"PO-Revision-Date: 2010-01-19 00:14+0000\n"
"POT-Creation-Date: 2010-03-20 22:48+0000\n"
"PO-Revision-Date: 2010-03-24 01:45+0100\n"
"Last-Translator: Милош Поповић <gpopac@gmail.com>\n"
"Language-Team: Serbian <gnom@prevod.org>\n"
"MIME-Version: 1.0\n"
@ -27,78 +27,177 @@ msgid "Window management and application launching"
msgstr "Управник прозорима и покретач програма"
#. **** Applications ****
#: ../js/ui/appDisplay.js:252 ../js/ui/dash.js:865
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:852
msgid "APPLICATIONS"
msgstr "ПРОГРАМИ"
#: ../js/ui/appDisplay.js:276
#: ../js/ui/appDisplay.js:343
msgid "PREFERENCES"
msgstr "ПОСТАВКЕ"
#: ../js/ui/appDisplay.js:647
#: ../js/ui/appDisplay.js:728
msgid "New Window"
msgstr "Нови прозор"
#: ../js/ui/appDisplay.js:651
#: ../js/ui/appDisplay.js:732
msgid "Remove from Favorites"
msgstr "Уклони из омиљених"
#: ../js/ui/appDisplay.js:652
#: ../js/ui/appDisplay.js:733
msgid "Add to Favorites"
msgstr "Додај у омиљене"
#: ../js/ui/appDisplay.js:1004
#: ../js/ui/appDisplay.js:1085
msgid "Drag here to add favorites"
msgstr "Превуците овде како би додали у омиљене"
#: ../js/ui/dash.js:240
msgid "Find..."
msgstr "Нађи..."
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s је додат међу омиљене"
#: ../js/ui/dash.js:493
#: ../js/ui/appFavorites.js:107
#, c-format
#| msgid "Remove from Favorites"
msgid "%s has been removed from your favorites."
msgstr "%s је уклоњен из омиљених"
#: ../js/ui/dash.js:194
#| msgid "Find..."
msgid "Find"
msgstr "Нађи"
#: ../js/ui/dash.js:507
msgid "Searching..."
msgstr "Тражим..."
#: ../js/ui/dash.js:507
#: ../js/ui/dash.js:521
msgid "No matching results."
msgstr "Ништа није пронађено."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:885 ../js/ui/placeDisplay.js:519
#: ../js/ui/dash.js:871 ../js/ui/placeDisplay.js:579
msgid "PLACES & DEVICES"
msgstr "МЕСТА И УРЕЂАЈИ"
#. **** Documents ****
#: ../js/ui/dash.js:892
#: ../js/ui/dash.js:878 ../js/ui/docDisplay.js:488
msgid "RECENT ITEMS"
msgstr "СКОРАШЊЕ СТАВКЕ"
#: ../js/ui/lookingGlass.js:363
msgid "No extensions installed"
msgstr "Нису инсталирана проширења"
#: ../js/ui/lookingGlass.js:400
msgid "Enabled"
msgstr "Омогућено"
#: ../js/ui/lookingGlass.js:402
msgid "Disabled"
msgstr "Онемогућено"
#: ../js/ui/lookingGlass.js:404
msgid "Error"
msgstr "Грешка"
#: ../js/ui/lookingGlass.js:406
msgid "Out of date"
msgstr "Истекао је датум"
#: ../js/ui/lookingGlass.js:431
msgid "View Source"
msgstr "Погледај извор"
#: ../js/ui/lookingGlass.js:437
msgid "Web Page"
msgstr "Интернет страница"
#: ../js/ui/overview.js:182
msgid "Undo"
msgstr "Опозови"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:336
#: ../js/ui/panel.js:385
msgid "Activities"
msgstr "Активности"
#. Translators: This is a time format.
#: ../js/ui/panel.js:549
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:616
msgid "%a %R"
msgstr "%A, %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:619
msgid "%a %l:%M %p"
msgstr "%A, %H:%M"
#: ../js/ui/placeDisplay.js:144
#: ../js/ui/placeDisplay.js:103
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Не могу да демонтирам „%s“"
#: ../js/ui/placeDisplay.js:106
msgid "Retry"
msgstr "Понови"
#: ../js/ui/placeDisplay.js:151
msgid "Connect to..."
msgstr "Повежи се на..."
#: ../js/ui/runDialog.js:245
#: ../js/ui/runDialog.js:232
msgid "Please enter a command:"
msgstr "Унесите наредбу:"
#: ../js/ui/runDialog.js:361
#: ../js/ui/runDialog.js:374
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Није успело покретање „%s“:"
#: ../js/ui/statusMenu.js:107
msgid "Available"
msgstr "Доступан"
#: ../js/ui/statusMenu.js:112
msgid "Busy"
msgstr "Заузет"
#: ../js/ui/statusMenu.js:117
msgid "Invisible"
msgstr "Невидљив"
#: ../js/ui/statusMenu.js:126
msgid "Account Information..."
msgstr "Подаци о налогу..."
#: ../js/ui/statusMenu.js:132
#| msgid "Search"
msgid "Sidebar"
msgstr "Бочна трака"
#: ../js/ui/statusMenu.js:142
msgid "System Preferences..."
msgstr "Поставке система..."
#: ../js/ui/statusMenu.js:151
msgid "Lock Screen"
msgstr "Закључај екран"
#: ../js/ui/statusMenu.js:156
msgid "Switch User"
msgstr "Промени корисника"
#: ../js/ui/statusMenu.js:162
msgid "Log Out..."
msgstr "Одјави ме..."
#: ../js/ui/statusMenu.js:167
msgid "Shut Down..."
msgstr "Искључи..."
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
@ -112,11 +211,21 @@ msgstr "Програми"
msgid "Recent Documents"
msgstr "Скорашњи документи"
#: ../src/shell-global.c:890
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s је покренут"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "„%s“ је спреман"
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Пре мање од једног минута"
#: ../src/shell-global.c:894
#: ../src/shell-global.c:971
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
@ -125,7 +234,7 @@ msgstr[1] "Пре %d минута"
msgstr[2] "Пре %d минута"
msgstr[3] "Пре %d минута"
#: ../src/shell-global.c:899
#: ../src/shell-global.c:976
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
@ -134,7 +243,7 @@ msgstr[1] "Пре %d сата"
msgstr[2] "Пре %d сата"
msgstr[3] "Пре %d сата"
#: ../src/shell-global.c:904
#: ../src/shell-global.c:981
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
@ -143,7 +252,7 @@ msgstr[1] "Пре %d дана"
msgstr[2] "Пре %d дана"
msgstr[3] "Пре %d дана"
#: ../src/shell-global.c:909
#: ../src/shell-global.c:986
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"

View File

@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2010-01-18 20:13+0000\n"
"PO-Revision-Date: 2010-01-19 00:14+0000\n"
"POT-Creation-Date: 2010-03-20 22:48+0000\n"
"PO-Revision-Date: 2010-03-24 01:45+0100\n"
"Last-Translator: Miloš Popović <gpopac@gmail.com>\n"
"Language-Team: Serbian <gnom@prevod.org>\n"
"MIME-Version: 1.0\n"
@ -27,78 +27,177 @@ msgid "Window management and application launching"
msgstr "Upravnik prozorima i pokretač programa"
#. **** Applications ****
#: ../js/ui/appDisplay.js:252 ../js/ui/dash.js:865
#: ../js/ui/appDisplay.js:311 ../js/ui/dash.js:852
msgid "APPLICATIONS"
msgstr "PROGRAMI"
#: ../js/ui/appDisplay.js:276
#: ../js/ui/appDisplay.js:343
msgid "PREFERENCES"
msgstr "POSTAVKE"
#: ../js/ui/appDisplay.js:647
#: ../js/ui/appDisplay.js:728
msgid "New Window"
msgstr "Novi prozor"
#: ../js/ui/appDisplay.js:651
#: ../js/ui/appDisplay.js:732
msgid "Remove from Favorites"
msgstr "Ukloni iz omiljenih"
#: ../js/ui/appDisplay.js:652
#: ../js/ui/appDisplay.js:733
msgid "Add to Favorites"
msgstr "Dodaj u omiljene"
#: ../js/ui/appDisplay.js:1004
#: ../js/ui/appDisplay.js:1085
msgid "Drag here to add favorites"
msgstr "Prevucite ovde kako bi dodali u omiljene"
#: ../js/ui/dash.js:240
msgid "Find..."
msgstr "Nađi..."
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s je dodat među omiljene"
#: ../js/ui/dash.js:493
#: ../js/ui/appFavorites.js:107
#, c-format
#| msgid "Remove from Favorites"
msgid "%s has been removed from your favorites."
msgstr "%s je uklonjen iz omiljenih"
#: ../js/ui/dash.js:194
#| msgid "Find..."
msgid "Find"
msgstr "Nađi"
#: ../js/ui/dash.js:507
msgid "Searching..."
msgstr "Tražim..."
#: ../js/ui/dash.js:507
#: ../js/ui/dash.js:521
msgid "No matching results."
msgstr "Ništa nije pronađeno."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:885 ../js/ui/placeDisplay.js:519
#: ../js/ui/dash.js:871 ../js/ui/placeDisplay.js:579
msgid "PLACES & DEVICES"
msgstr "MESTA I UREĐAJI"
#. **** Documents ****
#: ../js/ui/dash.js:892
#: ../js/ui/dash.js:878 ../js/ui/docDisplay.js:488
msgid "RECENT ITEMS"
msgstr "SKORAŠNJE STAVKE"
#: ../js/ui/lookingGlass.js:363
msgid "No extensions installed"
msgstr "Nisu instalirana proširenja"
#: ../js/ui/lookingGlass.js:400
msgid "Enabled"
msgstr "Omogućeno"
#: ../js/ui/lookingGlass.js:402
msgid "Disabled"
msgstr "Onemogućeno"
#: ../js/ui/lookingGlass.js:404
msgid "Error"
msgstr "Greška"
#: ../js/ui/lookingGlass.js:406
msgid "Out of date"
msgstr "Istekao je datum"
#: ../js/ui/lookingGlass.js:431
msgid "View Source"
msgstr "Pogledaj izvor"
#: ../js/ui/lookingGlass.js:437
msgid "Web Page"
msgstr "Internet stranica"
#: ../js/ui/overview.js:182
msgid "Undo"
msgstr "Opozovi"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:336
#: ../js/ui/panel.js:385
msgid "Activities"
msgstr "Aktivnosti"
#. Translators: This is a time format.
#: ../js/ui/panel.js:549
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:616
msgid "%a %R"
msgstr "%A, %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:619
msgid "%a %l:%M %p"
msgstr "%A, %H:%M"
#: ../js/ui/placeDisplay.js:144
#: ../js/ui/placeDisplay.js:103
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Ne mogu da demontiram „%s“"
#: ../js/ui/placeDisplay.js:106
msgid "Retry"
msgstr "Ponovi"
#: ../js/ui/placeDisplay.js:151
msgid "Connect to..."
msgstr "Poveži se na..."
#: ../js/ui/runDialog.js:245
#: ../js/ui/runDialog.js:232
msgid "Please enter a command:"
msgstr "Unesite naredbu:"
#: ../js/ui/runDialog.js:361
#: ../js/ui/runDialog.js:374
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Nije uspelo pokretanje „%s“:"
#: ../js/ui/statusMenu.js:107
msgid "Available"
msgstr "Dostupan"
#: ../js/ui/statusMenu.js:112
msgid "Busy"
msgstr "Zauzet"
#: ../js/ui/statusMenu.js:117
msgid "Invisible"
msgstr "Nevidljiv"
#: ../js/ui/statusMenu.js:126
msgid "Account Information..."
msgstr "Podaci o nalogu..."
#: ../js/ui/statusMenu.js:132
#| msgid "Search"
msgid "Sidebar"
msgstr "Bočna traka"
#: ../js/ui/statusMenu.js:142
msgid "System Preferences..."
msgstr "Postavke sistema..."
#: ../js/ui/statusMenu.js:151
msgid "Lock Screen"
msgstr "Zaključaj ekran"
#: ../js/ui/statusMenu.js:156
msgid "Switch User"
msgstr "Promeni korisnika"
#: ../js/ui/statusMenu.js:162
msgid "Log Out..."
msgstr "Odjavi me..."
#: ../js/ui/statusMenu.js:167
msgid "Shut Down..."
msgstr "Isključi..."
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
@ -112,11 +211,21 @@ msgstr "Programi"
msgid "Recent Documents"
msgstr "Skorašnji dokumenti"
#: ../src/shell-global.c:890
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s je pokrenut"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "„%s“ je spreman"
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Pre manje od jednog minuta"
#: ../src/shell-global.c:894
#: ../src/shell-global.c:971
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
@ -125,7 +234,7 @@ msgstr[1] "Pre %d minuta"
msgstr[2] "Pre %d minuta"
msgstr[3] "Pre %d minuta"
#: ../src/shell-global.c:899
#: ../src/shell-global.c:976
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
@ -134,7 +243,7 @@ msgstr[1] "Pre %d sata"
msgstr[2] "Pre %d sata"
msgstr[3] "Pre %d sata"
#: ../src/shell-global.c:904
#: ../src/shell-global.c:981
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
@ -143,7 +252,7 @@ msgstr[1] "Pre %d dana"
msgstr[2] "Pre %d dana"
msgstr[3] "Pre %d dana"
#: ../src/shell-global.c:909
#: ../src/shell-global.c:986
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"

280
po/uk.po Normal file
View File

@ -0,0 +1,280 @@
# Ukrainian translation for gnome-shell.
# Copyright (C) 2010 Free Software Foundation
# This file is distributed under the same license as the gnome-shell package.
# Maxim V. Dziumanenko <dziumanenko@gmail.com>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&component=general\n"
"POT-Creation-Date: 2010-03-31 13:32+0000\n"
"PO-Revision-Date: 2010-03-31 13:32+0000\n"
"Last-Translator: Maxim V. Dziumanenko <dziumanenko@gmail.com>\n"
"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.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%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\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 "Керування вікнами та запуск програм"
#. **** Applications ****
#: ../js/ui/appDisplay.js:312 ../js/ui/dash.js:855
msgid "APPLICATIONS"
msgstr "ПРОГРАМИ"
#: ../js/ui/appDisplay.js:344
msgid "PREFERENCES"
msgstr "ПАРАМЕТРИ"
#: ../js/ui/appDisplay.js:734
msgid "New Window"
msgstr "Нове вікно"
#: ../js/ui/appDisplay.js:738
msgid "Remove from Favorites"
msgstr "Видалити з улюбленого"
#: ../js/ui/appDisplay.js:739
msgid "Add to Favorites"
msgstr "Додати до улюбленого"
#: ../js/ui/appDisplay.js:1091
msgid "Drag here to add favorites"
msgstr "Перетягніть сюди для додавання до улюбленого"
#: ../js/ui/appFavorites.js:89
#, c-format
msgid "%s has been added to your favorites."
msgstr "%s додано до улюбленого."
#: ../js/ui/appFavorites.js:107
#, c-format
msgid "%s has been removed from your favorites."
msgstr "%s видалено з улюбленого."
#: ../js/ui/dash.js:194
msgid "Find"
msgstr "Знайти"
#: ../js/ui/dash.js:510
msgid "Searching..."
msgstr "Пошук..."
#: ../js/ui/dash.js:524
msgid "No matching results."
msgstr "Немає відповідностей."
#. **** Places ****
#. Translators: This is in the sense of locations for documents,
#. network locations, etc.
#: ../js/ui/dash.js:874 ../js/ui/placeDisplay.js:543
msgid "PLACES & DEVICES"
msgstr "МІСЦЯ ТА ПРИСТРОЇ"
#. **** Documents ****
#: ../js/ui/dash.js:881 ../js/ui/docDisplay.js:489
msgid "RECENT ITEMS"
msgstr "ОСТАННІ ДОКУМЕНТИ"
#: ../js/ui/lookingGlass.js:363
msgid "No extensions installed"
msgstr "Не встановлено розширення"
#: ../js/ui/lookingGlass.js:400
msgid "Enabled"
msgstr "Увімкнено"
#: ../js/ui/lookingGlass.js:402
msgid "Disabled"
msgstr "Вимкнено"
#: ../js/ui/lookingGlass.js:404
msgid "Error"
msgstr "Помилка"
#: ../js/ui/lookingGlass.js:406
msgid "Out of date"
msgstr "Застаріло"
#: ../js/ui/lookingGlass.js:431
msgid "View Source"
msgstr "Переглянути джерело"
#: ../js/ui/lookingGlass.js:437
msgid "Web Page"
msgstr "Веб-сторінка"
#: ../js/ui/overview.js:182
msgid "Undo"
msgstr "Вернути"
#. Button on the left side of the panel.
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:388
msgid "Activities"
msgstr "Дії"
#. Translators: This is the time format used in 24-hour mode.
#: ../js/ui/panel.js:619
msgid "%a %R"
msgstr "%a %R"
#. Translators: This is a time format used for AM/PM.
#: ../js/ui/panel.js:622
msgid "%a %l:%M %p"
msgstr "%a, %H:%M"
#: ../js/ui/placeDisplay.js:108
#, c-format
msgid "Failed to unmount '%s'"
msgstr "Помилка при відключенні '%s'"
#: ../js/ui/placeDisplay.js:111
msgid "Retry"
msgstr "Повторити"
#: ../js/ui/placeDisplay.js:156
msgid "Connect to..."
msgstr "З'єднатися з..."
#: ../js/ui/runDialog.js:232
msgid "Please enter a command:"
msgstr "Введіть команду:"
#: ../js/ui/runDialog.js:376
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Не вдається виконати «%s»:"
#: ../js/ui/statusMenu.js:107
msgid "Available"
msgstr "Доступний"
#: ../js/ui/statusMenu.js:112
msgid "Busy"
msgstr "Зайнятий"
#: ../js/ui/statusMenu.js:117
msgid "Invisible"
msgstr "Невидимий"
#: ../js/ui/statusMenu.js:126
msgid "Account Information..."
msgstr "Інформація про користувача..."
#: ../js/ui/statusMenu.js:132
msgid "Sidebar"
msgstr "Бічна панель"
#: ../js/ui/statusMenu.js:142
msgid "System Preferences..."
msgstr "Параметри системи..."
#: ../js/ui/statusMenu.js:151
msgid "Lock Screen"
msgstr "Блокувати екран"
#: ../js/ui/statusMenu.js:156
msgid "Switch User"
msgstr "Змінити користувача"
#: ../js/ui/statusMenu.js:162
msgid "Log Out..."
msgstr "Завершити сеанс..."
#: ../js/ui/statusMenu.js:167
msgid "Shut Down..."
msgstr "Вимкнути..."
#. Translators: This is a time format.
#: ../js/ui/widget.js:163
msgid "%H:%M"
msgstr "%H:%M"
#: ../js/ui/widget.js:317
msgid "Applications"
msgstr "Програми"
#: ../js/ui/widget.js:339
msgid "Recent Documents"
msgstr "Недавні документи"
#: ../js/ui/windowAttentionHandler.js:47
#, c-format
msgid "%s has finished starting"
msgstr "%s завершив запуск"
#: ../js/ui/windowAttentionHandler.js:49
#, c-format
msgid "'%s' is ready"
msgstr "'%s' готовий"
#: ../src/shell-global.c:967
msgid "Less than a minute ago"
msgstr "Менше хвилини тому"
#: ../src/shell-global.c:971
#, c-format
msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "%d хвилина тому"
msgstr[1] "%d хвилини тому"
msgstr[2] "%d хвилин тому"
#: ../src/shell-global.c:976
#, c-format
msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "%d година тому"
msgstr[1] "%d години тому"
msgstr[2] "%d годин тому"
#: ../src/shell-global.c:981
#, c-format
msgid "%d day ago"
msgid_plural "%d days ago"
msgstr[0] "%d день тому"
msgstr[1] "%d дні тому"
msgstr[2] "%d днів тому"
#: ../src/shell-global.c:986
#, c-format
msgid "%d week ago"
msgid_plural "%d weeks ago"
msgstr[0] "%d тиждень тому"
msgstr[1] "%d тижні тому"
msgstr[2] "%d тижнів тому"
#: ../src/shell-uri-util.c:89
msgid "Home Folder"
msgstr "Домашня тека"
#. Translators: this is the same string as the one found in
#. * nautilus
#: ../src/shell-uri-util.c:104
msgid "File System"
msgstr "Файлова система"
#: ../src/shell-uri-util.c:250
msgid "Search"
msgstr "Пошук"
#. Translators: the first string is the name of a gvfs
#. * method, and the second string is a path. For
#. * example, "Trash: some-directory". It means that the
#. * directory called "some-directory" is in the trash.
#.
#: ../src/shell-uri-util.c:300
#, c-format
msgid "%1$s: %2$s"
msgstr "%1$s: %2$s"

View File

@ -1,68 +0,0 @@
big_cflags = \
-I$(top_srcdir)/src \
-DPREFIX=\""$(prefix)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DG_DISABLE_DEPRECATED \
-DG_LOG_DOMAIN=\"Big\" \
$(BIG_CFLAGS) \
$(NULL)
big_built_sources = \
big-enum-types.h \
big-enum-types.c \
$(NULL)
BUILT_SOURCES += $(big_built_sources)
BIG_STAMP_FILES = stamp-big-marshal.h stamp-big-enum-types.h
# please, keep this sorted alphabetically
big_source_h = \
big/box.h \
big/rectangle.h \
big/theme-image.h \
$(NULL)
# please, keep this sorted alphabetically
big_source_c = \
big/box.c \
big/rectangle.c \
big/theme-image.c \
$(NULL)
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
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/big/big-enum-types.h.in \
$(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
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/big/big-enum-types.c.in \
$(big_source_h) ) >> xgen-betc && \
cp xgen-betc big-enum-types.c && \
rm -f xgen-betc
noinst_LTLIBRARIES += libbig-1.0.la
libbig_1_0_la_LIBADD = $(BIG_LIBS)
libbig_1_0_la_SOURCES = \
$(big_source_c) \
$(big_source_h) \
$(big_built_sources) \
$(NULL)
libbig_1_0_la_CPPFLAGS = $(big_cflags)
libbig_1_0_la_LDFLAGS = $(LDADD)
CLEANFILES += $(BIG_STAMP_FILES) $(BUILT_SOURCES)
EXTRA_DIST += \
big/README \
big/big-enum-types.h.in \
big/big-enum-types.c.in

View File

@ -74,8 +74,10 @@ st_source_h = \
st/st-button.h \
st/st-clickable.h \
st/st-clipboard.h \
st/st-container.h \
st/st-drawing-area.h \
st/st-entry.h \
st/st-group.h \
st/st-im-text.h \
st/st-label.h \
st/st-overflow-box.h \
@ -83,13 +85,11 @@ st_source_h = \
st/st-scrollable.h \
st/st-scroll-bar.h \
st/st-scroll-view.h \
st/st-shadow-texture.h \
st/st-shadow.h \
st/st-subtexture.h \
st/st-table.h \
st/st-table-child.h \
st/st-texture-cache.h \
st/st-texture-frame.h \
st/st-theme.h \
st/st-theme-context.h \
st/st-theme-node.h \
@ -109,7 +109,8 @@ BUILT_SOURCES += st.h
st_source_private_h = \
st/st-private.h \
st/st-table-private.h \
st/st-theme-private.h
st/st-theme-private.h \
st/st-theme-node-private.h
# please, keep this sorted alphabetically
st_source_c = \
@ -121,8 +122,10 @@ st_source_c = \
st/st-button.c \
st/st-clickable.c \
st/st-clipboard.c \
st/st-container.c \
st/st-drawing-area.c \
st/st-entry.c \
st/st-group.c \
st/st-im-text.c \
st/st-label.c \
st/st-overflow-box.c \
@ -130,23 +133,22 @@ st_source_c = \
st/st-scrollable.c \
st/st-scroll-bar.c \
st/st-scroll-view.c \
st/st-shadow-texture.c \
st/st-shadow.c \
st/st-subtexture.c \
st/st-table.c \
st/st-table-child.c \
st/st-texture-cache.c \
st/st-texture-frame.c \
st/st-theme.c \
st/st-theme-context.c \
st/st-theme-node.c \
st/st-theme-node-drawing.c \
st/st-tooltip.c \
st/st-widget.c \
$(NULL)
noinst_LTLIBRARIES += libst-1.0.la
libst_1_0_la_LIBADD = $(ST_LIBS)
libst_1_0_la_LIBADD = -lm $(ST_LIBS)
libst_1_0_la_SOURCES = \
$(st_source_c) \
$(st_source_private_h) \

View File

@ -15,6 +15,7 @@ TRAY_STAMP_FILES = stamp-na-marshal.h
# please, keep this sorted alphabetically
tray_source = \
gtk-compat.h \
tray/na-tray-child.c \
tray/na-tray-child.h \
tray/na-tray-manager.c \

View File

@ -8,7 +8,7 @@ noinst_PROGRAMS =
.AUTOPARALLEL:
bin_SCRIPTS = gnome-shell
bin_SCRIPTS = gnome-shell gnome-shell-clock-preferences
gnome-shell: gnome-shell.in
$(AM_V_GEN) sed -e "s|@MUTTER_BIN_DIR[@]|$(MUTTER_BIN_DIR)|" \
@ -24,7 +24,13 @@ gnome-shell: gnome-shell.in
CLEANFILES += gnome-shell
EXTRA_DIST += gnome-shell.in
include Makefile-big.am
gnome-shell-clock-preferences: gnome-shell-clock-preferences.in
$(AM_V_GEN) sed -e "s|@pkgdatadir[@]|$(pkgdatadir)|" \
-e "s|@GJS_CONSOLE[@]|$(GJS_CONSOLE)|" \
$< > $@ && chmod a+x $@
CLEANFILES += gnome-shell-clock-preferences
EXTRA_DIST += gnome-shell-clock-preferences.in
include Makefile-gdmuser.am
include Makefile-st.am
include Makefile-tray.am
@ -43,60 +49,69 @@ plugin_LTLIBRARIES = libgnome-shell.la
shell_built_sources = \
shell-marshal.h \
shell-marshal.c
shell-marshal.c \
shell-enum-types.h \
shell-enum-types.c
BUILT_SOURCES += $(shell_built_sources)
EXTRA_DIST += shell-marshal.list
SHELL_STAMP_FILES = stamp-shell-marshal.h
CLEANFILES += $(SHELL_STAMP_FILES)
libgnome_shell_la_SOURCES = \
$(shell_built_sources) \
gnome-shell-plugin.c \
shell-app.c \
shell-app.h \
shell-app-private.h \
shell-app-system.c \
shell-app-system.h \
shell-app-usage.c \
shell-app-usage.h \
shell-arrow.c \
shell_public_headers_h = \
shell-app.h \
shell-app-system.h \
shell-app-usage.h \
shell-arrow.h \
shell-doc-system.c \
shell-doc-system.h \
shell-drawing.c \
shell-drawing.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-doc-system.h \
shell-drawing.h \
shell-embedded-window.h \
shell-gconf.h \
shell-generic-container.h \
shell-gtk-embed.h \
shell-menu.h \
shell-overflow-list.h \
shell-process.c \
shell-process.h \
shell-global.c \
shell-global.h \
shell-global-private.h \
shell-slicer.c \
shell-slicer.h \
shell-stack.c \
shell-stack.h \
shell-tray-manager.c \
shell-tray-manager.h \
shell-uri-util.c \
shell-uri-util.h \
shell-process.h \
shell-global.h \
shell-perf-log.h \
shell-slicer.h \
shell-stack.h \
shell-tray-manager.h \
shell-uri-util.h \
shell-window-tracker.h \
shell-wm.h \
shell-xfixes-cursor.h
libgnome_shell_la_SOURCES = \
$(shell_built_sources) \
$(shell_public_headers_h) \
gnome-shell-plugin.c \
gtk-compat.h \
shell-app.c \
shell-app-private.h \
shell-app-system.c \
shell-app-usage.c \
shell-arrow.c \
shell-doc-system.c \
shell-drawing.c \
shell-embedded-window.c \
shell-embedded-window-private.h \
shell-gconf.c \
shell-generic-container.c \
shell-gtk-embed.c \
shell-menu.c \
shell-overflow-list.c \
shell-process.c \
shell-global.c \
shell-global-private.h \
shell-perf-log.c \
shell-slicer.c \
shell-stack.c \
shell-tray-manager.c \
shell-uri-util.c \
shell-window-tracker.c \
shell-window-tracker.h \
shell-wm.c \
shell-wm.h
shell-wm.c \
shell-xfixes-cursor.c
non_gir_sources = \
shell-embedded-window-private.h \
@ -140,6 +155,7 @@ stamp-shell-marshal.h: Makefile shell-marshal.list
(cmp -s xgen-smh shell-marshal.h || cp -f xgen-smh shell-marshal.h) && \
rm -f xgen-smh && \
echo timestamp > $(@F)
CLEANFILES += stamp-shell-marshal.h
shell-marshal.c: Makefile shell-marshal.list
$(AM_V_GEN) (echo "#include \"shell-marshal.h\"" ; \
@ -150,29 +166,50 @@ shell-marshal.c: Makefile shell-marshal.list
cp -f xgen-smc shell-marshal.c && \
rm -f xgen-smc
shell-enum-types.h: stamp-shell-enum-types.h Makefile
@true
stamp-shell-enum-types.h: $(srcdir)/shell-enum-types.h.in $(shell_public_headers_h)
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $< \
$(shell_public_headers_h) ) > $@.tmp && \
(cmp -s $@.tmp shell-enum-types.h || mv $@.tmp shell-enum-types.h) && \
rm -f $@.tmp && \
echo timestamp > $(@F)
EXTRA_DIST += shell-enum-types.h.in
CLEANFILES += stamp-shell-enum-types.h
shell-enum-types.c: shell-enum-types.c.in stamp-shell-enum-types.h
$(AM_V_GEN) ( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $< \
$(shell_public_headers_h) ) > $@.tmp && \
mv $@.tmp $@ && \
rm -f $@.tmp
EXTRA_DIST += shell-enum-types.c.in
libgnome_shell_la_LDFLAGS = -avoid-version -module
libgnome_shell_la_LIBADD = \
libgnome_shell_la_LIBADD =-lm \
$(MUTTER_PLUGIN_LIBS) \
$(LIBGNOMEUI_LIBS) \
libbig-1.0.la \
libst-1.0.la \
libgdmuser-1.0.la \
libtray.la
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
typelibdir = $(pkglibdir)
typelib_DATA = Shell-0.1.typelib Big-1.0.typelib St-1.0.typelib Gdm-1.0.typelib
typelib_DATA = Shell-0.1.typelib St-1.0.typelib Gdm-1.0.typelib
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir St-1.0.gir libgnome-shell.la Makefile
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) St-1.0.gir libgnome-shell.la Makefile
$(AM_V_GEN) $(G_IR_SCANNER) \
--namespace=Shell \
--nsversion=0.1 \
--add-include-path=$(MUTTER_LIB_DIR)/mutter/ \
--include=Clutter-1.0 \
--include=Meta-2.29 \
--include=Meta-2.31 \
--libtool="$(LIBTOOL)" \
--add-include-path=$(builddir) \
--include=Big-1.0 \
--include=St-1.0 \
--program=mutter \
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
@ -184,7 +221,7 @@ 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
Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir
$(AM_V_GEN) \
$(G_IR_COMPILER) \
--includedir=. \
@ -192,25 +229,6 @@ Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir Big-1.0.gir
Shell-0.1.gir -o $@
CLEANFILES += Shell-0.1.typelib
Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libbig-1.0.la Makefile
$(AM_V_GEN) $(G_IR_SCANNER) \
--namespace=Big \
--nsversion=1.0 \
--include=Clutter-1.0 \
--include=GdkPixbuf-2.0 \
--libtool="$(LIBTOOL)" \
--library=libbig-1.0.la \
$(addprefix $(srcdir)/,$(big_source_h)) \
$(addprefix $(srcdir)/,$(big_source_c)) \
$(srcdir)/big-enum-types.h \
$(big_cflags) \
-o $@
CLEANFILES += Big-1.0.gir
Big-1.0.typelib: libbig-1.0.la Big-1.0.gir
$(AM_V_GEN) $(G_IR_COMPILER) Big-1.0.gir -o $@
CLEANFILES += Big-1.0.typelib
St-1.0.gir: $(mutter) $(G_IR_SCANNER) libst-1.0.la Makefile
$(AM_V_GEN) $(G_IR_SCANNER) \
--namespace=St \
@ -220,7 +238,6 @@ St-1.0.gir: $(mutter) $(G_IR_SCANNER) libst-1.0.la Makefile
--add-include-path=$(builddir) \
--libtool="$(LIBTOOL)" \
--library=libst-1.0.la \
--library=libbig-1.0.la \
-DST_COMPILATION \
$(addprefix $(srcdir)/,$(st_source_h)) \
$(addprefix $(srcdir)/,$(st_source_c)) \
@ -249,7 +266,7 @@ Gdm-1.0.gir: $(mutter) $(G_IR_SCANNER) libgdmuser-1.0.la Makefile
-o $@
CLEANFILES += Gdm-1.0.gir
Gdm-1.0.typelib: libbig-1.0.la Gdm-1.0.gir
Gdm-1.0.typelib: Gdm-1.0.gir
$(AM_V_GEN) $(G_IR_COMPILER) Gdm-1.0.gir -o $@
CLEANFILES += Gdm-1.0.typelib

View File

@ -1,25 +0,0 @@
The Clutter actors and other files in this directory were created by
litl, LLC. They are released under the terms of the Library General
Public license.
The idea is that these actors may eventually make their way into Clutter
or into other libraries.
litl has requested that these actors should not be publically
installed under the 'big_*' names to avoid conflicts with their
development. So if you use them in your applications, do *NOT*
install:
- A 'libbig' library
- The header files
- gobject-introspection data for these actors
Into public locations. You can of course, take the code and rename it,
as long as you respect the provisions of the LGPL, or install into
private locations as we do for gnome-shell. (We install the typelib
into a private location, link the source files directly into the
gnome-shell plugin so no external library is needed, and we don't
install the header files at all.)
Patches applied:
http://bugzilla.gnome.org/show_bug.cgi?id=562929

File diff suppressed because it is too large Load Diff

View File

@ -1,129 +0,0 @@
/* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* big-box.h: Box container.
Copyright (C) 2006-2008 Red Hat, Inc.
Copyright (C) 2008 litl, LLC.
The libbigwidgets-lgpl is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The libbigwidgets-lgpl 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the libbigwidgets-lgpl; see the file COPYING.LIB.
If not, write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __BIG_BOX_H__
#define __BIG_BOX_H__
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define BIG_TYPE_BOX (big_box_get_type ())
#define BIG_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BIG_TYPE_BOX, BigBox))
#define BIG_IS_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BIG_TYPE_BOX))
#define BIG_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BIG_TYPE_BOX, BigBoxClass))
#define BIG_IS_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BIG_TYPE_BOX))
#define BIG_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BIG_TYPE_BOX, BigBoxClass))
typedef struct _BigBox BigBox;
typedef struct _BigBoxPrivate BigBoxPrivate;
typedef struct _BigBoxClass BigBoxClass;
typedef enum
{
BIG_BOX_PACK_NONE = 0,
BIG_BOX_PACK_EXPAND = 1 << 0,
BIG_BOX_PACK_END = 1 << 1,
BIG_BOX_PACK_IF_FITS = 1 << 2,
BIG_BOX_PACK_FIXED = 1 << 3,
BIG_BOX_PACK_ALLOCATE_WHEN_HIDDEN = 1 << 4
} BigBoxPackFlags;
typedef enum
{
BIG_BOX_ALIGNMENT_FIXED = 0,
BIG_BOX_ALIGNMENT_FILL = 1,
BIG_BOX_ALIGNMENT_START = 2,
BIG_BOX_ALIGNMENT_END = 3,
BIG_BOX_ALIGNMENT_CENTER = 4
} BigBoxAlignment;
typedef enum
{
BIG_BOX_ORIENTATION_VERTICAL = 1,
BIG_BOX_ORIENTATION_HORIZONTAL = 2
} BigBoxOrientation;
typedef enum
{
BIG_BOX_BACKGROUND_REPEAT_NONE = 0,
BIG_BOX_BACKGROUND_REPEAT_X = 1,
BIG_BOX_BACKGROUND_REPEAT_Y = 2,
BIG_BOX_BACKGROUND_REPEAT_BOTH = 3,
} BigBoxBackgroundRepeat;
struct _BigBox
{
ClutterActor parent_instance;
BigBoxPrivate *priv;
};
struct _BigBoxClass
{
ClutterActorClass parent_class;
};
GType big_box_get_type (void) G_GNUC_CONST;
ClutterActor *big_box_new (BigBoxOrientation orientation);
void big_box_prepend (BigBox *box,
ClutterActor *child,
BigBoxPackFlags flags);
void big_box_append (BigBox *box,
ClutterActor *child,
BigBoxPackFlags flags);
gboolean big_box_is_empty (BigBox *box);
void big_box_remove_all (BigBox *box);
void big_box_insert_after (BigBox *box,
ClutterActor *child,
ClutterActor *ref_child,
BigBoxPackFlags flags);
void big_box_insert_before (BigBox *box,
ClutterActor *child,
ClutterActor *ref_child,
BigBoxPackFlags flags);
void big_box_set_child_packing (BigBox *box,
ClutterActor *child,
BigBoxPackFlags flags);
void big_box_set_child_align (BigBox *box,
ClutterActor *child,
BigBoxAlignment fixed_x_align,
BigBoxAlignment fixed_y_align);
void big_box_set_padding (BigBox *box,
int padding);
void big_box_set_border_width (BigBox *box,
int border_width);
G_END_DECLS
#endif /* __BIG_BOX_H__ */

View File

@ -1,658 +0,0 @@
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/* rectangle.c: Rounded rectangle.
Copyright (C) 2008 litl, LLC.
The libbigwidgets-lgpl is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The libbigwidgets-lgpl 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the libbigwidgets-lgpl; see the file COPYING.LIB.
If not, write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <math.h>
#include <glib.h>
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <cairo/cairo.h>
#include "rectangle.h"
typedef struct {
gint ref_count;
ClutterColor color;
ClutterColor border_color;
int radius;
int border_width;
CoglHandle texture;
guint8 *data;
} Corner;
struct BigRectangle {
ClutterRectangle parent_instance;
float radius;
Corner *corner;
CoglHandle corner_material;
CoglHandle border_material;
CoglHandle background_material;
gboolean corners_dirty;
};
/* map of { radius, border_width, border_color, color } to Corner textures */
static GHashTable *all_corners = NULL;
struct BigRectangleClass {
ClutterRectangleClass parent_class;
};
G_DEFINE_TYPE(BigRectangle, big_rectangle, CLUTTER_TYPE_RECTANGLE)
enum
{
PROP_0,
PROP_CORNER_RADIUS
};
static gboolean
corner_equal(gconstpointer a,
gconstpointer b)
{
const Corner *corner_a;
const Corner *corner_b;
corner_a = a;
corner_b = b;
return *((guint32 *)&corner_a->color) == *((guint32 *)&corner_b->color) &&
*((guint32 *)&corner_a->border_color) == *((guint32 *)&corner_b->border_color) &&
corner_a->border_width == corner_b->border_width &&
corner_a->radius == corner_b->radius;
}
static guint
corner_hash(gconstpointer key)
{
const Corner *corner;
guint hashed[4];
corner = key;
hashed[0] = *((guint *)&(corner->color));
hashed[1] = *((guint *)&(corner->border_color));
hashed[2] = *((guint *)&(corner->border_width));
hashed[3] = *((guint *)&(corner->radius));
return hashed[0] ^ hashed[1] ^ hashed[2] ^ hashed[3];
}
static Corner *
create_corner_texture(Corner *src)
{
Corner *corner;
CoglHandle texture;
cairo_t *cr;
cairo_surface_t *surface;
guint x, y;
guint rowstride;
guint8 *data;
guint32 *src_p;
guint8 *dst_p;
guint size;
corner = g_memdup(src, sizeof(Corner));
size = 2 * MAX(corner->border_width, corner->radius);
rowstride = size * 4;
data = g_new0(guint8, size * rowstride);
surface = cairo_image_surface_create_for_data(data,
CAIRO_FORMAT_ARGB32,
size, size,
rowstride);
cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_scale(cr, size, size);
if (corner->border_width < corner->radius) {
double internal_radius = 0.5 * (1.0 - (double) corner->border_width / corner->radius);
if (corner->border_width != 0) {
cairo_set_source_rgba(cr,
(double)corner->border_color.red / G_MAXUINT8,
(double)corner->border_color.green / G_MAXUINT8,
(double)corner->border_color.blue / G_MAXUINT8,
(double)corner->border_color.alpha / G_MAXUINT8);
cairo_arc(cr, 0.5, 0.5, 0.5, 0, 2 * M_PI);
cairo_fill(cr);
}
cairo_set_source_rgba(cr,
(double)corner->color.red / G_MAXUINT8,
(double)corner->color.green / G_MAXUINT8,
(double)corner->color.blue / G_MAXUINT8,
(double)corner->color.alpha / G_MAXUINT8);
cairo_arc(cr, 0.5, 0.5, internal_radius, 0, 2 * M_PI);
cairo_fill(cr);
} else {
double radius;
radius = (gdouble)corner->radius / corner->border_width;
cairo_set_source_rgba(cr,
(double)corner->border_color.red / G_MAXUINT8,
(double)corner->border_color.green / G_MAXUINT8,
(double)corner->border_color.blue / G_MAXUINT8,
(double)corner->border_color.alpha / G_MAXUINT8);
cairo_arc(cr, radius, radius, radius, M_PI, 3 * M_PI / 2);
cairo_line_to(cr, 1.0 - radius, 0.0);
cairo_arc(cr, 1.0 - radius, radius, radius, 3 * M_PI / 2, 2*M_PI);
cairo_line_to(cr, 1.0, 1.0 - radius);
cairo_arc(cr, 1.0 - radius, 1.0 - radius, radius, 0, M_PI / 2);
cairo_line_to(cr, radius, 1.0);
cairo_arc(cr, radius, 1.0 - radius, radius, M_PI / 2, M_PI);
cairo_fill(cr);
}
cairo_destroy(cr);
cairo_surface_destroy(surface);
corner->data = g_new0(guint8, size * rowstride);
/* cogl doesn't seem to support the conversion, do it manually */
/* borrowed from clutter-cairo, conversion from ARGB pre-multiplied
* to RGBA */
for (y = 0; y < size; y++) {
src_p = (guint32 *) (data + y * rowstride);
dst_p = corner->data + y * rowstride;
for (x = 0; x < size; x++) {
guint8 alpha = (*src_p >> 24) & 0xff;
if (alpha == 0) {
dst_p[0] = dst_p[1] = dst_p[2] = dst_p[3] = alpha;
} else {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
dst_p[0] = (((*src_p >> 16) & 0xff) * 255 ) / alpha;
dst_p[1] = (((*src_p >> 8) & 0xff) * 255 ) / alpha;
dst_p[2] = (((*src_p >> 0) & 0xff) * 255 ) / alpha;
dst_p[3] = alpha;
#elif G_BYTE_ORDER == G_BIG_ENDIAN
dst_p[0] = alpha;
dst_p[1] = (((*src_p >> 0) & 0xff) * 255 ) / alpha;
dst_p[2] = (((*src_p >> 8) & 0xff) * 255 ) / alpha;
dst_p[3] = (((*src_p >> 16) & 0xff) * 255 ) / alpha;
#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
#error unknown ENDIAN type
#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
}
dst_p += 4;
src_p++;
}
}
g_free(data);
texture = cogl_texture_new_from_data(size, size,
COGL_TEXTURE_NONE,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_ANY,
rowstride,
corner->data);
g_assert(texture != COGL_INVALID_HANDLE);
corner->ref_count = 1;
corner->texture = texture;
g_hash_table_insert(all_corners, corner, corner);
return corner;
}
static void
corner_unref(Corner *corner)
{
corner->ref_count --;
if (corner->ref_count == 0) {
g_hash_table_remove(all_corners, corner);
cogl_handle_unref(corner->texture);
g_free(corner->data);
g_free(corner);
}
}
static Corner *
corner_get(guint radius,
ClutterColor *color,
guint border_width,
ClutterColor *border_color)
{
Corner key;
Corner *corner;
if (all_corners == NULL) {
all_corners = g_hash_table_new(corner_hash, corner_equal);
}
key.radius = radius;
key.color = *color;
key.border_color = *border_color;
key.border_width = border_width;
corner = g_hash_table_lookup(all_corners, &key);
if (!corner) {
corner = create_corner_texture(&key);
} else {
corner->ref_count ++;
}
return corner;
}
/* To match the CSS specification, we want the border to look like it was
* drawn over the background. But actually drawing the border over the
* background will produce slightly bad antialiasing at the edges, so
* compute the effective border color instead.
*/
#define NORM(x) (t = (x) + 127, (t + (t >> 8)) >> 8)
#define MULT(c,a) NORM(c*a)
static void
premultiply (ClutterColor *color)
{
guint t;
color->red = MULT (color->red, color->alpha);
color->green = MULT (color->green, color->alpha);
color->blue = MULT (color->blue, color->alpha);
}
static void
unpremultiply (ClutterColor *color)
{
if (color->alpha != 0) {
color->red = (color->red * 255 + 127) / color->alpha;
color->green = (color->green * 255 + 127) / color->alpha;
color->blue = (color->blue * 255 + 127) / color->alpha;
}
}
static void
over (const ClutterColor *source,
const ClutterColor *destination,
ClutterColor *result)
{
guint t;
ClutterColor src = *source;
ClutterColor dst = *destination;
premultiply (&src);
premultiply (&dst);
result->alpha = src.alpha + NORM ((255 - src.alpha) * dst.alpha);
result->red = src.red + NORM ((255 - src.alpha) * dst.red);
result->green = src.green + NORM ((255 - src.alpha) * dst.green);
result->blue = src.blue + NORM ((255 - src.alpha) * dst.blue);
unpremultiply (result);
}
static void
big_rectangle_update_corners(BigRectangle *rectangle)
{
Corner *corner;
corner = NULL;
if (rectangle->radius != 0) {
ClutterColor *color;
ClutterColor *border_color;
ClutterColor effective_border;
guint border_width;
g_object_get(rectangle,
"border-color", &border_color,
"border-width", &border_width,
"color", &color,
NULL);
over (border_color, color, &effective_border);
corner = corner_get(rectangle->radius,
color,
border_width,
&effective_border);
clutter_color_free(border_color);
clutter_color_free(color);
}
if (rectangle->corner) {
corner_unref(rectangle->corner);
}
rectangle->corner = corner;
if (corner) {
if (!rectangle->corner_material)
rectangle->corner_material = cogl_material_new();
cogl_material_set_layer (rectangle->corner_material, 0,
rectangle->corner->texture);
}
rectangle->corners_dirty = FALSE;
}
static void
big_rectangle_paint(ClutterActor *actor)
{
BigRectangle *rectangle;
ClutterColor *color;
ClutterColor *border_color;
guint8 actor_opacity;
CoglColor tmp_color;
guint border_width;
ClutterActorBox box;
float radius;
float width;
float height;
float max;
rectangle = BIG_RECTANGLE(actor);
/* We can't chain up, even when we the radius is 0, because of the different
* interpretation of the border/background relationship here than for
* ClutterRectangle.
*/
if (rectangle->corners_dirty)
big_rectangle_update_corners(rectangle);
g_object_get(rectangle,
"border-color", &border_color,
"border-width", &border_width,
"color", &color,
NULL);
if (border_color->alpha == 0 && color->alpha == 0)
goto out;
actor_opacity = clutter_actor_get_paint_opacity (actor);
clutter_actor_get_allocation_box(actor, &box);
/* translation was already done */
box.x2 -= box.x1;
box.y2 -= box.y1;
width = box.x2;
height = box.y2;
radius = rectangle->radius;
/* Optimization; if the border is transparent, it just looks like part of
* the background */
if (radius == 0 && border_color->alpha == 0)
border_width = 0;
max = MAX(border_width, radius);
if (radius != 0) {
cogl_color_set_from_4ub(&tmp_color,
actor_opacity, actor_opacity, actor_opacity, actor_opacity);
cogl_material_set_color(rectangle->corner_material, &tmp_color);
cogl_set_source(rectangle->corner_material);
/* NW */
cogl_rectangle_with_texture_coords(0, 0,
max, max,
0, 0,
0.5, 0.5);
/* NE */
cogl_rectangle_with_texture_coords(width - max, 0,
width, max,
0.5, 0,
1.0, 0.5);
/* SW */
cogl_rectangle_with_texture_coords(0, height - max,
max, height,
0, 0.5,
0.5, 1.0);
/* SE */
cogl_rectangle_with_texture_coords(width - max, height - max,
width, height,
0.5, 0.5,
1.0, 1.0);
}
if (border_width != 0) {
ClutterColor effective_border;
over (border_color, color, &effective_border);
if (!rectangle->border_material)
rectangle->border_material = cogl_material_new ();
cogl_color_set_from_4ub(&tmp_color,
effective_border.red,
effective_border.green,
effective_border.blue,
actor_opacity * effective_border.alpha / 255);
cogl_color_premultiply (&tmp_color);
cogl_material_set_color(rectangle->border_material, &tmp_color);
cogl_set_source(rectangle->border_material);
if (radius > 0) { /* skip corners */
/* NORTH */
cogl_rectangle(max, 0,
width - max, border_width);
/* EAST */
cogl_rectangle(width - border_width, max,
width, height - max);
/* SOUTH */
cogl_rectangle(max, height - border_width,
width - max, height);
/* WEST */
cogl_rectangle(0, max,
border_width, height - max);
} else { /* include corners */
/* NORTH */
cogl_rectangle(0, 0,
width, border_width);
/* EAST */
cogl_rectangle(width - border_width, border_width,
width, height - border_width);
/* SOUTH */
cogl_rectangle(0, height - border_width,
width, height);
/* WEST */
cogl_rectangle(0, border_width,
border_width, height - border_width);
}
}
if (!rectangle->background_material)
rectangle->background_material = cogl_material_new ();
cogl_color_set_from_4ub(&tmp_color,
color->red,
color->green,
color->blue,
actor_opacity * color->alpha / 255);
cogl_color_premultiply (&tmp_color);
cogl_material_set_color(rectangle->background_material, &tmp_color);
cogl_set_source(rectangle->background_material);
if (radius > border_width) {
/* Once we've drawn the borders and corners, if the corners are bigger
* the the border width, the remaining area is shaped like
*
* ########
* ##########
* ##########
* ########
*
* We draw it in 3 pieces - first the top and bottom, then the main
* rectangle
*/
cogl_rectangle(radius, border_width,
width - radius, radius);
cogl_rectangle(radius, height - radius,
width - radius, height - border_width);
}
cogl_rectangle(border_width, max,
width - border_width, height - max);
out:
clutter_color_free(border_color);
clutter_color_free(color);
}
static void
big_rectangle_notify(GObject *object,
GParamSpec *pspec)
{
BigRectangle *rectangle;
rectangle = BIG_RECTANGLE(object);
if (g_str_equal(pspec->name, "border-width") ||
g_str_equal(pspec->name, "color") ||
g_str_equal(pspec->name, "border-color")) {
rectangle->corners_dirty = TRUE;
}
}
static void
big_rectangle_set_property(GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
BigRectangle *rectangle;
rectangle = BIG_RECTANGLE(object);
switch (prop_id) {
case PROP_CORNER_RADIUS:
rectangle->radius = g_value_get_uint(value);
rectangle->corners_dirty = TRUE;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
big_rectangle_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
BigRectangle *rectangle;
rectangle = BIG_RECTANGLE(object);
switch (prop_id) {
case PROP_CORNER_RADIUS:
g_value_set_uint(value, rectangle->radius);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
big_rectangle_dispose(GObject *object)
{
BigRectangle *rectangle;
rectangle = BIG_RECTANGLE(object);
if (rectangle->corner) {
corner_unref(rectangle->corner);
rectangle->corner = NULL;
}
if (rectangle->corner_material) {
cogl_handle_unref (rectangle->corner_material);
rectangle->corner_material = NULL;
}
if (rectangle->background_material) {
cogl_handle_unref (rectangle->background_material);
rectangle->background_material = NULL;
}
if (rectangle->border_material) {
cogl_handle_unref (rectangle->border_material);
rectangle->border_material = NULL;
}
if (G_OBJECT_CLASS(big_rectangle_parent_class)->dispose)
G_OBJECT_CLASS(big_rectangle_parent_class)->dispose(object);
}
static void
big_rectangle_class_init(BigRectangleClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->dispose = big_rectangle_dispose;
gobject_class->set_property = big_rectangle_set_property;
gobject_class->get_property = big_rectangle_get_property;
gobject_class->notify = big_rectangle_notify;
actor_class->paint = big_rectangle_paint;
g_object_class_install_property
(gobject_class,
PROP_CORNER_RADIUS,
g_param_spec_uint("corner-radius",
"Corner radius",
"Radius of the rectangle rounded corner",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
}
static void
big_rectangle_init(BigRectangle *rectangle)
{
}

View File

@ -1,42 +0,0 @@
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
Copyright (C) 2008 litl, LLC.
The libbigwidgets-lgpl is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The libbigwidgets-lgpl 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the libbigwidgets-lgpl; see the file COPYING.LIB.
If not, write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __BIG_RECTANGLE_H__
#define __BIG_RECTANGLE_H__
#include <glib-object.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define BIG_TYPE_RECTANGLE (big_rectangle_get_type ())
#define BIG_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BIG_TYPE_RECTANGLE, BigRectangle))
#define BIG_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BIG_TYPE_RECTANGLE, BigRectangleClass))
#define BIG_IS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BIG_TYPE_RECTANGLE))
#define BIG_IS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BIG_TYPE_RECTANGLE))
#define BIG_RECTANGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BIG_TYPE_RECTANGLE, BigRectangleClass))
typedef struct BigRectangle BigRectangle;
typedef struct BigRectangleClass BigRectangleClass;
GType big_rectangle_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __BIG_RECTANGLE_H__ */

View File

@ -1,791 +0,0 @@
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/* theme-image.c: Stretched image.
Copyright (C) 2005-2008 Red Hat, Inc.
Copyright (C) 2008 litl, LLC.
The libbigwidgets-lgpl is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The libbigwidgets-lgpl 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the libbigwidgets-lgpl; see the file COPYING.LIB.
If not, write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA.
*/
#include <glib.h>
#include <clutter/clutter.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <librsvg/rsvg.h>
#include <librsvg/rsvg-cairo.h>
#include "theme-image.h"
typedef enum {
BIG_THEME_IMAGE_UNSET,
BIG_THEME_IMAGE_SVG,
BIG_THEME_IMAGE_SURFACE
} BigThemeImageType;
struct BigThemeImage {
ClutterCairoTexture parent_instance;
guint border_top;
guint border_bottom;
guint border_left;
guint border_right;
BigThemeImageType type;
union {
RsvgHandle *svg_handle;
cairo_surface_t *surface;
} u;
guint render_idle;
guint needs_render : 1;
};
struct BigThemeImageClass {
ClutterCairoTextureClass parent_class;
};
G_DEFINE_TYPE(BigThemeImage, big_theme_image, CLUTTER_TYPE_CAIRO_TEXTURE)
enum
{
PROP_0,
PROP_BORDER_TOP,
PROP_BORDER_BOTTOM,
PROP_BORDER_LEFT,
PROP_BORDER_RIGHT,
PROP_FILENAME,
PROP_PIXBUF
};
static void
big_theme_image_render(BigThemeImage *image)
{
int source_width = 0;
int source_height = 0;
int source_x1 = 0, source_x2 = 0, source_y1 = 0, source_y2 = 0;
int dest_x1 = 0, dest_x2 = 0, dest_y1 = 0, dest_y2 = 0;
int i, j;
int dest_width;
int dest_height;
ClutterGeometry geometry;
cairo_t *cr;
image->needs_render = FALSE;
if (image->render_idle) {
g_source_remove(image->render_idle);
image->render_idle = 0;
}
/* To draw a theme image, we divide the source and destination into 9
* pieces and draw each piece separately. (Some pieces may not exist
* if we have 0-width borders, in which case they'll be skipped)
*
* i=0 i=1 i=2
* border_left border_right
* +------------+--------------------+--------------+
* j=0: border_top | | | |
* +------------+--------------------+--------------+
* j=1 | | | |
* +------------+--------------------+--------------+
* j=2: border_bottom | | | |
* +------------+--------------------+--------------+
*
*/
switch (image->type) {
case BIG_THEME_IMAGE_SURFACE:
if (!image->u.surface)
return;
source_width = cairo_image_surface_get_width(image->u.surface);
source_height = cairo_image_surface_get_height(image->u.surface);
break;
case BIG_THEME_IMAGE_SVG:
{
RsvgDimensionData dimensions;
if (!image->u.svg_handle)
return;
rsvg_handle_get_dimensions(image->u.svg_handle, &dimensions);
source_width = dimensions.width;
source_height = dimensions.height;
break;
}
default:
return;
}
clutter_actor_get_allocation_geometry(CLUTTER_ACTOR(image), &geometry);
dest_width = geometry.width;
dest_height = geometry.height;
cr = clutter_cairo_texture_create(CLUTTER_CAIRO_TEXTURE(image));
for (j = 0; j < 3; j++) {
switch (j) {
case 0:
source_y1 = 0;
source_y2 = image->border_top;
dest_y1 = 0;
dest_y2 = image->border_top;
break;
case 1:
source_y1 = image->border_top;
source_y2 = source_height - image->border_bottom;
dest_y1 = image->border_top;
dest_y2 = dest_height - image->border_bottom;
break;
case 2:
source_y1 = source_height - image->border_bottom;
source_y2 = source_height;
dest_y1 = dest_height - image->border_bottom;
dest_y2 = dest_height;
break;
}
if (dest_y2 <= dest_y1)
continue;
/* pixbuf-theme-engine has a nice interpretation of source_y2 == source_y1,
* dest_y2 != dest_y1, which is to linearly interpolate between the surrounding
* areas. We could do that for the surface case by setting
*
* source_y1 == y - 0.5
* source_y2 == y + 0.5
*
* but it's hard for the SVG case. source_y2 < source_y1 is pathological ... someone
* specified borders that sum up larger than the image.
*/
if (source_y2 <= source_y1)
continue;
for (i = 0; i < 3; i++) {
switch (i) {
case 0:
source_x1 = 0;
source_x2 = image->border_left;
dest_x1 = 0;
dest_x2 = image->border_left;
break;
case 1:
source_x1 = image->border_left;
source_x2 = source_width - image->border_right;
dest_x1 = image->border_left;
dest_x2 = dest_width - image->border_right;
break;
case 2:
source_x1 = source_width - image->border_right;
source_x2 = source_width;
dest_x1 = dest_width - image->border_right;
dest_x2 = dest_width;
break;
}
if (dest_x2 <= dest_x1)
continue;
if (source_x2 <= source_x1)
continue;
cairo_save(cr);
cairo_rectangle(cr, dest_x1, dest_y1, dest_x2 - dest_x1, dest_y2 - dest_y1);
cairo_clip(cr);
cairo_translate(cr, dest_x1, dest_y1);
cairo_scale(cr,
(double)(dest_x2 - dest_x1) / (source_x2 - source_x1),
(double)(dest_y2 - dest_y1) / (source_y2 - source_y1));
switch (image->type) {
case BIG_THEME_IMAGE_SURFACE:
cairo_set_source_surface(cr, image->u.surface, - source_x1, - source_y1);
cairo_paint(cr);
break;
case BIG_THEME_IMAGE_SVG:
cairo_translate(cr, - source_x1, - source_y1);
rsvg_handle_render_cairo(image->u.svg_handle, cr);
break;
default:
break;
}
cairo_restore(cr);
}
}
/* This will cause the surface content to be uploaded as
* new texture content */
cairo_destroy(cr);
}
static gboolean
big_theme_image_render_idle(gpointer data)
{
BigThemeImage *image;
image = data;
big_theme_image_render(image);
return FALSE;
}
static void
big_theme_image_queue_render(BigThemeImage *image)
{
image->needs_render = TRUE;
if (!image->render_idle)
image->render_idle = g_idle_add(big_theme_image_render_idle,
image);
}
static void
big_theme_image_paint(ClutterActor *actor)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(actor);
if (image->needs_render)
big_theme_image_render(image);
if (CLUTTER_ACTOR_CLASS(big_theme_image_parent_class)->paint)
CLUTTER_ACTOR_CLASS(big_theme_image_parent_class)->paint(actor);
}
static void
big_theme_image_allocate(ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
BigThemeImage *image;
guint old_width;
guint old_height;
guint width;
guint height;
image = BIG_THEME_IMAGE(actor);
width = ABS(box->x2 - box->x1);
height = ABS(box->y2 - box->y1);
g_object_get(actor,
"surface-width", &old_width,
"surface-height", &old_height,
NULL);
if (width != old_width || height != old_height) {
clutter_cairo_texture_set_surface_size(CLUTTER_CAIRO_TEXTURE(actor), width, height);
big_theme_image_queue_render(image);
}
if (CLUTTER_ACTOR_CLASS(big_theme_image_parent_class))
CLUTTER_ACTOR_CLASS(big_theme_image_parent_class)->allocate(actor,
box,
flags);
}
static void
big_theme_image_get_preferred_height(ClutterActor *actor,
float for_width,
float *min_height_p,
float *natural_height_p)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(actor);
if (min_height_p)
*min_height_p = 0;
if (!natural_height_p)
return;
*natural_height_p = 0;
switch (image->type) {
case BIG_THEME_IMAGE_SURFACE:
if (!image->u.surface)
break;
*natural_height_p = cairo_image_surface_get_height(image->u.surface);
break;
case BIG_THEME_IMAGE_SVG:
{
RsvgDimensionData dimensions;
if (!image->u.svg_handle)
return;
rsvg_handle_get_dimensions(image->u.svg_handle, &dimensions);
*natural_height_p = dimensions.height;
break;
}
default:
break;
}
}
static void
big_theme_image_get_preferred_width(ClutterActor *actor,
float for_height,
float *min_width_p,
float *natural_width_p)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(actor);
if (min_width_p)
*min_width_p = 0;
if (!natural_width_p)
return;
*natural_width_p = 0;
switch (image->type) {
case BIG_THEME_IMAGE_SURFACE:
if (!image->u.surface)
break;
*natural_width_p = cairo_image_surface_get_width(image->u.surface);
break;
case BIG_THEME_IMAGE_SVG:
{
RsvgDimensionData dimensions;
if (!image->u.svg_handle)
return;
rsvg_handle_get_dimensions(image->u.svg_handle, &dimensions);
*natural_width_p = dimensions.width;
break;
}
default:
break;
}
}
static void
big_theme_image_set_border_value(BigThemeImage *image, guint *old_value, const GValue *new_value)
{
guint border_value;
border_value = g_value_get_uint(new_value);
if (*old_value != border_value) {
*old_value = border_value;
big_theme_image_queue_render(image);
}
}
static void
big_theme_image_set_filename(BigThemeImage *image, const char *filename)
{
if (!filename)
return;
if (g_str_has_suffix(filename, ".png") ||
g_str_has_suffix(filename, ".PNG")) {
image->type = BIG_THEME_IMAGE_SURFACE;
image->u.surface = cairo_image_surface_create_from_png(filename);
if (image->u.surface == NULL) {
g_warning("Error when loading PNG from file %s", filename);
}
} else if (g_str_has_suffix(filename, ".svg") ||
g_str_has_suffix(filename, ".SVG")) {
GError *error;
error = NULL;
image->u.svg_handle = rsvg_handle_new_from_file(filename, &error);
if (image->u.svg_handle == NULL) {
g_warning("Error when loading SVG from file %s: %s", filename,
error?error->message:"Error not set by RSVG");
if (error)
g_error_free(error);
return;
}
image->type = BIG_THEME_IMAGE_SVG;
} else {
g_warning("%s: Unsupported file type", filename);
return;
}
big_theme_image_queue_render(image);
}
static cairo_surface_t *
create_surface_from_pixbuf(const GdkPixbuf *pixbuf)
{
gint width = gdk_pixbuf_get_width (pixbuf);
gint height = gdk_pixbuf_get_height (pixbuf);
guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
guchar *cairo_pixels;
cairo_format_t format;
cairo_surface_t *surface;
static const cairo_user_data_key_t key;
int j;
if (n_channels == 3)
format = CAIRO_FORMAT_RGB24;
else
format = CAIRO_FORMAT_ARGB32;
cairo_pixels = g_malloc (4 * width * height);
surface = cairo_image_surface_create_for_data((unsigned char *)cairo_pixels,
format,
width, height, 4 * width);
cairo_surface_set_user_data(surface, &key,
cairo_pixels, (cairo_destroy_func_t)g_free);
for (j = height; j; j--) {
guchar *p = gdk_pixels;
guchar *q = cairo_pixels;
if (n_channels == 3) {
guchar *end = p + 3 * width;
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
q[0] = p[2];
q[1] = p[1];
q[2] = p[0];
#else
q[1] = p[0];
q[2] = p[1];
q[3] = p[2];
#endif
p += 3;
q += 4;
}
} else {
guchar *end = p + 4 * width;
guint t1,t2,t3;
#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
MULT(q[0], p[2], p[3], t1);
MULT(q[1], p[1], p[3], t2);
MULT(q[2], p[0], p[3], t3);
q[3] = p[3];
#else
q[0] = p[3];
MULT(q[1], p[0], p[3], t1);
MULT(q[2], p[1], p[3], t2);
MULT(q[3], p[2], p[3], t3);
#endif
p += 4;
q += 4;
}
#undef MULT
}
gdk_pixels += gdk_rowstride;
cairo_pixels += 4 * width;
}
return surface;
}
static void
big_theme_image_set_pixbuf(BigThemeImage *image, GdkPixbuf *pixbuf)
{
if (!pixbuf)
return;
image->type = BIG_THEME_IMAGE_SURFACE;
image->u.surface = create_surface_from_pixbuf(pixbuf);
g_assert(image->u.surface != NULL);
big_theme_image_queue_render(image);
}
static void
big_theme_image_set_property(GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(object);
switch (prop_id) {
case PROP_BORDER_TOP:
big_theme_image_set_border_value(image, &image->border_top, value);
break;
case PROP_BORDER_BOTTOM:
big_theme_image_set_border_value(image, &image->border_bottom, value);
break;
case PROP_BORDER_LEFT:
big_theme_image_set_border_value(image, &image->border_left, value);
break;
case PROP_BORDER_RIGHT:
big_theme_image_set_border_value(image, &image->border_right, value);
break;
case PROP_FILENAME:
big_theme_image_set_filename(image, g_value_get_string(value));
break;
case PROP_PIXBUF:
big_theme_image_set_pixbuf(image, g_value_get_object(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
big_theme_image_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(object);
switch (prop_id) {
case PROP_BORDER_TOP:
g_value_set_uint(value, image->border_top);
break;
case PROP_BORDER_BOTTOM:
g_value_set_uint(value, image->border_bottom);
break;
case PROP_BORDER_LEFT:
g_value_set_uint(value, image->border_left);
break;
case PROP_BORDER_RIGHT:
g_value_set_uint(value, image->border_right);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
big_theme_image_dispose(GObject *object)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(object);
if (image->render_idle) {
g_source_remove(image->render_idle);
image->render_idle = 0;
}
switch (image->type) {
case BIG_THEME_IMAGE_SVG:
if (image->u.svg_handle) {
g_object_unref(image->u.svg_handle);
image->u.svg_handle = NULL;
}
break;
case BIG_THEME_IMAGE_SURFACE:
if (image->u.surface) {
cairo_surface_destroy(image->u.surface);
image->u.surface = NULL;
}
break;
default:
break;
}
if (G_OBJECT_CLASS(big_theme_image_parent_class)->dispose)
G_OBJECT_CLASS(big_theme_image_parent_class)->dispose(object);
}
static void
big_theme_image_class_init(BigThemeImageClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->dispose = big_theme_image_dispose;
gobject_class->set_property = big_theme_image_set_property;
gobject_class->get_property = big_theme_image_get_property;
actor_class->allocate = big_theme_image_allocate;
actor_class->get_preferred_width = big_theme_image_get_preferred_width;
actor_class->get_preferred_height = big_theme_image_get_preferred_height;
actor_class->paint = big_theme_image_paint;
g_object_class_install_property
(gobject_class,
PROP_BORDER_TOP,
g_param_spec_uint("border-top",
"Border top",
"Top dimension of the image border "
"(none-scaled part)",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_BORDER_BOTTOM,
g_param_spec_uint("border-bottom",
"Border bottom",
"Bottom dimension of the image border "
"(none-scaled part)",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_BORDER_LEFT,
g_param_spec_uint("border-left",
"Border left",
"Left dimension of the image border "
"(none-scaled part)",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_BORDER_RIGHT,
g_param_spec_uint("border-right",
"Border right",
"Right dimension of the image border "
"(none-scaled part)",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_FILENAME,
g_param_spec_string("filename",
"Filename",
"Name of the file",
NULL,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_PIXBUF,
g_param_spec_object("pixbuf",
"Pixbuf",
"Pixbuf of the image",
GDK_TYPE_PIXBUF,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
}
static void
big_theme_image_init(BigThemeImage *image)
{
}
ClutterActor *
big_theme_image_new_from_file(const char *filename,
guint border_top,
guint border_bottom,
guint border_left,
guint border_right)
{
ClutterActor *actor;
actor = g_object_new(BIG_TYPE_THEME_IMAGE,
/* FIXME ClutterCairo requires creating a bogus
* surface with nonzero size
*/
"surface-width", 1,
"surface-height", 1,
"filename", filename,
"border-top", border_top,
"border-bottom", border_bottom,
"border-left", border_left,
"border-right", border_right,
NULL);
return actor;
}
ClutterActor *
big_theme_image_new_from_pixbuf(GdkPixbuf *pixbuf,
guint border_top,
guint border_bottom,
guint border_left,
guint border_right)
{
ClutterActor *actor;
actor = g_object_new(BIG_TYPE_THEME_IMAGE,
/* FIXME ClutterCairo requires creating a bogus
* surface with nonzero size
*/
"surface-width", 1,
"surface-height", 1,
"pixbuf", pixbuf,
"border-top", border_top,
"border-bottom", border_bottom,
"border-left", border_left,
"border-right", border_right,
NULL);
return actor;
}

View File

@ -1,39 +0,0 @@
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/* Copyright 2008 litl, LLC. All Rights Reserved. */
#ifndef __BIG_THEME_IMAGE_H__
#define __BIG_THEME_IMAGE_H__
#include <glib-object.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define BIG_TYPE_THEME_IMAGE (big_theme_image_get_type ())
#define BIG_THEME_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BIG_TYPE_THEME_IMAGE, BigThemeImage))
#define BIG_THEME_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BIG_TYPE_THEME_IMAGE, BigThemeImageClass))
#define BIG_IS_THEME_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BIG_TYPE_THEME_IMAGE))
#define BIG_IS_THEME_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BIG_TYPE_THEME_IMAGE))
#define BIG_THEME_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BIG_TYPE_THEME_IMAGE, BigThemeImageClass))
typedef struct BigThemeImage BigThemeImage;
typedef struct BigThemeImageClass BigThemeImageClass;
GType big_theme_image_get_type (void) G_GNUC_CONST;
ClutterActor * big_theme_image_new_from_file (const gchar *filename,
guint border_top,
guint border_bottom,
guint border_left,
guint border_right);
ClutterActor * big_theme_image_new_from_pixbuf (GdkPixbuf *pixbuf,
guint border_top,
guint border_bottom,
guint border_left,
guint border_right);
G_END_DECLS
#endif /* __BIG_THEME_IMAGE_H__ */

View File

@ -0,0 +1,18 @@
#!/bin/sh
if [ -f "$0.in" ]
then
scriptDir="`dirname $0`"
uiDir="$scriptDir/../data"
jsDir="$scriptDir/../js"
else
uiDir="@pkgdatadir@"
jsDir="@pkgdatadir@/js"
fi
progName="`basename $0`"
uiFile="$uiDir/clock-preferences.ui"
export GJS_PATH="$jsDir"
@GJS_CONSOLE@ -c "const ClockPreferences = imports.prefs.clockPreferences;
ClockPreferences.main({ progName: '$progName', uiFile: '$uiFile' });"

View File

@ -32,23 +32,27 @@
#include <clutter/clutter.h>
#include <clutter/x11/clutter-x11.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gjs/gjs.h>
#include <girepository.h>
#include <gmodule.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include "display.h"
#include "shell-global-private.h"
#include "shell-perf-log.h"
#include "shell-wm.h"
#include "st.h"
static void gnome_shell_plugin_constructed (GObject *object);
static void gnome_shell_plugin_dispose (GObject *object);
static void gnome_shell_plugin_finalize (GObject *object);
static void gnome_shell_plugin_start (MutterPlugin *plugin);
static void gnome_shell_plugin_minimize (MutterPlugin *plugin,
MutterWindow *actor);
static void gnome_shell_plugin_maximize (MutterPlugin *plugin,
@ -118,10 +122,10 @@ gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
MutterPluginClass *plugin_class = MUTTER_PLUGIN_CLASS (klass);
gobject_class->constructed = gnome_shell_plugin_constructed;
gobject_class->dispose = gnome_shell_plugin_dispose;
gobject_class->finalize = gnome_shell_plugin_finalize;
plugin_class->start = gnome_shell_plugin_start;
plugin_class->map = gnome_shell_plugin_map;
plugin_class->minimize = gnome_shell_plugin_minimize;
plugin_class->maximize = gnome_shell_plugin_maximize;
@ -138,25 +142,23 @@ gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
static void
gnome_shell_plugin_init (GnomeShellPlugin *shell_plugin)
{
_shell_global_set_plugin (shell_global_get(), MUTTER_PLUGIN(shell_plugin));
meta_prefs_override_preference_location ("/apps/metacity/general/button_layout",
"/desktop/gnome/shell/windows/button_layout");
}
static void
gnome_shell_plugin_constructed (GObject *object)
update_font_options (GtkSettings *settings)
{
MutterPlugin *plugin = MUTTER_PLUGIN (object);
GnomeShellPlugin *shell_plugin = GNOME_SHELL_PLUGIN (object);
MetaScreen *screen;
MetaDisplay *display;
GError *error = NULL;
int status;
const char *shell_js;
char **search_path;
StThemeContext *context;
ClutterStage *stage;
ClutterBackend *backend;
cairo_font_options_t *font_options;
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
gint dpi;
gint hinting;
gchar *hint_style_str;
cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_NONE;
gint antialias;
cairo_antialias_t antialias_mode = CAIRO_ANTIALIAS_NONE;
cairo_font_options_t *options;
/* Disable text mipmapping; it causes problems on pre-GEM Intel
* drivers and we should just be rendering text at the right
@ -165,21 +167,145 @@ gnome_shell_plugin_constructed (GObject *object)
*/
clutter_set_font_flags (clutter_get_font_flags () & ~CLUTTER_FONT_MIPMAPPING);
g_object_get (settings,
"gtk-xft-dpi", &dpi,
"gtk-xft-antialias", &antialias,
"gtk-xft-hinting", &hinting,
"gtk-xft-hintstyle", &hint_style_str,
NULL);
stage = CLUTTER_STAGE (clutter_stage_get_default ());
context = st_theme_context_get_for_stage (stage);
if (dpi != -1)
/* GTK stores resolution as 1024 * dots/inch */
st_theme_context_set_resolution (context, dpi / 1024);
else
st_theme_context_set_default_resolution (context);
/* Clutter (as of 0.9) passes comprehensively wrong font options
* override whatever set_font_flags() did above.
*
* http://bugzilla.openedhand.com/show_bug.cgi?id=1456
*/
backend = clutter_get_default_backend ();
font_options = cairo_font_options_create ();
/* Default options for everything is reasonable; except that
* we want to turn off subpixel anti-aliasing; since Clutter
options = cairo_font_options_create ();
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
if (hinting >= 0 && !hinting)
{
hint_style = CAIRO_HINT_STYLE_NONE;
}
else if (hint_style_str)
{
if (strcmp (hint_style_str, "hintnone") == 0)
hint_style = CAIRO_HINT_STYLE_NONE;
else if (strcmp (hint_style_str, "hintslight") == 0)
hint_style = CAIRO_HINT_STYLE_SLIGHT;
else if (strcmp (hint_style_str, "hintmedium") == 0)
hint_style = CAIRO_HINT_STYLE_MEDIUM;
else if (strcmp (hint_style_str, "hintfull") == 0)
hint_style = CAIRO_HINT_STYLE_FULL;
}
g_free (hint_style_str);
cairo_font_options_set_hint_style (options, hint_style);
/* We don't want to turn on subpixel anti-aliasing; since Clutter
* doesn't currently have the code to support ARGB masks,
* generating them then squashing them back to A8 is pointless.
*/
cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
clutter_backend_set_font_options (backend, font_options);
cairo_font_options_destroy (font_options);
antialias_mode = (antialias < 0 || antialias) ? CAIRO_ANTIALIAS_GRAY
: CAIRO_ANTIALIAS_NONE;
cairo_font_options_set_antialias (options, antialias_mode);
clutter_backend_set_font_options (backend, options);
cairo_font_options_destroy (options);
}
static void
settings_notify_cb (GtkSettings *settings,
GParamSpec *pspec,
gpointer data)
{
update_font_options (settings);
}
static void
malloc_statistics_callback (ShellPerfLog *perf_log,
gpointer data)
{
struct mallinfo info = mallinfo ();
shell_perf_log_update_statistic_i (perf_log,
"malloc.arenaSize",
info.arena);
shell_perf_log_update_statistic_i (perf_log,
"malloc.mmapSize",
info.hblkhd);
shell_perf_log_update_statistic_i (perf_log,
"malloc.usedSize",
info.uordblks);
}
static void
add_statistics (GnomeShellPlugin *shell_plugin)
{
ShellPerfLog *perf_log = shell_perf_log_get_default ();
/* For probably historical reasons, mallinfo() defines the returned values,
* even those in bytes as int, not size_t. We're determined not to use
* more than 2G of malloc'ed memory, so are OK with that.
*/
shell_perf_log_define_statistic (perf_log,
"malloc.arenaSize",
"Amount of memory allocated by malloc() with brk(), in bytes",
"i");
shell_perf_log_define_statistic (perf_log,
"malloc.mmapSize",
"Amount of memory allocated by malloc() with mmap(), in bytes",
"i");
shell_perf_log_define_statistic (perf_log,
"malloc.usedSize",
"Amount of malloc'ed memory currently in use",
"i");
shell_perf_log_add_statistics_callback (perf_log,
malloc_statistics_callback,
NULL, NULL);
}
static void
gnome_shell_plugin_start (MutterPlugin *plugin)
{
GnomeShellPlugin *shell_plugin = GNOME_SHELL_PLUGIN (plugin);
MetaScreen *screen;
MetaDisplay *display;
GtkSettings *settings;
GError *error = NULL;
int status;
const char *shell_js;
char **search_path;
ShellGlobal *global;
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
settings = gtk_settings_get_default ();
g_object_connect (settings,
"signal::notify::gtk-xft-dpi",
G_CALLBACK (settings_notify_cb), NULL,
"signal::notify::gtk-xft-antialias",
G_CALLBACK (settings_notify_cb), NULL,
"signal::notify::gtk-xft-hinting",
G_CALLBACK (settings_notify_cb), NULL,
"signal::notify::gtk-xft-hintstyle",
G_CALLBACK (settings_notify_cb), NULL,
NULL);
update_font_options (settings);
screen = mutter_plugin_get_screen (plugin);
display = meta_screen_get_display (screen);
@ -194,7 +320,13 @@ gnome_shell_plugin_constructed (GObject *object)
shell_plugin->gjs_context = gjs_context_new_with_search_path(search_path);
g_strfreev(search_path);
_shell_global_set_gjs_context (shell_global_get (), shell_plugin->gjs_context);
/* Initialize the global object here. */
global = shell_global_get ();
_shell_global_set_plugin (global, MUTTER_PLUGIN(shell_plugin));
_shell_global_set_gjs_context (global, shell_plugin->gjs_context);
add_statistics (shell_plugin);
if (!gjs_context_eval (shell_plugin->gjs_context,
"const Main = imports.ui.main; Main.start();",

View File

@ -1,6 +1,15 @@
#!@PYTHON@
# -*- mode: Python; indent-tabs-mode: nil; -*-
import atexit
import datetime
try:
import json
except ImportError:
try:
import simplejson as json
except ImportError:
json = None
import optparse
import os
import random
@ -37,10 +46,15 @@ def get_running_session_environs():
if not stat.st_uid == myuid:
continue
try:
exe = os.readlink(piddir + '/exe')
except OSError, e:
f = open(piddir + "/cmdline")
command = f.read()
f.close()
except IOError, e:
continue
if os.path.basename(exe) != 'gnome-session':
# /proc/cmdline is separated and terminated by NULs
command = command.split("\x00")[0]
command = os.path.basename(command)
if command != 'gnome-session':
continue
try:
f = open(os.path.join(piddir, 'environ'))
@ -124,7 +138,7 @@ def _get_glx_extensions():
return (server_glx_extensions, client_glx_extensions, glx_extensions)
def start_shell():
def start_shell(perf_output=None):
bin_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
if os.path.exists(os.path.join(bin_dir, 'gnome-shell.in')):
running_from_source_tree = True
@ -192,6 +206,12 @@ def start_shell():
# need to force indirect rendering for NVIDIA.
env['LIBGL_ALWAYS_INDIRECT'] = '1'
if options.perf is not None:
env['SHELL_PERF_MODULE'] = options.perf
if perf_output is not None:
env['SHELL_PERF_OUTPUT'] = perf_output
if options.debug:
debug_command = options.debug_command.split()
args = list(debug_command)
@ -205,6 +225,258 @@ def start_shell():
args.append('--sync')
return subprocess.Popen(args, env=env)
def run_shell(perf_output=None):
if options.debug:
# Record initial terminal state so we can reset it to that
# later, in case we kill gdb at a bad time
termattrs = termios.tcgetattr(0);
normal_exit = False
if options.verbose:
print "Starting shell"
try:
shell = None
if options.xephyr:
xephyr = start_xephyr()
# This makes us not grab the org.gnome.Panel or
# org.freedesktop.Notifications D-Bus names
os.environ['GNOME_SHELL_NO_REPLACE'] = '1'
shell = start_shell()
else:
xephyr = None
shell = start_shell(perf_output=perf_output)
# Wait for shell to exit
if options.verbose:
print "Waiting for shell to exit"
shell.wait()
except KeyboardInterrupt, e:
try:
os.kill(shell.pid, signal.SIGKILL)
except:
pass
shell.wait()
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);
return normal_exit
def upload_performance_report(report_text):
# Local imports to avoid impacting gnome-shell startup time
import base64
from ConfigParser import RawConfigParser
import hashlib
import hmac
import httplib
import urlparse
import urllib
try:
config_home = os.environ['XDG_CONFIG_HOME']
except KeyError:
config_home = None
if not config_home:
config_home = os.path.expanduser("~/.config")
config_file = os.path.join(config_home, "gnome-shell/perf.ini")
try:
config = RawConfigParser()
f = open(config_file)
config.readfp(f)
f.close()
base_url = config.get('upload', 'url')
system_name = config.get('upload', 'name')
secret_key = config.get('upload', 'key')
except Exception, e:
print "Can't read upload configuration from %s: %s" % (config_file, str(e))
sys.exit(1)
# Determine host, port and upload URL from provided data, we're
# a bit extra-careful about normalization since the URL is part
# of the signature.
split = urlparse.urlsplit(base_url)
scheme = split[0].lower()
netloc = split[1]
base_path = split[2]
m = re.match(r'^(.*?)(?::(\d+))?$', netloc)
if m.group(2):
host, port = m.group(1), int(m.group(2))
else:
host, port = m.group(1), None
if scheme != "http":
print "'%s' is not a HTTP URL" % base_url
sys.exit(1)
if port is None:
port = 80
if base_path.endswith('/'):
base_path = base_path[:-1]
if port == 80:
normalized_base = "%s://%s%s" % (scheme, host, base_path)
else:
normalized_base = "%s://%s:%d%s" % (scheme, host, port, base_path)
upload_url = normalized_base + '/system/%s/upload' % system_name
upload_path = urlparse.urlsplit(upload_url)[2] # path portion
# Create signature based on upload URL and the report data
signature_data = 'POST&' + upload_url + "&&"
h = hmac.new(secret_key, digestmod=hashlib.sha1)
h.update(signature_data)
h.update(report_text)
signature = urllib.quote(base64.b64encode(h.digest()), "~")
headers = {
'User-Agent': 'gnome-shell',
'Content-Type': 'application/json',
'X-Shell-Signature': 'HMAC-SHA1 ' + signature
};
connection = httplib.HTTPConnection(host, port)
connection.request('POST', upload_path, report_text, headers)
response = connection.getresponse()
if response.status == 200:
print "Performance report upload succeeded"
else:
print "Performance report upload failed with status %d" % response.status
print response.read()
def run_performance_test():
iters = options.perf_iters
if options.perf_warmup:
iters += 1
logs = []
metric_summaries = {}
for i in xrange(0, iters):
# We create an empty temporary file that the shell will overwrite
# with the contents.
handle, output_file = tempfile.mkstemp(".json", "gnome-shell-perf.")
os.close(handle)
# Run the performance test and collect the output as JSON
normal_exit = False
try:
normal_exit = run_shell(perf_output=output_file)
finally:
if not normal_exit:
os.remove(output_file)
if not normal_exit:
return False
try:
f = open(output_file)
output = json.load(f)
f.close()
finally:
os.remove(output_file)
# Grab the event definitions and monitor layout the first time around
if i == 0:
events = output['events']
monitors = output['monitors']
if options.perf_warmup and i == 0:
continue
for metric in output['metrics']:
name = metric['name']
if not name in metric_summaries:
summary = {}
summary['description'] = metric['description']
summary['units'] = metric['units']
summary['values'] = []
metric_summaries[name] = summary
else:
summary = metric_summaries[name]
summary['values'].append(metric['value'])
logs.append(output['log'])
if options.perf_output or options.perf_upload:
# Write a complete report, formatted as JSON. The Javascript/C code that
# generates the individual reports we are summarizing here is very careful
# to format them nicely, but we just dump out a compressed no-whitespace
# version here for simplicity. Using json.dump(indent=0) doesn't real
# improve the readability of the output much.
report = {
'date': datetime.datetime.now().isoformat(),
'events': events,
'monitors': monitors,
'metrics': metric_summaries,
'logs': logs
}
# Add the Git revision if available
bin_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
if os.path.exists(os.path.join(bin_dir, 'gnome-shell.in')):
top_dir = os.path.dirname(bin_dir)
git_dir = os.path.join(top_dir, '.git')
if os.path.exists(git_dir):
env = dict(os.environ)
env['GIT_DIR'] = git_dir
revision = subprocess.Popen(['git', 'rev-parse', 'HEAD'],
env=env,
stdout=subprocess.PIPE).communicate()[0].strip()
report['revision'] = revision
if options.perf_output:
f = open(options.perf_output, 'w')
json.dump(report, f)
f.close()
if options.perf_upload:
upload_performance_report(json.dumps(report))
else:
# Write a human readable summary
print '------------------------------------------------------------';
for metric in sorted(metric_summaries.keys()):
summary = metric_summaries[metric]
print "#", summary['description']
print metric, ", ".join((str(x) for x in summary['values']))
print '------------------------------------------------------------';
return True
def restore_gnome():
# Do imports lazily to save time and memory
import gio
@ -251,6 +523,17 @@ 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("", "--perf", metavar="PERF_MODULE",
help="Specify the name of a performance module to run")
parser.add_option("", "--perf-iters", type="int", metavar="ITERS",
help="Numbers of iterations of performance module to run",
default=1)
parser.add_option("", "--perf-warmup", action="store_true",
help="Run a dry run before performance tests")
parser.add_option("", "--perf-output", metavar="OUTPUT_FILE",
help="Output file to write performance report")
parser.add_option("", "--perf-upload", action="store_true",
help="Upload performance report to server")
parser.add_option("", "--xephyr", action="store_true",
help="Run a debugging instance inside Xephyr")
parser.add_option("", "--geometry", metavar="GEOMETRY",
@ -271,9 +554,15 @@ if args:
parser.print_usage()
sys.exit(1)
if options.create_extension:
import json
if options.create_extension and json is None:
print 'The Python simplejson module is required to create a new GNOME Shell extension'
sys.exit(1)
if options.perf and json is None:
print 'The Python simplejson module is required for performance tests'
sys.exit(1)
if options.create_extension:
print
print '''Name should be a very short (ideally descriptive) string.
Examples are: "Click To Focus", "Adblock", "Shell Window Shrinker".
@ -301,7 +590,7 @@ use an extension title clicktofocus@janedoe.example.com.'''
if uuid == '':
uuid = sample_uuid
extension_path = os.path.join(os.path.expanduser('~/.config'), 'gnome-shell', 'extensions', uuid)
extension_path = os.path.join(os.path.expanduser('~/.local'), 'share', 'gnome-shell', 'extensions', uuid)
if os.path.exists(extension_path):
print "Extension path %r already exists" % (extension_path, )
sys.exit(0)
@ -356,6 +645,11 @@ function main() {
subprocess.Popen(['gnome-open', extensionjs_path])
sys.exit(0)
# Handle ssh logins
if 'DISPLAY' not in os.environ:
running_env = get_running_session_environs()
os.environ.update(running_env)
if options.eval_file:
import dbus
@ -390,73 +684,16 @@ else:
# tfp does not work correctly in Xephyr
use_tfp = not options.xephyr
if options.verbose:
print "Starting shell"
# Handle ssh logins
if 'DISPLAY' not in os.environ:
running_env = get_running_session_environs()
os.environ.update(running_env)
if options.debug:
# Record initial terminal state so we can reset it to that
# 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:
shell = None
if options.xephyr:
xephyr = start_xephyr()
# This makes us not grab the org.gnome.Panel or
# org.freedesktop.Notifications D-Bus names
os.environ['GNOME_SHELL_NO_REPLACE'] = '1'
shell = start_shell()
if options.perf:
normal_exit = run_performance_test()
else:
xephyr = None
shell = start_shell()
# Wait for shell to exit
if options.verbose:
print "Waiting for shell to exit"
shell.wait()
except KeyboardInterrupt, e:
try:
os.kill(shell.pid, signal.SIGKILL)
except:
pass
shell.wait()
normal_exit = run_shell()
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 options.xephyr and options.replace and not normal_exit:
if not options.xephyr and options.replace and (options.perf or not normal_exit):
restore_gnome()

19
src/gtk-compat.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef __GTK_COMPAT_H__
#define __GTK_COMPAT_H__
#include <gtk/gtk.h>
/* Provide a compatibility layer for accessor functions introduced
* in GTK+ 2.20 which we need to build with GSEAL_ENABLE.
* That way it is still possible to build with GTK+ 2.18 when not
* using GSEAL_ENABLE
*/
#if !GTK_CHECK_VERSION(2, 20, 0)
#define gtk_widget_get_realized(w) GTK_WIDGET_REALIZED (w)
#define gtk_widget_get_mapped(w) GTK_WIDGET_MAPPED (w)
#endif /* GTK_CHECK_VERSION(2, 20, 0) */
#endif /* __GTK_COMPAT_H__ */

View File

@ -13,6 +13,8 @@ ShellApp* _shell_app_new_for_window (MetaWindow *window);
ShellApp* _shell_app_new (ShellAppInfo *appinfo);
void _shell_app_set_starting (ShellApp *app, gboolean starting);
void _shell_app_add_window (ShellApp *app, MetaWindow *window);
void _shell_app_remove_window (ShellApp *app, MetaWindow *window);

View File

@ -27,7 +27,8 @@
*/
static const char*const known_vendor_prefixes[] = { "gnome",
"fedora",
"mozilla" };
"mozilla",
NULL };
enum {
PROP_0,
@ -308,9 +309,15 @@ reread_entries (ShellAppSystem *self,
g_slist_free (*cache);
*cache = NULL;
*cache = gather_entries_recurse (self, *cache, unique, trunk);
gmenu_tree_item_unref (trunk);
if (!trunk)
{
*cache = NULL;
}
else
{
*cache = gather_entries_recurse (self, *cache, unique, trunk);
gmenu_tree_item_unref (trunk);
}
}
static void
@ -484,6 +491,49 @@ shell_app_system_get_app (ShellAppSystem *self,
return app;
}
/**
* shell_app_system_get_app_for_path:
* @system: a #ShellAppSystem
* @desktop_path: (utf8): UTF-8 encoded absolute file name
*
* Find or create a #ShellApp corresponding to a given absolute
* file name which must be in the standard paths (XDG_DATA_DIRS).
* For files outside the datadirs, this function returns %NULL.
*
* If already cached elsewhere in memory, return that instance.
* Otherwise, create a new one.
*
* Return value: (transfer full): The #ShellApp for id, or %NULL if none
*/
ShellApp *
shell_app_system_get_app_for_path (ShellAppSystem *system,
const char *desktop_path)
{
const char *basename;
ShellAppInfo *info;
basename = g_strrstr (desktop_path, "/");
if (basename)
basename += 1;
else
basename = desktop_path;
info = g_hash_table_lookup (system->priv->app_id_to_info, basename);
if (!info)
return NULL;
if (info->type == SHELL_APP_INFO_TYPE_ENTRY)
{
const char *full_path = gmenu_tree_entry_get_desktop_file_path ((GMenuTreeEntry*) info->entry);
if (strcmp (desktop_path, full_path) != 0)
return NULL;
}
else
return NULL;
return shell_app_system_get_app (system, basename);
}
/**
* shell_app_system_get_app_for_window:
* @self: A #ShellAppSystem
@ -1181,10 +1231,16 @@ shell_app_info_launch_full (ShellAppInfo *info,
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);
else if (info->type == SHELL_APP_INFO_TYPE_ENTRY)
{
gapp = g_desktop_app_info_new (shell_app_info_get_id (info));
}
else
{
filename = shell_app_info_get_desktop_file_path (info);
gapp = g_desktop_app_info_new_from_filename (filename);
g_free (filename);
}
if (!gapp)
{
@ -1199,11 +1255,6 @@ shell_app_info_launch_full (ShellAppInfo *info,
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);

View File

@ -70,6 +70,7 @@ gboolean shell_app_info_launch (ShellAppInfo *info,
ShellAppInfo *shell_app_system_load_from_desktop_file (ShellAppSystem *system, const char *filename, GError **error);
ShellApp *shell_app_system_get_app (ShellAppSystem *system, const char *id);
ShellApp *shell_app_system_get_app_for_path (ShellAppSystem *system, const char *desktop_path);
ShellApp *shell_app_system_get_app_for_window (ShellAppSystem *self, MetaWindow *window);
void _shell_app_system_register_app (ShellAppSystem *self, ShellApp *app);

View File

@ -381,7 +381,7 @@ on_session_status_changed (DBusGProxy *proxy,
static void
shell_app_usage_init (ShellAppUsage *self)
{
char *shell_config_dir, *path;
char *shell_userdata_dir, *path;
DBusGConnection *session_bus;
ShellWindowTracker *tracker;
@ -404,9 +404,9 @@ shell_app_usage_init (ShellAppUsage *self)
self->currently_idle = FALSE;
self->enable_monitoring = FALSE;
g_object_get (shell_global_get(), "configdir", &shell_config_dir, NULL),
path = g_build_filename (shell_config_dir, DATA_FILENAME, NULL);
g_free (shell_config_dir);
g_object_get (shell_global_get(), "userdatadir", &shell_userdata_dir, NULL),
path = g_build_filename (shell_userdata_dir, DATA_FILENAME, NULL);
g_free (shell_userdata_dir);
self->configfile = g_file_new_for_path (path);
g_free (path);
restore_from_file (self);

View File

@ -2,9 +2,13 @@
#include "config.h"
#include "st.h"
#include "shell-app-private.h"
#include "shell-global.h"
#include "shell-enum-types.h"
#include "display.h"
#include "st.h"
#include "shell-window-tracker.h"
#include <string.h>
@ -21,15 +25,23 @@ struct _ShellApp
ShellAppInfo *info;
guint32 last_user_time;
guint workspace_switch_id;
gboolean window_sort_stale;
GSList *windows;
ShellAppState state;
gboolean window_sort_stale : 1;
};
G_DEFINE_TYPE (ShellApp, shell_app, G_TYPE_OBJECT);
enum {
PROP_0,
PROP_STATE
};
enum {
WINDOWS_CHANGED,
LAST_SIGNAL
@ -37,6 +49,25 @@ enum {
static guint shell_app_signals[LAST_SIGNAL] = { 0 };
static void
shell_app_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ShellApp *app = SHELL_APP (gobject);
switch (prop_id)
{
case PROP_STATE:
g_value_set_enum (value, app->state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
const char *
shell_app_get_id (ShellApp *app)
{
@ -219,11 +250,201 @@ shell_app_is_transient (ShellApp *app)
return shell_app_info_is_transient (app->info);
}
gboolean
shell_app_launch (ShellApp *self,
GError **error)
typedef struct {
MetaWorkspace *workspace;
GSList **transients;
} CollectTransientsData;
static gboolean
collect_transients_on_workspace (MetaWindow *window,
gpointer datap)
{
return shell_app_info_launch (self->info, error);
CollectTransientsData *data = datap;
if (data->workspace && meta_window_get_workspace (window) != data->workspace)
return TRUE;
*data->transients = g_slist_prepend (*data->transients, window);
return TRUE;
}
/* The basic idea here is that when we're targeting a window,
* if it has transients we want to pick the most recent one
* the user interacted with.
* This function makes raising GEdit with the file chooser
* open work correctly.
*/
static MetaWindow *
find_most_recent_transient_on_same_workspace (MetaDisplay *display,
MetaWindow *reference)
{
GSList *transients, *transients_sorted, *iter;
MetaWindow *result;
CollectTransientsData data;
transients = NULL;
data.workspace = meta_window_get_workspace (reference);
data.transients = &transients;
meta_window_foreach_transient (reference, collect_transients_on_workspace, &data);
transients_sorted = meta_display_sort_windows_by_stacking (display, transients);
/* Reverse this so we're top-to-bottom (yes, we should probably change the order
* returned from the sort_windows_by_stacking function)
*/
transients_sorted = g_slist_reverse (transients_sorted);
g_slist_free (transients);
transients = NULL;
result = NULL;
for (iter = transients_sorted; iter; iter = iter->next)
{
MetaWindow *window = iter->data;
MetaWindowType wintype = meta_window_get_window_type (window);
/* Don't want to focus UTILITY types, like the Gimp toolbars */
if (wintype == META_WINDOW_NORMAL ||
wintype == META_WINDOW_DIALOG)
{
result = window;
break;
}
}
g_slist_free (transients_sorted);
return result;
}
/**
* shell_app_activate_window:
* @app: a #ShellApp
* @window: (allow-none): Window to be focused
* @timestamp: Event timestamp
*
* Bring all windows for the given app to the foreground,
* but ensure that @window is on top. If @window is %NULL,
* the window with the most recent user time for the app
* will be used.
*
* This function has no effect if @app is not currently running.
*/
void
shell_app_activate_window (ShellApp *app,
MetaWindow *window,
guint32 timestamp)
{
GSList *windows;
if (shell_app_get_state (app) != SHELL_APP_STATE_RUNNING)
return;
windows = shell_app_get_windows (app);
if (window == NULL && windows)
window = windows->data;
if (!g_slist_find (windows, window))
return;
else
{
GSList *iter;
ShellGlobal *global = shell_global_get ();
MetaScreen *screen = shell_global_get_screen (global);
MetaDisplay *display = meta_screen_get_display (screen);
MetaWorkspace *active = meta_screen_get_active_workspace (screen);
MetaWorkspace *workspace = meta_window_get_workspace (window);
guint32 last_user_timestamp = meta_display_get_last_user_time (display);
MetaWindow *most_recent_transient;
if (meta_display_xserver_time_is_before (display, timestamp, last_user_timestamp))
{
meta_window_set_demands_attention (window);
return;
}
/* Now raise all the other windows for the app that are on
* the same workspace, in reverse order to preserve the stacking.
*/
for (iter = windows; iter; iter = iter->next)
{
MetaWindow *other_window = iter->data;
if (other_window != window)
meta_window_raise (other_window);
}
/* If we have a transient that the user's interacted with more recently than
* the window, pick that.
*/
most_recent_transient = find_most_recent_transient_on_same_workspace (display, window);
if (most_recent_transient
&& meta_display_xserver_time_is_before (display,
meta_window_get_user_time (window),
meta_window_get_user_time (most_recent_transient)))
window = most_recent_transient;
if (active != workspace)
meta_workspace_activate_with_focus (workspace, window, timestamp);
else
meta_window_activate (window, timestamp);
}
}
/**
* shell_app_activate:
* @app: a #ShellApp
*
* Perform an appropriate default action for operating on this application,
* dependent on its current state. For example, if the application is not
* currently running, launch it. If it is running, activate the most
* recently used NORMAL window (or if that window has a transient, the most
* recently used transient for that window).
*/
void
shell_app_activate (ShellApp *app)
{
switch (app->state)
{
case SHELL_APP_STATE_STOPPED:
/* TODO sensibly handle this error */
shell_app_info_launch (app->info, NULL);
break;
case SHELL_APP_STATE_STARTING:
break;
case SHELL_APP_STATE_RUNNING:
shell_app_activate_window (app, NULL, shell_global_get_current_time (shell_global_get ()));
break;
}
}
/**
* shell_app_open_new_window:
* @app: a #ShellApp
*
* Request that the application create a new window.
*/
void
shell_app_open_new_window (ShellApp *app)
{
/* Here we just always launch the application again, even if we know
* it was already running. For most applications this
* should have the effect of creating a new window, whether that's
* a second process (in the case of Calculator) or IPC to existing
* instance (Firefox). There are a few less-sensical cases such
* as say Pidgin. Ideally, we have the application express to us
* that it supports an explicit new-window action.
*/
shell_app_info_launch (app->info, NULL);
}
/**
* shell_app_get_state:
* @app: a #ShellApp
*
* Returns: State of the application
*/
ShellAppState
shell_app_get_state (ShellApp *app)
{
return app->state;
}
/**
@ -341,10 +562,9 @@ shell_app_is_on_workspace (ShellApp *app,
* @other: A #ShellApp
*
* Compare one #ShellApp instance to another, in the following way:
* - Running applications sort before not-running applications.
* - If one of them has visible windows and the other does not, the one
* with visible windows is first.
* - If one has no windows at all (i.e. it's not running) and the other
* does, the one with windows is first.
* - Finally, the application which the user interacted with most recently
* compares earlier.
*/
@ -353,7 +573,13 @@ shell_app_compare (ShellApp *app,
ShellApp *other)
{
gboolean vis_app, vis_other;
GSList *windows_app, *windows_other;
if (app->state != other->state)
{
if (app->state == SHELL_APP_STATE_RUNNING)
return -1;
return 1;
}
vis_app = shell_app_has_visible_windows (app);
vis_other = shell_app_has_visible_windows (other);
@ -368,10 +594,7 @@ shell_app_compare (ShellApp *app,
else if (!app->windows && other->windows)
return 1;
windows_app = shell_app_get_windows (app);
windows_other = shell_app_get_windows (other);
return meta_window_get_user_time (windows_other->data) - meta_window_get_user_time (windows_app->data);
return other->last_user_time - app->last_user_time;
}
ShellApp *
@ -399,6 +622,18 @@ _shell_app_new (ShellAppInfo *info)
return app;
}
static void
shell_app_state_transition (ShellApp *app,
ShellAppState state)
{
if (app->state == state)
return;
g_return_if_fail (!(app->state == SHELL_APP_STATE_RUNNING &&
state == SHELL_APP_STATE_STARTING));
app->state = state;
g_object_notify (G_OBJECT (app), "state");
}
static void
shell_app_on_unmanaged (MetaWindow *window,
ShellApp *app)
@ -411,6 +646,8 @@ shell_app_on_user_time_changed (MetaWindow *window,
GParamSpec *pspec,
ShellApp *app)
{
app->last_user_time = meta_window_get_user_time (window);
/* Ideally we don't want to emit windows-changed if the sort order
* isn't actually changing. This check catches most of those.
*/
@ -437,6 +674,8 @@ void
_shell_app_add_window (ShellApp *app,
MetaWindow *window)
{
guint32 user_time;
if (g_slist_find (app->windows, window))
return;
@ -445,6 +684,13 @@ _shell_app_add_window (ShellApp *app,
g_signal_connect (window, "notify::user-time", G_CALLBACK(shell_app_on_user_time_changed), app);
app->window_sort_stale = TRUE;
user_time = meta_window_get_user_time (window);
if (user_time > app->last_user_time)
app->last_user_time = user_time;
if (app->state != SHELL_APP_STATE_RUNNING)
shell_app_state_transition (app, SHELL_APP_STATE_RUNNING);
g_signal_emit (app, shell_app_signals[WINDOWS_CHANGED], 0);
if (app->workspace_switch_id == 0)
@ -484,12 +730,58 @@ _shell_app_remove_window (ShellApp *app,
g_signal_emit (app, shell_app_signals[WINDOWS_CHANGED], 0);
if (app->windows == NULL)
disconnect_workspace_switch (app);
{
disconnect_workspace_switch (app);
shell_app_state_transition (app, SHELL_APP_STATE_STOPPED);
}
}
void
_shell_app_set_starting (ShellApp *app,
gboolean starting)
{
if (starting && app->state == SHELL_APP_STATE_STOPPED)
shell_app_state_transition (app, SHELL_APP_STATE_STARTING);
else if (!starting && app->state == SHELL_APP_STATE_STARTING)
shell_app_state_transition (app, SHELL_APP_STATE_RUNNING);
}
/**
* shell_app_request_quit:
* @app: A #ShellApp
*
* Initiate an asynchronous request to quit this application.
* The application may interact with the user, and the user
* might cancel the quit request from the application UI.
*
* This operation may not be supported for all applications.
*
* Returns: %TRUE if a quit request is supported for this application
*/
gboolean
shell_app_request_quit (ShellApp *app)
{
GSList *iter;
/* TODO - check for an XSMP connection; we could probably use that */
for (iter = app->windows; iter; iter = iter->next)
{
MetaWindow *win = iter->data;
if (!shell_window_tracker_is_window_interesting (win))
continue;
meta_window_delete (win, shell_global_get_current_time (shell_global_get ()));
}
return TRUE;
}
static void
shell_app_init (ShellApp *self)
{
self->state = SHELL_APP_STATE_STOPPED;
}
static void
@ -516,6 +808,7 @@ shell_app_class_init(ShellAppClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = shell_app_get_property;
gobject_class->dispose = shell_app_dispose;
shell_app_signals[WINDOWS_CHANGED] = g_signal_new ("windows-changed",
@ -525,4 +818,19 @@ shell_app_class_init(ShellAppClass *klass)
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* ShellApp:state:
*
* The high-level state of the application, effectively whether it's
* running or not, or transitioning between those states.
*/
g_object_class_install_property (gobject_class,
PROP_STATE,
g_param_spec_enum ("state",
"State",
"Application state",
SHELL_TYPE_APP_STATE,
SHELL_APP_STATE_STOPPED,
G_PARAM_READABLE));
}

View File

@ -3,6 +3,7 @@
#define __SHELL_APP_H__
#include <clutter/clutter.h>
#include <gio/gio.h>
#include "window.h"
@ -25,6 +26,12 @@ struct _ShellAppClass
};
typedef enum {
SHELL_APP_STATE_STOPPED,
SHELL_APP_STATE_STARTING,
SHELL_APP_STATE_RUNNING
} ShellAppState;
GType shell_app_get_type (void) G_GNUC_CONST;
const char *shell_app_get_id (ShellApp *app);
@ -34,7 +41,16 @@ ClutterActor *shell_app_get_faded_icon (ShellApp *app, float size);
char *shell_app_get_name (ShellApp *app);
char *shell_app_get_description (ShellApp *app);
gboolean shell_app_is_transient (ShellApp *app);
gboolean shell_app_launch (ShellApp *info, GError **error);
void shell_app_activate_window (ShellApp *app, MetaWindow *window, guint32 timestamp);
void shell_app_activate (ShellApp *app);
void shell_app_open_new_window (ShellApp *app);
ShellAppState shell_app_get_state (ShellApp *app);
gboolean shell_app_request_quit (ShellApp *app);
guint shell_app_get_n_windows (ShellApp *app);

View File

@ -51,20 +51,24 @@ shell_draw_clock (StDrawingArea *area,
void
shell_draw_box_pointer (StDrawingArea *area,
ShellPointerDirection direction,
ClutterColor *border_color,
ClutterColor *background_color)
ShellPointerDirection direction)
{
StThemeNode *theme_node;
ClutterColor border_color, body_color;
guint width, height;
cairo_t *cr;
theme_node = st_widget_get_theme_node (ST_WIDGET (area));
st_theme_node_get_border_color (theme_node, (StSide)direction, &border_color);
st_theme_node_get_foreground_color (theme_node, &body_color);
st_drawing_area_get_surface_size (area, &width, &height);
cr = st_drawing_area_get_context (area);
cairo_set_line_width (cr, 1.0);
clutter_cairo_set_source_color (cr, border_color);
clutter_cairo_set_source_color (cr, &border_color);
switch (direction)
{
@ -98,7 +102,7 @@ shell_draw_box_pointer (StDrawingArea *area,
cairo_stroke_preserve (cr);
clutter_cairo_set_source_color (cr, background_color);
clutter_cairo_set_source_color (cr, &body_color);
cairo_fill (cr);
}

View File

@ -8,17 +8,16 @@
G_BEGIN_DECLS
/* Note that these correspond to StSide */
typedef enum {
SHELL_POINTER_UP,
SHELL_POINTER_RIGHT,
SHELL_POINTER_DOWN,
SHELL_POINTER_LEFT,
SHELL_POINTER_RIGHT
SHELL_POINTER_LEFT
} ShellPointerDirection;
void shell_draw_box_pointer (StDrawingArea *area,
ShellPointerDirection direction,
ClutterColor *border_color,
ClutterColor *background_color);
ShellPointerDirection direction);
void shell_draw_clock (StDrawingArea *area,
int hour,

View File

@ -6,6 +6,7 @@
#include <clutter/x11/clutter-x11.h>
#include "shell-embedded-window-private.h"
#include "gtk-compat.h"
/* This type is a subclass of GtkWindow that ties the window to a
* ShellGtkEmbed; the window is reparented into the stage
@ -55,8 +56,12 @@ static void
shell_embedded_window_show (GtkWidget *widget)
{
ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget);
GtkWidgetClass *widget_class;
GTK_WIDGET_SET_FLAGS (widget, GTK_VISIBLE);
/* Skip GtkWindow, but run the default GtkWidget handling which
* marks the widget visible */
widget_class = g_type_class_peek (GTK_TYPE_WIDGET);
widget_class->show (widget);
if (window->priv->actor)
{
@ -107,7 +112,7 @@ shell_embedded_window_realize (GtkWidget *widget)
* modifying the GDK hierarchy.
*/
XReparentWindow (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)),
GDK_WINDOW_XWINDOW (widget->window),
GDK_WINDOW_XWINDOW (gtk_widget_get_window (widget)),
stage_xwindow,
window->priv->position.x, window->priv->position.y);
}
@ -202,7 +207,8 @@ _shell_embedded_window_set_actor (ShellEmbeddedWindow *window,
window->priv->actor = actor;
if (GTK_WIDGET_VISIBLE (window) && CLUTTER_ACTOR_IS_REALIZED (actor))
if (gtk_widget_get_visible (GTK_WIDGET (window))
&& CLUTTER_ACTOR_IS_REALIZED (actor))
gtk_widget_map (GTK_WIDGET (window));
}
@ -222,8 +228,8 @@ _shell_embedded_window_allocate (ShellEmbeddedWindow *window,
window->priv->position.width = width;
window->priv->position.height = height;
if (GTK_WIDGET_REALIZED (window))
gdk_window_move_resize (GTK_WIDGET (window)->window,
if (gtk_widget_get_realized (GTK_WIDGET (window)))
gdk_window_move_resize (gtk_widget_get_window (GTK_WIDGET (window)),
x, y, width, height);
allocation.x = 0;
@ -239,7 +245,7 @@ _shell_embedded_window_realize (ShellEmbeddedWindow *window)
{
g_return_if_fail (SHELL_IS_EMBEDDED_WINDOW (window));
if (GTK_WIDGET_VISIBLE (window))
if (gtk_widget_get_visible (GTK_WIDGET (window)))
gtk_widget_map (GTK_WIDGET (window));
}

View File

@ -1,5 +1,5 @@
/*** BEGIN file-header ***/
#include "big-enum-types.h"
#include "shell-enum-types.h"
/*** END file-header ***/
/*** BEGIN file-production ***/

View File

@ -1,6 +1,6 @@
/*** BEGIN file-header ***/
#ifndef __BIG_ENUM_TYPES_H__
#define __BIG_ENUM_TYPES_H__
#ifndef __SHELL_ENUM_TYPES_H__
#define __SHELL_ENUM_TYPES_H__
#include <glib-object.h>
@ -15,11 +15,11 @@ G_BEGIN_DECLS
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* !__BIG_ENUM_TYPES_H__ */
#endif /* !__SHELL_ENUM_TYPES_H__ */
/*** END file-tail ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define BIG_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
#define SHELL_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
/*** END value-header ***/

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