Compare commits

..

11 Commits

Author SHA1 Message Date
Colin Walters
94d01bed12 build: Split out "private" sources variable that can be easily appended
Move the action muxing copy stuff in there.
2011-12-20 13:41:08 -05:00
Ryan Lortie
9daf358122 action muxer: drop direct GDBusActionGroup use
We now have GRemoteActionGroup interface with the needed API,
implemented by GDBusActionGroup.

With the new API we could theoretically turn GActionMuxer itself into a
GRemoteActionGroup and expose the _full API to the shell so that the
timestamps could be passed from there.
2011-12-17 13:23:26 -05:00
Matthias Clasen
b4b3f5a669 GActionMuxer: pass platform data
Pass the current timestamp as platform data when activating
an action. This is implemented slightly hacky, since we use
clutter_get_current_event_time() to get at the timestamp, but
the alternative is to expose g_action_muxer_activate_action_full
to js, which would be quite a bit more involved.
2011-12-16 23:39:14 -05:00
Matthias Clasen
5290a9dd08 Add per-window actions
GTK+ also exports window-specific actions, by putting the object path
for the exported action group in the _DBUS_OBJECT_PATH X property.
We add this action group to the app's muxer with a 'win' prefix,
since that is what the exported menu expects. Whenever the focus
window changes, we update the window-specific actions of its
application, and emit notify::action-group to cause the app
menu to be updated.
2011-12-15 01:25:35 -05:00
Matthias Clasen
ab4a7c5237 Another update for GLib API changes
GDBusActionGroup api has changed again, adapt to that.
Also, use a GActionMuxer to add the 'app.' prefix to actions,
instead of manually stripping it out of the action names.
In the future, the muxer will also contain per-window actions
with a 'win.' prefix.
2011-12-15 00:29:31 -05:00
Giovanni Campagna
95e5c5cfb1 Application Menu: watch for menu property changes
By the time the window is first mapped and the app menu button is
synced, we may not have finished reading the menu. In that case,
connect to notify::menu and update accordingly.
2011-12-08 21:55:51 +01:00
Giovanni Campagna
757fb5796e Application Menu: update for latest GMenu changes
GMenuProxy has been replaced by GDBusMenuModel, and the object path
has been moved (now needs to be retrieved from the AppMenu GApplication
property).
Update the test to prefix each action with "app." as documented,
and use a GtkApplicationWindow instead of a plain GtkWindow.
2011-12-08 21:53:03 +01:00
Giovanni Campagna
75e9fa9cfb test-gapplication: update for latest gapplication changes
g_application_set_action_group is deprecated, we should use
GActionMap. Also, GSimpleActions can now be constructed as normal
GObjects.
2011-12-02 22:15:14 +01:00
Colin Walters
8997aa45b1 popupMenu: Remove app. from app actions 2011-12-01 12:33:07 -05:00
Giovanni Campagna
f884dbbfb2 Application Menu: add support for showing GApplication actions
Use the new GApplication support in ShellApp to create the application
menu. Supports plain (no state), boolean and double actions.
Includes a test application (as no other application uses GApplication
for actions)

https://bugzilla.gnome.org/show_bug.cgi?id=621203
2011-12-01 10:21:38 -05:00
Giovanni Campagna
d0c36bb732 ShellApp: port to new GDBusActionGroup and GMenuProxy API
GDBusActionGroup and GMenuProxy are new objects in GIO 2.32 that
help with accessing menus and actions of remote applications.
This patch makes it possible for the shell to associate an
application with a dbus name and from that a GMenu, that will
be shown as the application menu.

https://bugzilla.gnome.org/show_bug.cgi?id=621203
2011-11-25 18:20:38 -05:00
92 changed files with 9058 additions and 13783 deletions

82
NEWS
View File

@@ -1,85 +1,3 @@
3.3.4
=====
* https://live.gnome.org/EveryDetailMatters
- Add "browse" for labels for dash items - once a tooltip is
showing, switch to other items without a delay [Seif; #666170]
- Always scale down windows in the overview at least to 70% [Vit; #646704]
- Fix the new-workspace drop indicator sometimes getting stuck
[Stefano; #664201]
- Delay rearranging windows in the overview as long as the pointer
is over a window [Vit; #645325]
* Add a GConf => DConf migration file for overriden Mutter settings
[Florian; #667636]
* When a VPN connection is active, show that as the network icon
[Giovanni; #665115]
* Handle the "ExtendedAway" IM status as away, not offline [Guillaume; #667813]
* Improve the appearance of the labels in "Applications" [Alex; #642392]
* Adjust for GTK+ and Mutter API changes for application menu [Ryan; #668118]
* Add section label support to the application menu [Giovanni; #666681]
* Fix screenshot methods to work again [Cosimo; #667662]
* Fix several crashers related to updating workspace thumbnails [Owen; #667652]
* Fix memory management error causing gnome-shell-hotplug-sniffer to crash
[Owen; #667378]
* Build fixes [Emmanuele, Rico; #667864]
* Code cleanups [Adel; #668087]
* Misc bug fixes [Colin, Florian, Giovanni, Owen, Xavier; #633028, #658817,
#664138, #667881, #668048, #668050]
Contributors:
Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Xavier Claessens,
Guillaume Desmottes, Stefano Facchini, Adel Gadllah, Alex Hultman,
Ryan Lortie, Seif Lotfy, Florian Müllner, Vit Stanislav, Owen Taylor,
Rico Tzschichholz, Colin Walters
Translations:
Ihar Hrachyshka [be], Alexander Shopov [bg], Arash Mousavi [fa],
Jiri Grönroos, Timo Jyrinki [fi], Fran Diéguez [gl], Kjartan Maraas [nb],
Yuri Myasoedov [ru], Matej Urbančič [sl], Nguyễn Thái Ngọc Duy [vi]
3.3.3
=====
* https://live.gnome.org/EveryDetailMatters
- Stop flashing the window labels on actions in overview [Zan; #644861]
- Improve the look of window captions in the overview [Marc; #664487]
- Move dash tooltips beside the icon [Seif, Stefano; #666166]
* Support application menus exported from applications via new GLib API
and D-Bus protocol. [Giovanni, Colin, Matthias, Cosimo]
* For removable device prompts, show "Open with Rhythmbox], rather
than "Open with Rhythmbox Music Player' [Florian; #664561]
* Switch to activating the message tray only with a hot corner rather
than a full row of pixels, allowing mouse events to apps [Rui; #663366]
* Fully handle the case where the workspaces-only-on-primary
GSetting is set to false [Florian; #652580]
* Add support for background-size CSS property to St [Quentin; #633462]
* Port to new GJS Lang.Class framework [Giovanni; #664436]
* Finish port to GDBus [Giovanni; #664436]
* Stop using the deprecated Clutter default stage [Florian, Jasper; #664052]
* Fix bugs that kept browser plugin from working in WebKit-based browser
[Jasper; #666444]
* Fix typo that made uninstalling extensions not work [Jasper]
* Fix crash in browser plugin if shell is not run [Jürg]
* Reintroduce piscine paschal ovum [Giovanni; #666606]
* Network menu bug fixes
Giovanni; #664124, #665194, #665680, #666429, #666614]
* Misc bug fixes [Florian, Jasper, Jonny, Marina, Ron; #647587, #659272,
#664138, #665261, #666020, #666243]
* Build fixes [Owen]
Contributors:
Jürg Billeter, Giovanni Campagna, Stefano Candori, Cosimo Cecchi,
Matthias Clasen, Zan Dobersek, Quentin Glidic, Jonny Lamb, Ryan Lortie,
Seif Lotfy, Rui Matos, Florian Müllner, Bastien Nocera, Jasper St. Pierre,
Marc Plano-Lesay, Owen Taylor, Colin Walters, Ron Yorsten,
Marina Zhurakhinskaya
Translations:
Petr Kovar [cz], Kris Thomsen [dk], Daniel Mustieles [es],
Ville-Pekka Vainio [fi], Yaron Shahrabani [he], Luca Ferretti [it],
Hideki Yamane [ja], Žygimantas Beručka [lt], Jovan Naumovski [mk],
Kjartan Maraas [nb], "Andreas N" [nn], Lucian Adrian Grijincu [ro],
Matej Urbančič [sl], Praveen Illa [te], Muhammet Kara [tr],
Daniel Korostil [uk], Aron Xu [zh_CN]
3.3.2
=====
* Port D-Bus usage in the shell to GDBus [Giovanni, Marc-Antoine, Florian,

View File

@@ -455,7 +455,7 @@ plugin_enable_extension (PluginObject *obj,
NPString uuid,
gboolean enabled)
{
gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
const gchar *uuid_str = uuid.UTF8Characters;
if (!uuid_is_valid (uuid_str))
return FALSE;
@@ -468,8 +468,6 @@ plugin_enable_extension (PluginObject *obj,
NULL, /* callback */
NULL /* user_data */);
g_free (uuid_str);
return TRUE;
}
@@ -478,32 +476,21 @@ plugin_install_extension (PluginObject *obj,
NPString uuid,
NPString version_tag)
{
gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
gchar *version_tag_str;
const gchar *uuid_str = uuid.UTF8Characters;
if (!uuid_is_valid (uuid_str))
{
g_free (uuid_str);
return FALSE;
}
version_tag_str = g_strndup (version_tag.UTF8Characters,
version_tag.UTF8Length);
return FALSE;
g_dbus_proxy_call (obj->proxy,
"InstallRemoteExtension",
g_variant_new ("(ss)",
uuid_str,
version_tag_str),
version_tag.UTF8Characters),
G_DBUS_CALL_FLAGS_NONE,
-1, /* timeout */
NULL, /* cancellable */
NULL, /* callback */
NULL /* user_data */);
g_free (uuid_str);
g_free (version_tag_str);
return TRUE;
}
@@ -514,14 +501,11 @@ plugin_uninstall_extension (PluginObject *obj,
{
GError *error = NULL;
GVariant *res;
gchar *uuid_str;
const gchar *uuid_str;
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
uuid_str = uuid.UTF8Characters;
if (!uuid_is_valid (uuid_str))
{
g_free (uuid_str);
return FALSE;
}
return FALSE;
res = g_dbus_proxy_call_sync (obj->proxy,
"UninstallExtension",
@@ -532,8 +516,6 @@ plugin_uninstall_extension (PluginObject *obj,
NULL, /* cancellable */
&error);
g_free (uuid_str);
if (!res)
{
g_warning ("Failed to uninstall extension: %s", error->message);
@@ -551,14 +533,11 @@ plugin_get_info (PluginObject *obj,
{
GError *error = NULL;
GVariant *res;
gchar *uuid_str;
const gchar *uuid_str;
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
uuid_str = uuid.UTF8Characters;
if (!uuid_is_valid (uuid_str))
{
g_free (uuid_str);
return FALSE;
}
return FALSE;
res = g_dbus_proxy_call_sync (obj->proxy,
"GetExtensionInfo",
@@ -568,8 +547,6 @@ plugin_get_info (PluginObject *obj,
NULL, /* cancellable */
&error);
g_free (uuid_str);
if (!res)
{
g_warning ("Failed to retrieve extension metadata: %s", error->message);
@@ -587,14 +564,11 @@ plugin_get_errors (PluginObject *obj,
{
GError *error = NULL;
GVariant *res;
gchar *uuid_str;
const gchar *uuid_str;
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
uuid_str = uuid.UTF8Characters;
if (!uuid_is_valid (uuid_str))
{
g_free (uuid_str);
return FALSE;
}
return FALSE;
res = g_dbus_proxy_call_sync (obj->proxy,
"GetExtensionErrors",
@@ -604,8 +578,6 @@ plugin_get_errors (PluginObject *obj,
NULL, /* cancellable */
&error);
g_free (uuid_str);
if (!res)
{
g_warning ("Failed to retrieve errors: %s", error->message);
@@ -661,8 +633,7 @@ plugin_get_shell_version (PluginObject *obj,
STRINGN_TO_NPVARIANT (buffer, length, *result);
out:
if (res)
g_variant_unref (res);
g_variant_unref (res);
return ret;
}

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.3.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.3.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])
@@ -63,14 +63,14 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.7.5
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=1.29.18
MUTTER_MIN_VERSION=3.3.3
MUTTER_MIN_VERSION=3.3.2
FOLKS_MIN_VERSION=0.5.2
GTK_MIN_VERSION=3.3.9
GIO_MIN_VERSION=2.31.6
GTK_MIN_VERSION=3.0.0
GIO_MIN_VERSION=2.31.0
LIBECAL_MIN_VERSION=2.32.0
LIBEDATASERVER_MIN_VERSION=1.2.0
LIBEDATASERVERUI_MIN_VERSION=2.91.6
TELEPATHY_GLIB_MIN_VERSION=0.15.6
TELEPATHY_GLIB_MIN_VERSION=0.15.5
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
POLKIT_MIN_VERSION=0.100
STARTUP_NOTIFICATION_MIN_VERSION=0.11
@@ -84,7 +84,6 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
gjs-internals-1.0 >= $GJS_MIN_VERSION
libgnome-menu-3.0 $recorder_modules
gdk-x11-3.0 libsoup-2.4
gl
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION

View File

@@ -59,8 +59,6 @@ gschemas.compiled: $(gsettings_SCHEMAS:.xml=.valid)
all-local: gschemas.compiled
convertdir = $(datadir)/GConf/gsettings
convert_DATA = gnome-shell-overrides.convert
shadersdir = $(pkgdatadir)/shaders
shaders_DATA = \
@@ -71,7 +69,6 @@ EXTRA_DIST = \
gnome-shell.desktop.in.in \
$(menu_DATA) \
$(shaders_DATA) \
$(convert_DATA) \
org.gnome.shell.gschema.xml.in
CLEANFILES = \

View File

@@ -1,5 +0,0 @@
[org.gnome.shell.overrides]
attach-modal-dialogs = /desktop/gnome/shell/windows/attach_modal_dialogs
button-layout = /desktop/gnome/shell/windows/button_layout
edge-tiling = /desktop/gnome/shell/windows/edge_tiling
workspaces-only-on-primary = /desktop/gnome/shell/windows/workspaces_only_on_primary

View File

@@ -60,7 +60,6 @@ StScrollBar StBin#trough {
StScrollBar StButton#vhandle
{
background-image: url("scroll-vhandle.svg");
background-size: contain;
background-color: #252525;
border: 1px solid #080808;
border-radius: 8px;
@@ -69,7 +68,6 @@ StScrollBar StButton#vhandle
StScrollBar StButton#hhandle
{
background-image: url("scroll-hhandle.svg");
background-size: contain;
background-color: #252525;
border: 1px solid #080808;
border-radius: 8px;
@@ -226,20 +224,16 @@ StTooltip StLabel {
.toggle-switch-us {
background-image: url("toggle-off-us.svg");
background-size: contain;
}
.toggle-switch-us:checked {
background-image: url("toggle-on-us.svg");
background-size: contain;
}
.toggle-switch-intl {
background-image: url("toggle-off-intl.svg");
background-size: contain;
}
.toggle-switch-intl:checked {
background-image: url("toggle-on-intl.svg");
background-size: contain;
}
.nm-menu-item-icons {
@@ -362,7 +356,6 @@ StTooltip StLabel {
.panel-button:focus {
border-image: url("panel-button-border.svg") 10 10 0 2;
background-image: url("panel-button-highlight-wide.svg");
background-size: contain;
color: white;
text-shadow: black 0px 2px 2px;
}
@@ -371,7 +364,6 @@ StTooltip StLabel {
.panel-status-button:checked,
.panel-status-button:focus {
background-image: url("panel-button-highlight-narrow.svg");
background-size: contain;
}
.panel-button:active > .system-status-icon,
@@ -475,17 +467,16 @@ StTooltip StLabel {
}
.window-caption {
background: rgba(0,0,0,0.5);
border-radius: 8px;
background: rgba(0,0,0,0.8);
border: 1px solid rgba(128,128,128,0.40);
border-radius: 10px;
font-size: 9pt;
font-weight: bold;
padding: 6px 12px;
-shell-caption-spacing: 12px;
padding: 2px 8px;
-shell-caption-spacing: 4px;
}
.window-close {
background-image: url("close-window.svg");
background-size: 34px;
height: 34px;
width: 34px;
-shell-close-overlap: 20px;
@@ -520,7 +511,6 @@ StTooltip StLabel {
.placeholder {
background-image: url("dash-placeholder.svg");
background-size: contain;
height: 24px;
}
@@ -655,17 +645,6 @@ StTooltip StLabel {
font-size: 11pt;
}
.dash-label {
border-radius: 7px;
padding: 4px 12px;
background-color: rgba(0,0,0,0.5);
color: #ffffff;
font-size: 0.9em;
font-weight: bold;
text-align: center;
-x-offset: 8px;
}
/* Apps */
.icon-grid {
@@ -707,13 +686,11 @@ StTooltip StLabel {
.app-filter:selected {
color: #ffffff;
background-image: url("filter-selected-ltr.svg");
background-size: contain;
background-position: 190px 10px;
}
.app-filter:selected:rtl {
background-image: url("filter-selected-rtl.svg");
background-size: contain;
background-position: 10px 10px;
}
@@ -740,8 +717,7 @@ StTooltip StLabel {
border-radius: 4px;
padding: 3px;
border: 1px rgba(0,0,0,0);
font-size: 8pt;
font-weight: bold;
font-size: 7.5pt;
color: white;
transition-duration: 100;
text-align: center;
@@ -795,7 +771,6 @@ StTooltip StLabel {
.app-well-app.running > .overview-icon {
text-shadow: black 0px 2px 2px;
background-image: url("running-indicator.svg");
background-size: contain;
}
.contact:selected,
@@ -1457,7 +1432,6 @@ StTooltip StLabel {
.summary-source-button:selected .summary-source {
background-image: url("panel-button-highlight-narrow.svg");
background-size: contain;
border-image: url("source-button-border.svg") 10 10 0 1;
}
@@ -1468,7 +1442,6 @@ StTooltip StLabel {
.summary-source-button:expanded:selected {
background-image: url("panel-button-highlight-wide.svg");
background-size: contain;
border-image: url("source-button-border.svg") 10 10 0 1;
}
@@ -1582,7 +1555,6 @@ StTooltip StLabel {
width: 52px;
height: 52px;
background-image: url("corner-ripple-ltr.png");
background-size: contain;
}
.ripple-box:rtl {
@@ -1624,7 +1596,6 @@ StTooltip StLabel {
border: 0px;
background: rgba(255,255,255,0.5);
background-image: url("ws-switch-arrow-up.svg");
background-size: contain;
border-radius: 8px;
}
@@ -1633,7 +1604,6 @@ StTooltip StLabel {
border: 0px;
background: rgba(255,255,255,0.5);
background-image: url("ws-switch-arrow-down.svg");
background-size: contain;
border-radius: 8px;
}

View File

@@ -18,10 +18,11 @@ DOC_MODULE=shell
# The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# Directories containing the source code
# Directories containing the source code, relative to $(srcdir).
# gtk-doc will search all .c and .h files beneath these paths
# for inline comments documenting functions and macros.
DOC_SOURCE_DIR=$(top_srcdir)/src
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
DOC_SOURCE_DIR=../../../src
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS=
@@ -57,16 +58,7 @@ EXTRA_HFILES=
# Header files or dirs to ignore when scanning. Use base file/dir names
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
IGNORE_HFILES= \
calendar-server \
gvc \
hotplug-sniffer \
st \
tray \
gactionmuxer.h \
gactionobservable.h \
gactionobserver.h \
shell-recorder-src.h
IGNORE_HFILES=calendar-server gvc hotplug-sniffer st tray
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
@@ -87,7 +79,7 @@ expand_content_files=
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(BLUETOOTH_LIBS) $(top_builddir)/src/libgnome-shell.la
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(top_builddir)/src/libgnome-shell.la
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make

View File

@@ -18,10 +18,11 @@ DOC_MODULE=st
# The top-level SGML file. You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# Directories containing the source code
# Directories containing the source code, relative to $(srcdir).
# gtk-doc will search all .c and .h files beneath these paths
# for inline comments documenting functions and macros.
DOC_SOURCE_DIR=$(top_srcdir)/src/st
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
DOC_SOURCE_DIR=../../../src/st
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS=

View File

@@ -72,7 +72,6 @@ nobase_dist_js_DATA = \
ui/tweener.js \
ui/userMenu.js \
ui/viewSelector.js \
ui/wanda.js \
ui/windowAttentionHandler.js \
ui/windowManager.js \
ui/workspace.js \

View File

@@ -205,8 +205,7 @@ const UserListItem = new Lang.Class({
// We use background-image instead of, say, St.TextureCache
// so the theme writers can add a rounded frame around the image
// and so theme writers can pick the icon size.
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
'background-size: contain;');
this._iconBin.set_style('background-image: url("' + iconFile + '");');
} else {
this._iconBin.hide();
}

View File

@@ -38,7 +38,7 @@ function recursivelyDeleteDir(dir) {
let child = dir.get_child(info.get_name());
if (type == Gio.FileType.REGULAR)
deleteGFile(child);
else if (type == Gio.FileType.DIRECTORY)
else if (type == Gio.TypeType.DIRECTORY)
recursivelyDeleteDir(child);
}

View File

@@ -232,53 +232,3 @@ function fixupPCIDescription(desc) {
return out.join(' ');
}
// lowerBound:
// @array: an array or array-like object, already sorted
// according to @cmp
// @val: the value to add
// @cmp: a comparator (or undefined to compare as numbers)
//
// Returns the position of the first element that is not
// lower than @val, according to @cmp.
// That is, returns the first position at which it
// is possible to insert @val without violating the
// order.
// This is quite like an ordinary binary search, except
// that it doesn't stop at first element comparing equal.
function lowerBound(array, val, cmp) {
let min, max, mid, v;
cmp = cmp || function(a, b) { return a - b; };
if (array.length == 0)
return 0;
min = 0; max = array.length;
while (min < (max - 1)) {
mid = Math.floor((min + max) / 2);
v = cmp(array[mid], val);
if (v < 0)
min = mid + 1;
else
max = mid;
}
return (min == max || cmp(array[min], val) < 0) ? max : min;
}
// insertSorted:
// @array: an array sorted according to @cmp
// @val: a value to insert
// @cmp: the sorting function
//
// Inserts @val into @array, preserving the
// sorting invariants.
// Returns the position at which it was inserted
function insertSorted(array, val, cmp) {
let pos = lowerBound(array, val, cmp);
array.splice(pos, 0, val);
return pos;
}

View File

@@ -470,7 +470,6 @@ const AppWellIcon = new Lang.Class({
Lang.bind(this,
this._onStateChanged));
this._onStateChanged();
this.isMenuUp = false;
},
_onDestroy: function() {
@@ -552,8 +551,8 @@ const AppWellIcon = new Lang.Class({
this._menuManager.addMenu(this._menu);
}
this.isMenuUp = true;
this.actor.set_hover(true);
this.actor.show_tooltip();
this._menu.popup();
return false;
@@ -569,7 +568,6 @@ const AppWellIcon = new Lang.Class({
_onMenuPoppedDown: function() {
this.actor.sync_hover();
this.isMenuUp = false;
},
_onActivate: function (event) {

View File

@@ -557,7 +557,7 @@ const AutorunTransientNotification = new Lang.Class({
let label = new St.Bin({ y_align: St.Align.MIDDLE,
child: new St.Label
({ text: _("Open with %s").format(app.get_name()) })
({ text: _("Open with %s").format(app.get_display_name()) })
});
box.add(label);

View File

@@ -6,7 +6,6 @@ const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const AppDisplay = imports.ui.appDisplay;
const AppFavorites = imports.ui.appFavorites;
@@ -17,9 +16,6 @@ const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const DASH_ANIMATION_TIME = 0.2;
const DASH_ITEM_LABEL_SHOW_TIME = 0.15;
const DASH_ITEM_LABEL_HIDE_TIME = 0.1;
const DASH_ITEM_HOVER_TIMEOUT = 300;
// A container like StBin, but taking the child's scale into account
// when requesting a size
@@ -36,8 +32,6 @@ const DashItemContainer = new Lang.Class({
Lang.bind(this, this._allocate));
this.actor._delegate = this;
this._label = null;
this.child = null;
this._childScale = 1;
this._childOpacity = 255;
@@ -90,60 +84,6 @@ const DashItemContainer = new Lang.Class({
alloc.natural_size = natWidth * this.child.scale_y;
},
showLabel: function() {
if (this._label == null)
return;
this._label.opacity = 0;
this._label.show();
let [stageX, stageY] = this.actor.get_transformed_position();
let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
let labelHeight = this._label.get_height();
let yOffset = Math.floor((itemHeight - labelHeight) / 2)
let y = stageY + yOffset;
let node = this._label.get_theme_node();
let xOffset = node.get_length('-x-offset');
let x;
if (St.Widget.get_default_direction () == St.TextDirection.RTL)
x = stageX - this._label.get_width() - xOffset;
else
x = stageX + this.actor.get_width() + xOffset;
this._label.set_position(x, y);
Tweener.addTween(this._label,
{ opacity: 255,
time: DASH_ITEM_LABEL_SHOW_TIME,
transition: 'easeOutQuad',
});
},
setLabelText: function(text) {
if (this._label == null)
this._label = new St.Label({ style_class: 'dash-label'});
this._label.set_text(text);
Main.layoutManager.addChrome(this._label);
this._label.hide();
},
hideLabel: function () {
this._label.opacity = 255;
Tweener.addTween(this._label,
{ opacity: 0,
time: DASH_ITEM_LABEL_HIDE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._label.hide();
})
});
},
setChild: function(actor) {
if (this.child == actor)
return;
@@ -298,9 +238,6 @@ const Dash = new Lang.Class({
this._dragPlaceholderPos = -1;
this._animatingPlaceholdersCount = 0;
this._favRemoveTarget = null;
this._showLabelTimeoutId = 0;
this._resetHoverTimeoutId = 0;
this._labelShowing = false;
this._box = new St.BoxLayout({ name: 'dash',
vertical: true,
@@ -434,48 +371,14 @@ const Dash = new Lang.Class({
Lang.bind(this, function() {
display.actor.opacity = 255;
}));
display.actor.set_tooltip_text(app.get_name());
let item = new DashItemContainer();
item.setChild(display.actor);
item.setLabelText(app.get_name());
display.icon.setIconSize(this.iconSize);
display.actor.connect('notify::hover',
Lang.bind(this, function() {
this._onHover(item, display)
}));
return item;
},
_onHover: function (item, display) {
if (display.actor.get_hover() && !display.isMenuUp) {
if (this._showLabelTimeoutId == 0) {
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
Lang.bind(this, function() {
this._labelShowing = true;
item.showLabel();
return false;
}));
if (this._resetHoverTimeoutId > 0) {
Mainloop.source_remove(this._resetHoverTimeoutId);
this._resetHoverTimeoutId = 0;
}
}
} else {
if (this._showLabelTimeoutId > 0)
Mainloop.source_remove(this._showLabelTimeoutId);
this._showLabelTimeoutId = 0;
item.hideLabel();
if (this._labelShowing) {
this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT,
Lang.bind(this, function() {
this._labelShowing = false;
return false;
}));
}
}
return item;
},
_adjustIconSize: function() {

View File

@@ -333,8 +333,7 @@ const EndSessionDialog = new Lang.Class({
this._iconBin.child = null;
if (iconFile) {
this._iconBin.show();
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
'background-size: contain;');
this._iconBin.set_style('background-image: url("' + iconFile + '");');
} else {
this._iconBin.hide();
}

View File

@@ -202,7 +202,7 @@ function gotExtensionZipFile(session, message, uuid) {
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
}
loadExtension(dir, ExtensionType.PER_USER, true);
loadExtension(dir, true, ExtensionType.PER_USER);
});
}

View File

@@ -35,8 +35,7 @@ const BaseIcon = new Lang.Class({
this.actor.set_child(box);
this.iconSize = ICON_SIZE;
this._iconBin = new St.Bin({ x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this._iconBin = new St.Bin();
box.add_actor(this._iconBin);
@@ -126,12 +125,12 @@ const BaseIcon = new Lang.Class({
this.iconSize = size;
this.icon = this.createIcon(this.iconSize);
this._iconBin.child = this.icon;
// The icon returned by createIcon() might actually be smaller than
// the requested icon size (for instance StTextureCache does this
// for fallback icons), so set the size explicitly.
this._iconBin.set_size(this.iconSize, this.iconSize);
this.icon.set_size(this.iconSize, this.iconSize);
this._iconBin.child = this.icon;
},
_onStyleChanged: function() {
@@ -146,11 +145,6 @@ const BaseIcon = new Lang.Class({
size = found ? len : ICON_SIZE;
}
// don't create icons unnecessarily
if (size == this.iconSize &&
this._iconBin.child)
return;
this._createIconTexture(size);
}
});

View File

@@ -433,9 +433,9 @@ const HotCorner = new Lang.Class({
Lang.bind(this, this._onCornerLeft));
// Cache the three ripples instead of dynamically creating and destroying them.
this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
Main.uiGroup.add_actor(this._ripple1);
Main.uiGroup.add_actor(this._ripple2);

View File

@@ -44,7 +44,7 @@ const Magnifier = new Lang.Class({
this._zoomRegions = [];
// Create small clutter tree for the magnified mouse.
let xfixesCursor = Shell.XFixesCursor.get_for_stage(global.stage);
let xfixesCursor = Shell.XFixesCursor.get_default();
this._mouseSprite = new Clutter.Texture();
xfixesCursor.update_texture_image(this._mouseSprite);
this._cursorRoot = new Clutter.Group();

View File

@@ -332,7 +332,6 @@ function _windowRemoved(workspace, window) {
workspace._lastRemovedWindow = null;
_queueCheckWorkspaces();
}
return false;
});
}

View File

@@ -1430,16 +1430,8 @@ const MessageTray = new Lang.Class({
this._notificationRemoved = false;
this._reNotifyAfterHideNotification = null;
this._corner = new Clutter.Rectangle({ width: 1,
height: 1,
opacity: 0,
reactive: true });
this._corner.connect('enter-event', Lang.bind(this, this._onCornerEnter));
Main.layoutManager.trayBox.add_actor(this._corner);
Main.layoutManager.trackChrome(this._corner);
Main.layoutManager.trayBox.add_actor(this.actor);
this.actor.y = this.actor.height;
this.actor.y = -1;
Main.layoutManager.trackChrome(this.actor);
Main.layoutManager.trackChrome(this._notificationBin);
@@ -1478,24 +1470,12 @@ const MessageTray = new Lang.Class({
this._chatSummaryItemsCount = 0;
},
_onCornerEnter: function(actor, event) {
this._pointerInSummary = true;
this._updateState();
},
_setSizePosition: function() {
let monitor = Main.layoutManager.bottomMonitor;
this._notificationBin.x = 0;
this._notificationBin.width = monitor.width;
this._summaryBin.x = 0;
this._summaryBin.width = monitor.width;
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
this._corner.x = 0;
else
this._corner.x = Main.layoutManager.trayBox.width - 1;
this._corner.y = Main.layoutManager.trayBox.height - 1;
},
contains: function(source) {
@@ -2096,7 +2076,7 @@ const MessageTray = new Lang.Class({
_hideTray: function() {
this._tween(this.actor, '_trayState', State.HIDDEN,
{ y: this.actor.height,
{ y: -1,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});

View File

@@ -94,7 +94,7 @@ const NotificationDaemon = new Lang.Class({
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
this._sources = [];
this._sources = {};
this._senderToPid = {};
this._notifications = {};
this._busProxy = new Bus();
@@ -152,30 +152,14 @@ const NotificationDaemon = new Lang.Class({
}
},
_lookupSource: function(title, pid, trayIcon) {
for (let i = 0; i < this._sources.length; i++) {
let source = this._sources[i];
if (source.pid == pid &&
(source.initialTitle == title || source.trayIcon || trayIcon))
return source;
}
return null;
},
// Returns the source associated with ndata.notification if it is set.
// Otherwise, returns the source associated with the title and pid if
// such source is stored in this._sources and the notification is not
// transient. If the existing or requested source is associated with
// a tray icon and passed in pid matches a pid of an existing source,
// the title match is ignored to enable representing a tray icon and
// notifications from the same application with a single source.
//
// If no existing source is found, a new source is created as long as
// pid is provided.
// Otherwise, returns the source associated with the pid if one is
// stored in this._sources and the notification is not transient.
// Otherwise, creates a new source as long as pid is provided.
//
// Either a pid or ndata.notification is needed to retrieve or
// create a source.
_getSource: function(title, pid, ndata, sender, trayIcon) {
_getSource: function(title, pid, ndata, sender) {
if (!pid && !(ndata && ndata.notification))
return null;
@@ -192,24 +176,20 @@ const NotificationDaemon = new Lang.Class({
// with a transient one from the same sender, so we
// always create a new source object for new transient notifications
// and never add it to this._sources .
if (!isForTransientNotification) {
let source = this._lookupSource(title, pid, trayIcon);
if (source) {
source.setTitle(title);
return source;
}
if (!isForTransientNotification && this._sources[pid]) {
let source = this._sources[pid];
source.setTitle(title);
return source;
}
let source = new Source(title, pid, sender, trayIcon);
let source = new Source(title, pid, sender);
source.setTransient(isForTransientNotification);
if (!isForTransientNotification) {
this._sources.push(source);
this._sources[pid] = source;
source.connect('destroy', Lang.bind(this,
function() {
let index = this._sources.indexOf(source);
if (index >= 0)
this._sources.splice(index, 1);
delete this._sources[pid];
}));
}
@@ -288,7 +268,7 @@ const NotificationDaemon = new Lang.Class({
let sender = invocation.get_sender();
let pid = this._senderToPid[sender];
let source = this._getSource(appName, pid, ndata, sender, null);
let source = this._getSource(appName, pid, ndata, sender);
if (source) {
this._notifyForSource(source, ndata);
@@ -314,7 +294,7 @@ const NotificationDaemon = new Lang.Class({
}
let [pid] = result;
source = this._getSource(appName, pid, ndata, sender, null);
source = this._getSource(appName, pid, ndata, sender);
// We only store sender-pid entries for persistent sources.
// Removing the entries once the source is destroyed
@@ -463,8 +443,8 @@ const NotificationDaemon = new Lang.Class({
if (!tracker.focus_app)
return;
for (let i = 0; i < this._sources.length; i++) {
let source = this._sources[i];
for (let id in this._sources) {
let source = this._sources[id];
if (source.app == tracker.focus_app) {
source.destroyNonResidentNotifications();
return;
@@ -483,11 +463,12 @@ const NotificationDaemon = new Lang.Class({
},
_onTrayIconAdded: function(o, icon) {
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null, icon);
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null);
source.setTrayIcon(icon);
},
_onTrayIconRemoved: function(o, icon) {
let source = this._lookupSource(null, icon.pid, true);
let source = this._sources[icon.pid];
if (source)
source.destroy();
}
@@ -497,12 +478,10 @@ const Source = new Lang.Class({
Name: 'NotificationDaemonSource',
Extends: MessageTray.Source,
_init: function(title, pid, sender, trayIcon) {
_init: function(title, pid, sender) {
this.parent(title);
this.initialTitle = title;
this.pid = pid;
this._pid = pid;
if (sender)
this._nameWatcherId = Gio.DBus.session.watch_name(sender,
Gio.BusNameWatcherFlags.NONE,
@@ -516,12 +495,7 @@ const Source = new Lang.Class({
this.title = this.app.get_name();
else
this.useNotificationIcon = true;
this.trayIcon = trayIcon;
if (this.trayIcon) {
this._setSummaryIcon(this.trayIcon);
this.useNotificationIcon = false;
}
this._trayIcon = null;
},
_onNameVanished: function() {
@@ -548,7 +522,7 @@ const Source = new Lang.Class({
},
handleSummaryClick: function() {
if (!this.trayIcon)
if (!this._trayIcon)
return false;
let event = Clutter.get_current_event();
@@ -569,11 +543,11 @@ const Source = new Lang.Class({
let id = global.connect('notify::stage-input-mode', Lang.bind(this,
function () {
global.disconnect(id);
this.trayIcon.click(event);
this._trayIcon.click(event);
}));
Main.overview.hide();
} else {
this.trayIcon.click(event);
this._trayIcon.click(event);
}
return true;
},
@@ -582,25 +556,31 @@ const Source = new Lang.Class({
if (this.app)
return;
this.app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
this.app = Shell.WindowTracker.get_default().get_app_from_pid(this._pid);
if (!this.app)
return;
// Only override the icon if we were previously using
// notification-based icons (ie, not a trayicon) or if it was unset before
if (!this.trayIcon) {
if (!this._trayIcon) {
this.useNotificationIcon = false;
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
}
},
setTrayIcon: function(icon) {
this._setSummaryIcon(icon);
this.useNotificationIcon = false;
this._trayIcon = icon;
},
open: function(notification) {
this.destroyNonResidentNotifications();
this.openApp();
},
_lastNotificationRemoved: function() {
if (!this.trayIcon)
if (!this._trayIcon)
this.destroy();
},

View File

@@ -23,7 +23,6 @@ const Params = imports.misc.params;
const PlaceDisplay = imports.ui.placeDisplay;
const Tweener = imports.ui.tweener;
const ViewSelector = imports.ui.viewSelector;
const Wanda = imports.ui.wanda;
const WorkspacesView = imports.ui.workspacesView;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
@@ -109,6 +108,7 @@ const Overview = new Lang.Class({
if (this.isDummy) {
this.animationInProgress = false;
this.visible = false;
this.workspaces = null;
return;
}
@@ -180,6 +180,8 @@ const Overview = new Lang.Class({
this._lastActiveWorkspaceIndex = -1;
this._lastHoveredWindow = null;
this._needsFakePointerEvent = false;
this.workspaces = null;
},
// The members we construct that are implemented in JS might
@@ -202,8 +204,6 @@ const Overview = new Lang.Class({
this._viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
// Default search providers
// Wanda comes obviously first
this.addSearchProvider(new Wanda.WandaSearchProvider());
this.addSearchProvider(new AppDisplay.AppSearchProvider());
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
@@ -587,10 +587,13 @@ const Overview = new Lang.Class({
this._workspacesDisplay.show();
this.workspaces = this._workspacesDisplay.workspacesView;
global.overlay_group.add_actor(this.workspaces.actor);
if (!this._desktopFade.child)
this._desktopFade.child = this._getDesktopClone();
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
this._desktopFade.opacity = 255;
this._desktopFade.show();
Tweener.addTween(this._desktopFade,
@@ -725,7 +728,7 @@ const Overview = new Lang.Class({
this.animationInProgress = true;
this._hideInProgress = true;
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
this._desktopFade.opacity = 0;
this._desktopFade.show();
Tweener.addTween(this._desktopFade,
@@ -734,7 +737,7 @@ const Overview = new Lang.Class({
transition: 'easeOutQuad' });
}
this._workspacesDisplay.zoomFromOverview();
this.workspaces.hide();
// Make other elements fade out.
Tweener.addTween(this._group,
@@ -776,6 +779,9 @@ const Overview = new Lang.Class({
global.window_group.show();
this.workspaces.destroy();
this.workspaces = null;
this._workspacesDisplay.hide();
this._desktopFade.hide();

View File

@@ -528,9 +528,6 @@ const AppMenuButton = new Lang.Class({
if (targetApp) {
this._appMenuNotifyId = targetApp.connect('notify::menu', Lang.bind(this, this._sync));
this._actionGroupNotifyId = targetApp.connect('notify::action-group', Lang.bind(this, this._sync));
} else {
this._appMenuNotifyId = 0;
this._actionGroupNotifyId = 0;
}
this._targetApp = targetApp;
@@ -552,7 +549,7 @@ const AppMenuButton = new Lang.Class({
_maybeSetMenu: function() {
let menu;
if (this._targetApp.action_group && this._targetApp.menu) {
if (this._targetApp.action_group) {
if (this.menu instanceof PopupMenu.RemoteMenu &&
this.menu.actionGroup == this._targetApp.action_group)
return;

View File

@@ -155,12 +155,9 @@ const PlacesManager = new Lang.Class({
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
function (size) {
// do NOT use St.Icon here, it crashes the shell
// see wanda.js for details
return St.TextureCache.get_default().load_icon_name('applications-internet',
null,
St.IconType.FULLCOLOR,
size);
return new St.Icon({ icon_name: 'applications-internet',
icon_type: St.IconType.FULLCOLOR,
icon_size: size });
},
function (params) {
// BUG: nautilus-connect-server doesn't have a desktop file, so we can't

View File

@@ -393,7 +393,6 @@ const AuthenticationAgent = new Lang.Class({
Lang.bind(this,
function() {
this._reallyCompleteRequest(wasDismissed);
return false;
}));
} else {
this._reallyCompleteRequest(wasDismissed);

View File

@@ -939,12 +939,7 @@ const PopupMenuBase = new Lang.Class({
this.emit('activate', menuItem);
this.close(true);
}));
// the weird name is to avoid a conflict with some random property
// the menuItem may have, called destroyId
// (FIXME: in the future it may make sense to have container objects
// like PopupMenuManager does)
menuItem._popupMenuDestroyId = menuItem.connect('destroy', Lang.bind(this, function(menuItem) {
menuItem.disconnect(menuItem._popupMenuDestroyId);
menuItem.connect('destroy', Lang.bind(this, function(emitter) {
menuItem.disconnect(menuItem._activateId);
menuItem.disconnect(menuItem._activeChangeId);
menuItem.disconnect(menuItem._sensitiveChangeId);
@@ -1398,23 +1393,12 @@ const PopupMenuSection = new Lang.Class({
this.actor = this.box;
this.actor._delegate = this;
this.isOpen = true;
// an array of externally managed separators
this.separators = [];
},
// deliberately ignore any attempt to open() or close(), but emit the
// corresponding signal so children can still pick it up
open: function(animate) { this.emit('open-state-changed', true); },
close: function() { this.emit('open-state-changed', false); },
destroy: function() {
for (let i = 0; i < this.separators.length; i++)
this.separators[i].destroy();
this.separators = [];
this.parent();
}
});
const PopupSubMenuMenuItem = new Lang.Class({
@@ -1748,25 +1732,17 @@ const RemoteMenu = new Lang.Class({
},
_createMenuItem: function(model, index) {
let labelValue = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null);
let label = labelValue ? labelValue.deep_unpack() : '';
// remove all underscores that are not followed by another underscore
label = label.replace(/_([^_])/, '$1');
let section_link = model.get_item_link(index, Gio.MENU_LINK_SECTION);
if (section_link) {
let item = new PopupMenuSection();
if (label) {
let title = new PopupMenuItem(label, { reactive: false,
style_class: 'popup-subtitle-menu-item' });
item._titleMenuItem = title;
title._ignored = true;
item.addMenuItem(title);
}
this._modelChanged(section_link, 0, 0, section_link.get_n_items(), item);
return [item, true, ''];
}
// labels are not checked for existance, as they're required for all items
let label = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null).deep_unpack();
// remove all underscores that are not followed by another underscore
label = label.replace(/_([^_])/, '$1');
let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU);
if (submenu_link) {
@@ -1850,13 +1826,8 @@ const RemoteMenu = new Lang.Class({
let currentItems = target._getMenuItems();
k0 = 0;
// skip ignored items at the beginning
while (k0 < currentItems.length && currentItems[k0]._ignored)
k0++;
// find the right menu item matching the model item
for (j0 = 0; j0 < position; j0++, k0++) {
if (currentItems[k0]._ignored)
for (j0 = 0, k0 = 0; j0 < position; j0++, k0++) {
if (currentItems[k0] instanceof PopupSeparatorMenuItem)
k0++;
}
@@ -1868,7 +1839,7 @@ const RemoteMenu = new Lang.Class({
for (j = j0, k = k0; j < j0 + removed; j++, k++) {
currentItems[k].destroy();
if (currentItems[k]._ignored)
if (currentItems[k] instanceof PopupSeparatorMenuItem)
j--;
}
}
@@ -1879,20 +1850,14 @@ const RemoteMenu = new Lang.Class({
if (item) {
// separators must be added in the parent to make autohiding work
if (addSeparator) {
let separator = new PopupSeparatorMenuItem();
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
target.addMenuItem(new PopupSeparatorMenuItem(), k+1);
k++;
}
target.addMenuItem(item, k);
if (addSeparator) {
let separator = new PopupSeparatorMenuItem();
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
target.addMenuItem(new PopupSeparatorMenuItem(), k+1);
k++;
}
} else if (changeSignal) {
@@ -1918,10 +1883,7 @@ const RemoteMenu = new Lang.Class({
}
if (target instanceof PopupMenuSection) {
if (target._titleMenuItem)
target.actor.visible = target.numMenuItems != 1;
else
target.actor.visible = target.numMenuItems != 0;
target.actor.visible = target.numMenuItems != 0;
} else {
let sourceItem = target.sourceActor._delegate;
if (sourceItem instanceof PopupSubMenuMenuItem)

View File

@@ -122,13 +122,8 @@ const GnomeShell = new Lang.Class({
* indicating whether the operation was successful or not.
*
*/
ScreenshotAreaAsync : function (params, invocation) {
let [x, y, width, height, filename, callback] = params;
global.screenshot_area (x, y, width, height, filename,
function (obj, result) {
let retval = GLib.Variant.new('(b)', [result]);
invocation.return_value(retval);
});
ScreenshotAreaAsync : function (x, y, width, height, filename, callback) {
global.screenshot_area (x, y, width, height, filename, function (obj, result) { callback(result); });
},
/**
@@ -154,13 +149,8 @@ const GnomeShell = new Lang.Class({
* indicating whether the operation was successful or not.
*
*/
ScreenshotAsync : function (params, invocation) {
let [filename] = params;
global.screenshot(filename,
function (obj, result) {
let retval = GLib.Variant.new('(b)', [result]);
invocation.return_value(retval);
});
ScreenshotAsync : function (filename, callback) {
global.screenshot(filename, function (obj, result) { callback(result); });
},
ListExtensions: function() {

View File

@@ -30,6 +30,7 @@ const Indicator = new Lang.Class({
_init: function() {
this.parent('bluetooth-disabled', null);
GLib.spawn_command_line_sync ('pkill -f "^bluetooth-applet$"');
this._applet = new GnomeBluetoothApplet.Applet();
this._killswitch = new PopupMenu.PopupSwitchMenuItem(_("Bluetooth"), false);

View File

@@ -249,11 +249,9 @@ const NMWirelessSectionTitleMenuItem = new Lang.Class({
updateForDevice: function(device) {
// we show the switch
// - if there not just one device
// - if the switch is off (but it can be turned on)
// - if the switch is off
// - if the device is activated or disconnected
if (!this._hardwareEnabled) {
this.setStatus(_("hardware disabled"));
} else if (device && this._softwareEnabled) {
if (device && this._softwareEnabled && this._hardwareEnabled) {
let text = device.getStatusLabel();
this.setStatus(text);
} else
@@ -329,7 +327,7 @@ const NMDevice = new Lang.Class({
}
this.section = new PopupMenu.PopupMenuSection();
this._deferredWorkId = Main.initializeDeferredWork(this.section.actor, Lang.bind(this, this._createSection));
this._createSection();
},
destroy: function() {
@@ -396,29 +394,16 @@ const NMDevice = new Lang.Class({
this._activeConnection = activeConnection;
this._clearSection();
this._queueCreateSection();
this._createSection();
},
checkConnection: function(connection) {
let pos = this._findConnection(connection._uuid);
let exists = pos != -1;
let exists = this._findConnection(connection._uuid) != -1;
let valid = this.connectionValid(connection);
if (exists && !valid)
this.removeConnection(connection);
else if (!exists && valid)
this.addConnection(connection);
else if (exists && valid) {
// propagate changes and update the UI
if (this._connections[pos].timestamp != connection._timestamp) {
this._connections[pos].timestamp = connection._timestamp;
this._connections.sort(this._connectionSortFunction);
this._clearSection();
this._queueCreateSection();
}
}
},
addConnection: function(connection) {
@@ -433,7 +418,7 @@ const NMDevice = new Lang.Class({
this._connections.sort(this._connectionSortFunction);
this._clearSection();
this._queueCreateSection();
this._createSection();
},
removeConnection: function(connection) {
@@ -457,7 +442,7 @@ const NMDevice = new Lang.Class({
// (or in the case of NMDeviceWired, we want to hide
// the only explicit connection)
this._clearSection();
this._queueCreateSection();
this._createSection();
}
},
@@ -541,11 +526,6 @@ const NMDevice = new Lang.Class({
return -1;
},
_queueCreateSection: function() {
this._clearSection();
Main.queueDeferredWork(this._deferredWorkId);
},
_clearSection: function() {
// Clear everything
this.section.removeAll();
@@ -640,7 +620,7 @@ const NMDevice = new Lang.Class({
this._updateStatusItem();
this._clearSection();
this._queueCreateSection();
this._createSection();
this.emit('state-changed');
},
@@ -884,12 +864,7 @@ const NMDeviceBluetooth = new Lang.Class({
this._autoConnectionName = this._makeConnectionName(this.device);
this._clearSection();
this._queueCreateSection();
this._updateStatusItem();
},
_getDescription: function() {
return this.device.name || _("Bluetooth");
this._createSection();
}
});
@@ -1234,6 +1209,7 @@ const NMDeviceWireless = new Lang.Class({
accessPoints: [ accessPoint ]
};
apObj.ssidText = ssidToLabel(apObj.ssid);
needsupdate = true;
}
// check if this enables new connections for this group
@@ -1248,13 +1224,37 @@ const NMDeviceWireless = new Lang.Class({
}
}
if (pos == -1 || needsupdate) {
if (needsupdate) {
if (apObj.item)
apObj.item.destroy();
if (pos != -1)
this._networks.splice(pos, 1);
pos = Util.insertSorted(this._networks, apObj, this._networkSortFunction);
this._clearSection();
this._queueCreateSection();
if (this._networks.length == 0) {
// only network in the list
this._networks.push(apObj);
this._clearSection();
this._createSection();
return;
}
// skip networks that should appear earlier
let menuPos = 0;
for (pos = 0;
pos < this._networks.length &&
this._networkSortFunction(this._networks[pos], apObj) < 0; ++pos) {
if (this._networks[pos] != this._activeNetwork)
menuPos++;
}
// (re-)add the network
this._networks.splice(pos, 0, apObj);
if (this._shouldShowConnectionList()) {
menuPos += (this._activeConnectionItem ? 1 : 0);
this._createNetworkItem(apObj, menuPos);
}
}
},
@@ -1341,7 +1341,7 @@ const NMDeviceWireless = new Lang.Class({
let obj = this._connections[pos];
this._connections.splice(pos, 1);
let forceupdate = false;
let anyauto = false, forceupdate = false;
for (let i = 0; i < this._networks.length; i++) {
let apObj = this._networks[i];
let connections = apObj.connections;
@@ -1349,14 +1349,16 @@ const NMDeviceWireless = new Lang.Class({
if (connections[k]._uuid == connection._uuid) {
// remove the connection from the access point group
connections.splice(k);
forceupdate = forceupdate || connections.length == 0;
anyauto = connections.length == 0;
if (forceupdate)
if (anyauto) {
// this potentially changes the sorting order
forceupdate = true;
break;
}
if (apObj.item) {
if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) {
let items = apObj.item.menu._getMenuItems();
let items = apObj.item.menu.getMenuItems();
if (items.length == 2) {
// we need to update the connection list to convert this to a normal item
forceupdate = true;
@@ -1378,10 +1380,10 @@ const NMDeviceWireless = new Lang.Class({
}
}
if (forceupdate) {
if (forceupdate || anyauto) {
this._networks.sort(this._networkSortFunction);
this._clearSection();
this._queueCreateSection();
this._createSection();
}
},
@@ -1414,13 +1416,13 @@ const NMDeviceWireless = new Lang.Class({
if (forceupdate) {
this._networks.sort(this._networkSortFunction);
this._clearSection();
this._queueCreateSection();
this._createSection();
}
},
_createActiveConnectionItem: function() {
let icon, title;
if (this._activeConnection && this._activeConnection._connection) {
if (this._activeConnection._connection) {
let connection = this._activeConnection._connection;
if (this._activeNetwork)
this._activeConnectionItem = new NMNetworkMenuItem(this._activeNetwork.accessPoints, undefined,
@@ -1513,7 +1515,7 @@ const NMDeviceWireless = new Lang.Class({
if (!this._shouldShowConnectionList())
return;
if (this._activeNetwork) {
if(this._activeConnection) {
this._createActiveConnectionItem();
this.section.addMenuItem(this._activeConnectionItem);
}
@@ -1522,10 +1524,8 @@ const NMDeviceWireless = new Lang.Class({
for(let j = 0; j < this._networks.length; j++) {
let apObj = this._networks[j];
if (apObj == this._activeNetwork) {
activeOffset--;
if (apObj == this._activeNetwork)
continue;
}
this._createNetworkItem(apObj, j + activeOffset);
}
@@ -1803,7 +1803,6 @@ const NMApplet = new Lang.Class({
let activating = null;
let default_ip4 = null;
let default_ip6 = null;
let active_vpn = null;
for (let i = 0; i < this._activeConnections.length; i++) {
let a = this._activeConnections[i];
@@ -1833,8 +1832,6 @@ const NMApplet = new Lang.Class({
default_ip4 = a;
if (a.default6)
default_ip6 = a;
if (a._type == 'vpn')
active_vpn = a;
if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
activating = a;
@@ -1865,7 +1862,7 @@ const NMApplet = new Lang.Class({
}
}
this._mainConnection = activating || active_vpn || default_ip4 || default_ip6 || this._activeConnections[0] || null;
this._mainConnection = activating || default_ip4 || default_ip6 || this._activeConnections[0] || null;
},
_notifyActivated: function(activeConnection) {

View File

@@ -33,6 +33,10 @@ const NotificationDirection = {
RECEIVED: 'chat-received'
};
let contactFeatures = [Tp.ContactFeature.ALIAS,
Tp.ContactFeature.AVATAR_DATA,
Tp.ContactFeature.PRESENCE];
// 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,
@@ -79,21 +83,11 @@ const Client = new Lang.Class({
// account path -> AccountNotification
this._accountNotifications = {};
// Define features we want
this._accountManager = Tp.AccountManager.dup();
let factory = this._accountManager.get_factory();
factory.add_account_features([Tp.Account.get_feature_quark_connection()]);
factory.add_connection_features([Tp.Connection.get_feature_quark_contact_list()]);
factory.add_channel_features([Tp.Channel.get_feature_quark_contacts()]);
factory.add_contact_features([Tp.ContactFeature.ALIAS,
Tp.ContactFeature.AVATAR_DATA,
Tp.ContactFeature.PRESENCE,
Tp.ContactFeature.SUBSCRIPTION_STATES]);
// Set up a SimpleObserver, which will call _observeChannels whenever a
// channel matching its filters is detected.
// The second argument, recover, means _observeChannels will be run
// for any existing channel as well.
this._accountManager = Tp.AccountManager.dup();
this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager,
'name': 'GnomeShell',
'uniquify-name': true })
@@ -120,9 +114,16 @@ const Client = new Lang.Class({
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
}
// Watch subscription requests and connection errors
this._subscriptionSource = null;
this._accountSource = null;
let factory = this._accountManager.get_factory();
factory.add_account_features([Tp.Account.get_feature_quark_connection()]);
factory.add_connection_features([Tp.Connection.get_feature_quark_contact_list()]);
factory.add_contact_features([Tp.ContactFeature.SUBSCRIPTION_STATES,
Tp.ContactFeature.ALIAS,
Tp.ContactFeature.AVATAR_DATA]);
this._accountManager.connect('account-validity-changed',
Lang.bind(this, this._accountValidityChanged));
@@ -132,6 +133,22 @@ const Client = new Lang.Class({
_observeChannels: function(observer, account, conn, channels,
dispatchOp, requests, context) {
// If the self_contact doesn't have the ALIAS, make sure
// to fetch it before trying to grab the channels.
let self_contact = conn.get_self_contact();
if (self_contact.has_feature(Tp.ContactFeature.ALIAS)) {
this._finishObserveChannels(account, conn, channels, context);
} else {
Shell.get_self_contact_features(conn,
contactFeatures,
Lang.bind(this, function() {
this._finishObserveChannels(account, conn, channels, context);
}));
context.delay();
}
},
_finishObserveChannels: function(account, conn, channels, context) {
let len = channels.length;
for (let i = 0; i < len; i++) {
let channel = channels[i];
@@ -142,7 +159,16 @@ const Client = new Lang.Class({
targetHandleType != Tp.HandleType.CONTACT)
continue;
this._createChatSource(account, conn, channel, channel.get_target_contact());
/* Request a TpContact */
Shell.get_tp_contacts(conn, [targetHandle],
contactFeatures,
Lang.bind(this, function (connection, contacts, failed) {
if (contacts.length < 1)
return;
/* We got the TpContact */
this._createChatSource(account, conn, channel, contacts[0]);
}), null);
}
context.accept();
@@ -171,11 +197,11 @@ const Client = new Lang.Class({
_handleChannels: function(handler, account, conn, channels,
requests, user_action_time, context) {
this._handlingChannels(account, conn, channels, true);
this._handlingChannels(account, conn, channels);
context.accept();
},
_handlingChannels: function(account, conn, channels, notify) {
_handlingChannels: function(account, conn, channels) {
let len = channels.length;
for (let i = 0; i < len; i++) {
let channel = channels[i];
@@ -186,18 +212,7 @@ const Client = new Lang.Class({
continue;
}
// 'notify' will be true when coming from an actual HandleChannels
// call, and not when from a successful Claim call. The point is
// we don't want to notify for a channel we just claimed which
// has no new messages (for example, a new channel which only has
// a delivery notification). We rely on _displayPendingMessages()
// and _messageReceived() to notify for new messages.
// But we should still notify from HandleChannels because the
// Telepathy spec states that handlers must foreground channels
// in HandleChannels calls which are already being handled.
if (notify && this._tpClient.is_handling_channel(channel)) {
if (this._tpClient.is_handling_channel(channel)) {
// We are already handling the channel, display the source
let source = this._chatSources[channel.get_object_path()];
if (source)
@@ -208,25 +223,41 @@ const Client = new Lang.Class({
_displayRoomInvitation: function(conn, channel, dispatchOp, context) {
// We can only approve the rooms if we have been invited to it
let selfContact = channel.group_get_self_contact();
if (selfContact == null) {
let selfHandle = channel.group_get_self_handle();
if (selfHandle == 0) {
Shell.decline_dispatch_op(context, 'Not invited to the room');
return;
}
let [invited, inviter, reason, msg] = channel.group_get_local_pending_contact_info(selfContact);
let [invited, inviter, reason, msg] = channel.group_get_local_pending_info(selfHandle);
if (!invited) {
Shell.decline_dispatch_op(context, 'Not invited to the room');
return;
}
// Request a TpContact for the inviter
Shell.get_tp_contacts(conn, [inviter],
contactFeatures,
Lang.bind(this, this._createRoomInviteSource, channel, context, dispatchOp));
context.delay();
},
_createRoomInviteSource: function(connection, contacts, failed, channel, context, dispatchOp) {
if (contacts.length < 1) {
Shell.decline_dispatch_op(context, 'Failed to get inviter');
return;
}
// We got the TpContact
// FIXME: We don't have a 'chat room' icon (bgo #653737) use
// system-users for now as Empathy does.
let source = new ApproverSource(dispatchOp, _("Invitation"),
Gio.icon_new_for_string('system-users'));
Main.messageTray.add(source);
let notif = new RoomInviteNotification(source, dispatchOp, channel, inviter);
let notif = new RoomInviteNotification(source, dispatchOp, channel, contacts[0]);
source.notify(notif);
context.accept();
},
@@ -254,7 +285,7 @@ const Client = new Lang.Class({
Lang.bind(this, function(dispatchOp, result) {
try {
dispatchOp.claim_with_finish(result);
this._handlingChannels(account, conn, [channel], false);
this._handlingChannels(account, conn, [channel]);
} catch (err) {
throw new Error('Failed to Claim channel: ' + err);
}}));
@@ -266,6 +297,21 @@ const Client = new Lang.Class({
},
_approveCall: function(account, conn, channel, dispatchOp, context) {
let [targetHandle, targetHandleType] = channel.get_handle();
Shell.get_tp_contacts(conn, [targetHandle],
contactFeatures,
Lang.bind(this, this._createAudioVideoSource, channel, context, dispatchOp));
context.delay();
},
_createAudioVideoSource: function(connection, contacts, failed, channel, context, dispatchOp) {
if (contacts.length < 1) {
Shell.decline_dispatch_op(context, 'Failed to get inviter');
return;
}
let isVideo = false;
let props = channel.borrow_immutable_properties();
@@ -280,13 +326,27 @@ const Client = new Lang.Class({
Gio.icon_new_for_string('audio-input-microphone'));
Main.messageTray.add(source);
let notif = new AudioVideoNotification(source, dispatchOp, channel,
channel.get_target_contact(), isVideo);
let notif = new AudioVideoNotification(source, dispatchOp, channel, contacts[0], isVideo);
source.notify(notif);
context.accept();
},
_approveFileTransfer: function(account, conn, channel, dispatchOp, context) {
let [targetHandle, targetHandleType] = channel.get_handle();
Shell.get_tp_contacts(conn, [targetHandle],
contactFeatures,
Lang.bind(this, this._createFileTransferSource, channel, context, dispatchOp));
context.delay();
},
_createFileTransferSource: function(connection, contacts, failed, channel, context, dispatchOp) {
if (contacts.length < 1) {
Shell.decline_dispatch_op(context, 'Failed to get file sender');
return;
}
// Use the icon of the file being transferred
let gicon = Gio.content_type_get_icon(channel.get_mime_type());
@@ -294,8 +354,7 @@ const Client = new Lang.Class({
let source = new ApproverSource(dispatchOp, _("File Transfer"), gicon);
Main.messageTray.add(source);
let notif = new FileTransferNotification(source, dispatchOp, channel,
channel.get_target_contact());
let notif = new FileTransferNotification(source, dispatchOp, channel, contacts[0]);
source.notify(notif);
context.accept();
},
@@ -443,9 +502,15 @@ const ChatSource = new Lang.Class({
this._notification.setUrgency(MessageTray.Urgency.HIGH);
this._notifyTimeoutId = 0;
// We ack messages when the user expands the new notification or views the summary
// notification, in which case the notification is also expanded.
this._notification.connect('expanded', Lang.bind(this, this._ackMessages));
// We ack messages when the message box is collapsed if user has
// interacted with it before and so read the messages:
// - user clicked on it the tray
// - user expanded the notification by hovering over the toaster notification
this._shouldAck = false;
this.connect('summary-item-clicked', Lang.bind(this, this._summaryItemClicked));
this._notification.connect('expanded', Lang.bind(this, this._notificationExpanded));
this._notification.connect('collapsed', Lang.bind(this, this._notificationCollapsed));
this._presence = contact.get_presence_type();
@@ -669,12 +734,12 @@ const ChatSource = new Lang.Class({
if (presence == Tp.ConnectionPresenceType.AVAILABLE) {
msg = _("%s is online.").format(title);
shouldNotify = (this._presence == Tp.ConnectionPresenceType.OFFLINE);
} else if (presence == Tp.ConnectionPresenceType.OFFLINE) {
} else if (presence == Tp.ConnectionPresenceType.OFFLINE ||
presence == Tp.ConnectionPresenceType.EXTENDED_AWAY) {
presence = Tp.ConnectionPresenceType.OFFLINE;
msg = _("%s is offline.").format(title);
shouldNotify = (this._presence != Tp.ConnectionPresenceType.OFFLINE);
} else if (presence == Tp.ConnectionPresenceType.AWAY ||
presence == Tp.ConnectionPresenceType.EXTENDED_AWAY) {
} else if (presence == Tp.ConnectionPresenceType.AWAY) {
msg = _("%s is away.").format(title);
shouldNotify = false;
} else if (presence == Tp.ConnectionPresenceType.BUSY) {
@@ -709,6 +774,24 @@ const ChatSource = new Lang.Class({
// 'pending-message-removed' for each one.
this._channel.ack_all_pending_messages_async(Lang.bind(this, function(src, result) {
this._channel.ack_all_pending_messages_finish(result);}));
},
_summaryItemClicked: function(source, button) {
if (button != 1)
return;
this._shouldAck = true;
},
_notificationExpanded: function() {
this._shouldAck = true;
},
_notificationCollapsed: function() {
if (this._shouldAck)
this._ackMessages();
this._shouldAck = false;
}
});

View File

@@ -239,8 +239,7 @@ const IMStatusChooserItem = new Lang.Class({
},
_setIconFromFile: function(iconFile) {
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
'background-size: contain;');
this._iconBin.set_style('background-image: url("' + iconFile + '");');
this._iconBin.child = null;
},

View File

@@ -419,6 +419,29 @@ const ViewSelector = new Lang.Class({
// not when setting the initially selected one.
if (!tab.visible)
tab.show(!firstSwitch);
// Pull a Meg Ryan:
if (!firstSwitch && Main.overview.workspaces) {
if (tab != this._tabs[0]) {
Tweener.addTween(Main.overview.workspaces.actor,
{ opacity: 0,
time: 0.1,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
Main.overview.workspaces.actor.hide();
Main.overview.workspaces.actor.opacity = 255;
})
});
} else {
Main.overview.workspaces.actor.opacity = 0;
Main.overview.workspaces.actor.show();
Tweener.addTween(Main.overview.workspaces.actor,
{ opacity: 255,
time: 0.1,
transition: 'easeOutQuad' });
}
}
},
switchTab: function(id) {

View File

@@ -1,210 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Search = imports.ui.search;
// we could make these gsettings
const FISH_NAME = 'wanda';
const FISH_SPEED = 300;
const FISH_COMMAND = 'fortune';
const GNOME_PANEL_PIXMAPDIR = '../gnome-panel/pixmaps';
const FISH_GROUP = 'Fish Animation';
const MAGIC_FISH_KEY = 'free the fish';
const WandaIcon = new Lang.Class({
Name: 'WandaIcon',
Extends: IconGrid.BaseIcon,
_init : function(fish, label, params) {
this._fish = fish;
let file = GLib.build_filenamev([global.datadir, GNOME_PANEL_PIXMAPDIR, fish + '.fish']);
if (GLib.file_test(file, GLib.FileTest.EXISTS)) {
this._keyfile = new GLib.KeyFile();
this._keyfile.load_from_file(file, GLib.KeyFileFlags.NONE);
this._imageFile = GLib.build_filenamev([global.datadir, GNOME_PANEL_PIXMAPDIR,
this._keyfile.get_string(FISH_GROUP, 'image')]);
let tmpPixbuf = GdkPixbuf.Pixbuf.new_from_file(this._imageFile);
this._imgHeight = tmpPixbuf.height;
this._imgWidth = tmpPixbuf.width / this._keyfile.get_integer(FISH_GROUP, 'frames');
} else {
this._imageFile = null;
}
this.parent(label, params);
},
createIcon: function(iconSize) {
if (this._animations)
this._animations.destroy();
if (!this._imageFile) {
return new St.Icon({ icon_name: 'face-smile',
icon_type: St.IconType.FULLCOLOR,
icon_size: iconSize
});
}
this._animations = St.TextureCache.get_default().load_sliced_image(this._imageFile, this._imgWidth, this._imgHeight);
this._animations.connect('destroy', Lang.bind(this, function() {
if (this._timeoutId)
GLib.source_remove(this._timeoutId);
this._timeoutId = 0;
this._animations = null;
}));
this._animations.connect('notify::mapped', Lang.bind(this, function() {
if (this._animations.mapped && !this._timeoutId) {
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, FISH_SPEED, Lang.bind(this, this._update));
this._i = 0;
this._update();
} else if (!this._animations.mapped && this._timeoutId) {
GLib.source_remove(this._timeoutId);
this._timeoutId = 0;
}
}));
this._i = 0;
return this._animations;
},
_update: function() {
let n = this._animations.get_n_children();
if (n == 0) {
return true;
}
this._animations.get_nth_child(this._i).hide();
this._i = (this._i + 1) % n;
this._animations.get_nth_child(this._i).show();
return true;
},
});
const WandaIconBin = new Lang.Class({
Name: 'WandaIconBin',
_init: function(fish, label, params) {
this.actor = new St.Bin({ style_class: 'search-result-content',
reactive: true,
track_hover: true });
this.icon = new WandaIcon(fish, label, params);
this.actor.child = this.icon.actor;
this.actor.label_actor = this.icon.label;
},
});
const FortuneDialog = new Lang.Class({
Name: 'FortuneDialog',
_init: function(name, command) {
let text;
try {
let [res, stdout, stderr, status] = GLib.spawn_command_line_sync(command);
text = String.fromCharCode.apply(null, stdout);
} catch(e) {
text = _("Sorry, no wisdom for you today:\n%s").format(e.message);
}
this._title = new St.Label({ style_class: 'polkit-dialog-headline',
text: _("%s the Oracle says").format(name) });
this._label = new St.Label({ style_class: 'polkit-dialog-description',
text: text });
this._label.clutter_text.line_wrap = true;
this._box = new St.BoxLayout({ vertical: true,
style_class: 'polkit-dialog' // this is just to force a reasonable width
});
this._box.add(this._title, { align: St.Align.MIDDLE });
this._box.add(this._label, { expand: true });
this._button = new St.Button({ button_mask: St.ButtonMask.ONE,
style_class: 'modal-dialog',
reactive: true });
this._button.connect('clicked', Lang.bind(this, this.destroy));
this._button.child = this._box;
let monitor = Main.layoutManager.primaryMonitor;
Main.layoutManager.addChrome(this._button);
this._button.set_position(Math.floor(monitor.width / 2 - this._button.width / 2),
Math.floor(monitor.height / 2 - this._button.height / 2));
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 10, Lang.bind(this, this.destroy));
},
destroy: function() {
this._button.destroy();
}
});
function capitalize(str) {
return str[0].toUpperCase() + str.substring(1, str.length);
}
const WandaSearchProvider = new Lang.Class({
Name: 'WandaSearchProvider',
Extends: Search.SearchProvider,
_init: function() {
this.parent(_("Your favorite Easter Egg"));
},
getResultMeta: function(fish) {
return { 'id': fish,
'name': capitalize(fish),
'createIcon': function(iconSize) {
// for DND only (maybe could be improved)
// DON'T use St.Icon here, it crashes the shell
// (dnd.js code assumes it can query the actor size
// without parenting it, while StWidget accesses
// StThemeNode in get_preferred_width/height, which
// triggers an assertion failure)
return St.TextureCache.get_default().load_icon_name(null,
'face-smile',
St.IconType.FULLCOLOR,
iconSize);
}
};
},
getInitialResultSet: function(terms) {
if (terms.join(' ') == MAGIC_FISH_KEY) {
return [ FISH_NAME ];
}
return [];
},
getSubsearchResultSet: function(previousResults, terms) {
return this.getInitialResultSet(terms);
},
activateResult: function(fish, params) {
if (this._dialog)
this._dialog.destroy();
this._dialog = new FortuneDialog(capitalize(fish), FISH_COMMAND);
},
createResultActor: function (resultMeta, terms) {
let icon = new WandaIconBin(resultMeta.id, resultMeta.name);
return icon.actor;
}
});

View File

@@ -23,8 +23,6 @@ const WINDOW_DND_SIZE = 256;
const SCROLL_SCALE_AMOUNT = 100 / 5;
const WINDOW_CLONE_MAXIMUM_SCALE = 0.7;
const LIGHTBOX_FADE_TIME = 0.1;
const CLOSE_BUTTON_FADE_TIME = 0.1;
@@ -96,11 +94,10 @@ const ScaledPoint = new Lang.Class({
const WindowClone = new Lang.Class({
Name: 'WindowClone',
_init : function(realWindow, workspace) {
_init : function(realWindow) {
this.realWindow = realWindow;
this.metaWindow = realWindow.meta_window;
this.metaWindow._delegate = this;
this._workspace = workspace;
let [borderX, borderY] = this._getInvisibleBorderPadding();
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture(),
@@ -386,12 +383,19 @@ const WindowClone = new Lang.Class({
this.emit('drag-begin');
},
_getWorkspaceActor : function() {
let index = this.metaWindow.get_workspace().index();
return Main.overview.workspaces.getWorkspaceByIndex(index);
},
handleDragOver : function(source, actor, x, y, time) {
return this._workspace.handleDragOver(source, actor, x, y, time);
let workspace = this._getWorkspaceActor();
return workspace.handleDragOver(source, actor, x, y, time);
},
acceptDrop : function(source, actor, x, y, time) {
this._workspace.acceptDrop(source, actor, x, y, time);
let workspace = this._getWorkspaceActor();
workspace.acceptDrop(source, actor, x, y, time);
},
_onDragCancelled : function (draggable, time) {
@@ -490,9 +494,6 @@ const WindowOverlay = new Lang.Class({
},
fadeIn: function() {
if (!this._hidden)
return;
this.show();
this.title.opacity = 0;
this._parentActor.raise_top();
@@ -521,7 +522,7 @@ const WindowOverlay = new Lang.Class({
// get_transformed_position() and get_transformed_size(),
// as windowClone might be moving.
// See Workspace._showWindowOverlay
updatePositions: function(cloneX, cloneY, cloneWidth, cloneHeight, animate) {
updatePositions: function(cloneX, cloneY, cloneWidth, cloneHeight) {
let button = this.closeButton;
let title = this.title;
@@ -543,34 +544,15 @@ const WindowOverlay = new Lang.Class({
else
buttonX = cloneX + (cloneWidth - button._overlap);
if (animate)
this._animateOverlayActor(button, Math.floor(buttonX), Math.floor(buttonY), button.width);
else
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
if (!title.fullWidth)
title.fullWidth = title.width;
let titleWidth = Math.min(title.fullWidth, cloneWidth);
title.width = Math.min(title.fullWidth, cloneWidth);
let titleX = cloneX + (cloneWidth - titleWidth) / 2;
let titleX = cloneX + (cloneWidth - title.width) / 2;
let titleY = cloneY + cloneHeight + title._spacing;
if (animate)
this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY), titleWidth);
else {
title.width = titleWidth;
title.set_position(Math.floor(titleX), Math.floor(titleY));
}
},
_animateOverlayActor: function(actor, x, y, width) {
Tweener.addTween(actor,
{ x: x,
y: y,
width: width,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad'
});
title.set_position(Math.floor(titleX), Math.floor(titleY));
},
_closeWindow: function(actor) {
@@ -966,7 +948,7 @@ const Workspace = new Lang.Class({
let scale = Math.min((width - buttonOuterWidth) / rect.width,
(height - buttonOuterHeight - captionHeight) / rect.height,
WINDOW_CLONE_MAXIMUM_SCALE);
1.0);
x = Math.floor(x + (width - scale * rect.width) / 2);
@@ -1035,7 +1017,7 @@ const Workspace = new Lang.Class({
let [x, y, scale] = this._computeWindowLayout(metaWindow, slot);
if (overlay && initialPositioning)
if (overlay)
overlay.hide();
if (animate && isOnCurrentWorkspace) {
if (!metaWindow.showing_on_its_workspace()) {
@@ -1058,11 +1040,20 @@ const Workspace = new Lang.Class({
});
}
this._animateClone(clone, overlay, x, y, scale, initialPositioning);
Tweener.addTween(clone.actor,
{ x: x,
y: y,
scale_x: scale,
scale_y: scale,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._showWindowOverlay(clone, overlay, true);
})
});
} else {
clone.actor.set_position(x, y);
clone.actor.set_scale(scale, scale);
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
}
}
@@ -1084,35 +1075,23 @@ const Workspace = new Lang.Class({
}
},
_animateClone: function(clone, overlay, x, y, scale, initialPositioning) {
Tweener.addTween(clone.actor,
{ x: x,
y: y,
scale_x: scale,
scale_y: scale,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._showWindowOverlay(clone, overlay, true);
})
});
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, true);
},
_updateWindowOverlayPositions: function(clone, overlay, x, y, scale, animate) {
let [cloneWidth, cloneHeight] = clone.actor.get_size();
cloneWidth = scale * cloneWidth;
cloneHeight = scale * cloneHeight;
if (overlay)
overlay.updatePositions(x, y, cloneWidth, cloneHeight, animate);
},
_showWindowOverlay: function(clone, overlay, fade) {
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
// all animations before calling onComplete callbacks.)
// So we need to manually compute where the window will
// be after the workspace animation finishes.
let [cloneX, cloneY] = clone.actor.get_position();
let [cloneWidth, cloneHeight] = clone.actor.get_size();
cloneWidth = clone.actor.scale_x * cloneWidth;
cloneHeight = clone.actor.scale_y * cloneHeight;
if (overlay) {
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
if (fade)
overlay.fadeIn();
else
@@ -1130,16 +1109,6 @@ const Workspace = new Lang.Class({
}
},
_hideAllOverlays: function() {
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
Tweener.removeTweens(clone.actor);
let overlay = this._windowOverlays[i];
if (overlay)
overlay.hide();
}
},
_delayedWindowRepositioning: function() {
if (this._windowIsZooming)
return true;
@@ -1157,16 +1126,22 @@ const Workspace = new Lang.Class({
return true;
}
let actorUnderPointer = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
for (let i = 0; i < this._windows.length; i++) {
if (this._windows[i].actor == actorUnderPointer)
return true;
}
this.positionWindows(WindowPositionFlags.ANIMATE);
return false;
},
showWindowsOverlays: function() {
if (this.leavingOverview)
return;
this._windowOverlaysGroup.show();
this._showAllOverlays();
},
hideWindowsOverlays: function() {
this._windowOverlaysGroup.hide();
},
_doRemoveWindow : function(metaWin) {
let win = metaWin.get_compositor_private();
@@ -1320,7 +1295,7 @@ const Workspace = new Lang.Class({
this.leavingOverview = true;
this._hideAllOverlays();
this.hideWindowsOverlays();
if (this._repositionWindowsId > 0) {
Mainloop.source_remove(this._repositionWindowsId);
@@ -1411,7 +1386,7 @@ const Workspace = new Lang.Class({
// Create a clone of a (non-desktop) window and add it to the window list
_addWindowClone : function(win) {
let clone = new WindowClone(win, this);
let clone = new WindowClone(win);
let overlay = new WindowOverlay(clone, this._windowOverlaysGroup);
clone.connect('selected',

View File

@@ -51,7 +51,6 @@ const WindowClone = new Lang.Class({
dragActorMaxSize: Workspace.WINDOW_DND_SIZE,
dragActorOpacity: Workspace.DRAGGING_WINDOW_OPACITY });
this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
this._draggable.connect('drag-cancelled', Lang.bind(this, this._onDragCancelled));
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
this.inDrag = false;
},
@@ -109,10 +108,6 @@ const WindowClone = new Lang.Class({
this.emit('drag-begin');
},
_onDragCancelled : function (draggable, time) {
this.emit('drag-cancelled');
},
_onDragEnd : function (draggable, time, snapback) {
this.inDrag = false;
@@ -154,8 +149,6 @@ const WorkspaceThumbnail = new Lang.Class({
this.metaWorkspace = metaWorkspace;
this.monitorIndex = Main.layoutManager.primaryIndex;
this._removed = false;
this.actor = new St.Group({ reactive: true,
clip_to_allocation: true,
style_class: 'workspace-thumbnail' });
@@ -181,21 +174,17 @@ const WorkspaceThumbnail = new Lang.Class({
let monitor = Main.layoutManager.primaryMonitor;
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
let windows = global.get_window_actors().filter(this._isWorkspaceWindow, this);
let windows = global.get_window_actors().filter(this._isMyWindow, this);
// Create clones for windows that should be visible in the Overview
this._windows = [];
this._allWindows = [];
this._minimizedChangedIds = [];
for (let i = 0; i < windows.length; i++) {
let minimizedChangedId =
windows[i].meta_window._minimizedChangedId =
windows[i].meta_window.connect('notify::minimized',
Lang.bind(this,
this._updateMinimized));
this._allWindows.push(windows[i].meta_window);
this._minimizedChangedIds.push(minimizedChangedId);
if (this._isMyWindow(windows[i]) && this._isOverviewWindow(windows[i])) {
if (this._isOverviewWindow(windows[i])) {
this._addWindowClone(windows[i]);
}
}
@@ -280,11 +269,17 @@ const WorkspaceThumbnail = new Lang.Class({
let clone = this._windows[index];
this._windows.splice(index, 1);
if (win && this._isOverviewWindow(win)) {
if (metaWin._minimizedChangedId) {
metaWin.disconnect(metaWin._minimizedChangedId);
delete metaWin._minimizedChangedId;
}
}
clone.destroy();
},
_doAddWindow : function(metaWin) {
if (this._removed)
if (this.leavingOverview)
return;
let win = metaWin.get_compositor_private();
@@ -294,7 +289,7 @@ const WorkspaceThumbnail = new Lang.Class({
// the compositor finds out about them...
Mainloop.idle_add(Lang.bind(this,
function () {
if (!this._removed &&
if (this.actor &&
metaWin.get_compositor_private() &&
metaWin.get_workspace() == this.metaWorkspace)
this._doAddWindow(metaWin);
@@ -303,19 +298,16 @@ const WorkspaceThumbnail = new Lang.Class({
return;
}
if (this._allWindows.indexOf(metaWin) == -1) {
let minimizedChangedId = metaWin.connect('notify::minimized',
Lang.bind(this,
this._updateMinimized));
this._allWindows.push(metaWin);
this._minimizedChangedIds.push(minimizedChangedId);
}
// We might have the window in our list already if it was on all workspaces and
// now was moved to this workspace
if (this._lookupIndex (metaWin) != -1)
return;
if (!metaWin._minimizedChangedId)
metaWin._minimizedChangedId = metaWin.connect('notify::minimized',
Lang.bind(this,
this._updateMinimized));
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
return;
@@ -327,13 +319,6 @@ const WorkspaceThumbnail = new Lang.Class({
},
_windowRemoved : function(metaWorkspace, metaWin) {
let index = this._allWindows.indexOf(metaWin);
if (index != -1) {
metaWin.disconnect(this._minimizedChangedIds[index]);
this._allWindows.splice(index, 1);
this._minimizedChangedIds.splice(index, 1);
}
this._doRemoveWindow(metaWin);
},
@@ -360,36 +345,27 @@ const WorkspaceThumbnail = new Lang.Class({
this.actor.destroy();
},
workspaceRemoved : function() {
if (this._removed)
return;
this._removed = true;
_onDestroy: function(actor) {
this.metaWorkspace.disconnect(this._windowAddedId);
this.metaWorkspace.disconnect(this._windowRemovedId);
global.screen.disconnect(this._windowEnteredMonitorId);
global.screen.disconnect(this._windowLeftMonitorId);
for (let i = 0; i < this._allWindows.length; i++)
this._allWindows[i].disconnect(this._minimizedChangedIds[i]);
},
_onDestroy: function(actor) {
this.workspaceRemoved();
for (let i = 0; i < this._windows.length; i++) {
let metaWin = this._windows[i].metaWindow;
if (metaWin._minimizedChangedId) {
metaWin.disconnect(metaWin._minimizedChangedId);
delete metaWin._minimizedChangedId;
}
}
this._windows = [];
this.actor = null;
},
// Tests if @win belongs to this workspace
_isWorkspaceWindow : function (win) {
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index());
},
// Tests if @win belongs to this workspace and monitor
_isMyWindow : function (win) {
return this._isWorkspaceWindow(win) &&
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index()) &&
(!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex);
},
@@ -410,10 +386,6 @@ const WorkspaceThumbnail = new Lang.Class({
Lang.bind(this, function(clone) {
Main.overview.beginWindowDrag();
}));
clone.connect('drag-cancelled',
Lang.bind(this, function(clone) {
Main.overview.cancelledWindowDrag();
}));
clone.connect('drag-end',
Lang.bind(this, function(clone) {
Main.overview.endWindowDrag();
@@ -547,59 +519,6 @@ const ThumbnailsBox = new Lang.Class({
this._stateCounts[ThumbnailState[key]] = 0;
this._thumbnails = [];
Main.overview.connect('item-drag-begin',
Lang.bind(this, this._onDragBegin));
Main.overview.connect('item-drag-end',
Lang.bind(this, this._onDragEnd));
Main.overview.connect('item-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
Main.overview.connect('window-drag-begin',
Lang.bind(this, this._onDragBegin));
Main.overview.connect('window-drag-end',
Lang.bind(this, this._onDragEnd));
Main.overview.connect('window-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
},
_onDragBegin: function() {
this._dragCancelled = false;
this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion)
};
DND.addDragMonitor(this._dragMonitor);
},
_onDragEnd: function() {
if (this._dragCancelled)
return;
this._endDrag();
},
_onDragCancelled: function() {
this._dragCancelled = true;
this._endDrag();
},
_endDrag: function() {
this._clearDragPlaceholder();
DND.removeDragMonitor(this._dragMonitor);
},
_onDragMotion: function(dragEvent) {
if (!this.actor.contains(dragEvent.targetActor))
this._onLeave();
return DND.DragMotionResult.CONTINUE;
},
_onLeave: function() {
this._clearDragPlaceholder();
},
_clearDragPlaceholder: function() {
this._dropPlaceholderPos = -1;
this.actor.queue_relayout();
},
// Draggable target interface
@@ -751,10 +670,8 @@ const ThumbnailsBox = new Lang.Class({
if (thumbnail.state > ThumbnailState.NORMAL)
continue;
if (currentPos >= start && currentPos < start + count) {
thumbnail.workspaceRemoved();
if (currentPos >= start && currentPos < start + count)
this._setThumbnailState(thumbnail, ThumbnailState.REMOVING);
}
currentPos++;
}

View File

@@ -1,7 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
@@ -20,7 +19,6 @@ const WORKSPACE_SWITCH_TIME = 0.25;
// Note that mutter has a compile-time limit of 36
const MAX_WORKSPACES = 16;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
const CONTROLS_POP_IN_TIME = 0.1;
@@ -42,6 +40,8 @@ const WorkspacesView = new Lang.Class({
this._spacing = node.get_length('spacing');
this._updateWorkspaceActors(false);
}));
this.actor.connect('notify::mapped',
Lang.bind(this, this._onMappedChanged));
this._width = 0;
this._height = 0;
@@ -59,11 +59,6 @@ const WorkspacesView = new Lang.Class({
this._zoomOut = false; // zoom to a larger area
this._inDrag = false; // dragging a window
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._updateExtraWorkspacesId =
this._settings.connect('changed::workspaces-only-on-primary',
Lang.bind(this, this._updateExtraWorkspaces));
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
this._workspaces = workspaces;
@@ -72,7 +67,17 @@ const WorkspacesView = new Lang.Class({
this._workspaces[w].actor.reparent(this.actor);
this._workspaces[activeWorkspaceIndex].actor.raise_top();
this._updateExtraWorkspaces();
this._extraWorkspaces = [];
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == Main.layoutManager.primaryIndex)
continue;
let ws = new Workspace.Workspace(null, i);
this._extraWorkspaces[m++] = ws;
ws.setGeometry(monitors[i].x, monitors[i].y, monitors[i].width, monitors[i].height);
global.overlay_group.add_actor(ws.actor);
}
// Position/scale the desktop windows and their children after the
// workspaces have been created. This cannot be done first because
@@ -83,8 +88,6 @@ const WorkspacesView = new Lang.Class({
Lang.bind(this, function() {
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomToOverview();
if (!this._extraWorkspaces)
return;
for (let w = 0; w < this._extraWorkspaces.length; w++)
this._extraWorkspaces[w].zoomToOverview();
}));
@@ -95,14 +98,14 @@ const WorkspacesView = new Lang.Class({
this._clipWidth, this._clipHeight);
}));
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
lower: 0,
page_increment: 1,
page_size: 1,
step_increment: 0,
upper: this._workspaces.length });
this.scrollAdjustment.connect('notify::value',
Lang.bind(this, this._onScroll));
this._scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
lower: 0,
page_increment: 1,
page_size: 1,
step_increment: 0,
upper: this._workspaces.length });
this._scrollAdjustment.connect('notify::value',
Lang.bind(this, this._onScroll));
this._switchWorkspaceNotifyId =
global.window_manager.connect('switch-workspace',
@@ -116,35 +119,8 @@ const WorkspacesView = new Lang.Class({
Lang.bind(this, this._dragBegin));
this._windowDragEndId = Main.overview.connect('window-drag-end',
Lang.bind(this, this._dragEnd));
},
_updateExtraWorkspaces: function() {
this._destroyExtraWorkspaces();
if (!this._settings.get_boolean('workspaces-only-on-primary'))
return;
this._extraWorkspaces = [];
let monitors = Main.layoutManager.monitors;
for (let i = 0; i < monitors.length; i++) {
if (i == Main.layoutManager.primaryIndex)
continue;
let ws = new Workspace.Workspace(null, i);
ws.setGeometry(monitors[i].x, monitors[i].y,
monitors[i].width, monitors[i].height);
global.overlay_group.add_actor(ws.actor);
this._extraWorkspaces.push(ws);
}
},
_destroyExtraWorkspaces: function() {
if (!this._extraWorkspaces)
return;
for (let m = 0; m < this._extraWorkspaces.length; m++)
this._extraWorkspaces[m].destroy();
this._extraWorkspaces = null;
this._swipeScrollBeginId = 0;
this._swipeScrollEndId = 0;
},
setGeometry: function(x, y, width, height, spacing) {
@@ -181,6 +157,10 @@ const WorkspacesView = new Lang.Class({
return this._workspaces[active];
},
getWorkspaceByIndex: function(index) {
return this._workspaces[index];
},
hide: function() {
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
@@ -191,8 +171,6 @@ const WorkspacesView = new Lang.Class({
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomFromOverview();
if (!this._extraWorkspaces)
return;
for (let w = 0; w < this._extraWorkspaces.length; w++)
this._extraWorkspaces[w].zoomFromOverview();
},
@@ -204,8 +182,6 @@ const WorkspacesView = new Lang.Class({
syncStacking: function(stackIndices) {
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].syncStacking(stackIndices);
if (!this._extraWorkspaces)
return;
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].syncStacking(stackIndices);
},
@@ -267,8 +243,10 @@ const WorkspacesView = new Lang.Class({
for (let w = 0; w < this._workspaces.length; w++) {
let workspace = this._workspaces[w];
if (this._animating || this._scrolling) {
workspace.hideWindowsOverlays();
workspace.actor.show();
} else {
workspace.showWindowsOverlays();
if (this._inDrag)
workspace.actor.visible = (Math.abs(w - active) <= 1);
else
@@ -284,7 +262,7 @@ const WorkspacesView = new Lang.Class({
this._animatingScroll = true;
if (showAnimation) {
Tweener.addTween(this.scrollAdjustment, {
Tweener.addTween(this._scrollAdjustment, {
value: index,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad',
@@ -294,7 +272,7 @@ const WorkspacesView = new Lang.Class({
})
});
} else {
this.scrollAdjustment.value = index;
this._scrollAdjustment.value = index;
this._animatingScroll = false;
}
},
@@ -302,7 +280,7 @@ const WorkspacesView = new Lang.Class({
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
let active = global.screen.get_active_workspace_index();
Tweener.addTween(this.scrollAdjustment,
Tweener.addTween(this._scrollAdjustment,
{ upper: newNumWorkspaces,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad'
@@ -329,12 +307,12 @@ const WorkspacesView = new Lang.Class({
},
_onDestroy: function() {
this._destroyExtraWorkspaces();
this.scrollAdjustment.run_dispose();
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].destroy();
this._scrollAdjustment.run_dispose();
Main.overview.disconnect(this._overviewShowingId);
Main.overview.disconnect(this._overviewShownId);
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
this._settings.disconnect(this._updateExtraWorkspacesId);
if (this._inDrag)
this._dragEnd();
@@ -357,6 +335,21 @@ const WorkspacesView = new Lang.Class({
}
},
_onMappedChanged: function() {
if (this.actor.mapped) {
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(this._scrollAdjustment,
direction);
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
Lang.bind(this, this._swipeScrollBegin));
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
Lang.bind(this, this._swipeScrollEnd));
} else {
Main.overview.disconnect(this._swipeScrollBeginId);
Main.overview.disconnect(this._swipeScrollEndId);
}
},
_dragBegin: function() {
if (this._scrolling)
return;
@@ -378,9 +371,6 @@ const WorkspacesView = new Lang.Class({
this._firstDragMotion = false;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
if (!this._extraWorkspaces)
return DND.DragMotionResult.CONTINUE;
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
}
@@ -394,18 +384,15 @@ const WorkspacesView = new Lang.Class({
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(null);
if (!this._extraWorkspaces)
return;
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].setReservedSlot(null);
},
startSwipeScroll: function() {
_swipeScrollBegin: function() {
this._scrolling = true;
},
endSwipeScroll: function(result) {
_swipeScrollEnd: function(overview, result) {
this._scrolling = false;
if (result == Overview.SwipeScrollResult.CLICK) {
@@ -454,6 +441,7 @@ const WorkspacesView = new Lang.Class({
let dy = newY - currentY;
for (let i = 0; i < this._workspaces.length; i++) {
this._workspaces[i].hideWindowsOverlays();
this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
this._workspaces[i].actor.y += dy;
}
@@ -474,8 +462,6 @@ const WorkspacesDisplay = new Lang.Class({
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate', Lang.bind(this, this._allocate));
this.actor.connect('notify::mapped', Lang.bind(this, this._setupSwipeScrolling));
this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
this.actor.set_clip_to_allocation(true);
let controls = new St.Bin({ style_class: 'workspace-controls',
@@ -492,19 +478,12 @@ const WorkspacesDisplay = new Lang.Class({
controls.connect('scroll-event',
Lang.bind(this, this._onScrollEvent));
this._primaryIndex = Main.layoutManager.primaryIndex;
this._monitorIndex = Main.layoutManager.primaryIndex;
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
controls.add_actor(this._thumbnailsBox.actor);
this._workspacesViews = null;
this._primaryScrollAdjustment = null;
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._settings.connect('changed::workspaces-only-on-primary',
Lang.bind(this,
this._workspacesOnlyOnPrimaryChanged));
this._workspacesOnlyOnPrimaryChanged();
this.workspacesView = null;
this._inDrag = false;
this._cancelledDrag = false;
@@ -515,8 +494,6 @@ const WorkspacesDisplay = new Lang.Class({
this._updateAlwaysZoom();
// If we stop hiding the overview on layout changes, we will need to
// update the _workspacesViews here
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
@@ -537,9 +514,6 @@ const WorkspacesDisplay = new Lang.Class({
this._windowDragBeginId = 0;
this._windowDragCancelledId = 0;
this._windowDragEndId = 0;
this._notifyOpacityId = 0;
this._swipeScrollBeginId = 0;
this._swipeScrollEndId = 0;
},
show: function() {
@@ -550,7 +524,16 @@ const WorkspacesDisplay = new Lang.Class({
this._controls.show();
this._thumbnailsBox.show();
this._updateWorkspacesViews();
this._workspaces = [];
for (let i = 0; i < global.screen.n_workspaces; i++) {
let metaWorkspace = global.screen.get_workspace_by_index(i);
this._workspaces[i] = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
}
if (this.workspacesView)
this.workspacesView.destroy();
this.workspacesView = new WorkspacesView(this._workspaces);
this._updateWorkspacesGeometry();
this._restackedNotifyId =
global.screen.connect('restacked',
@@ -581,12 +564,6 @@ const WorkspacesDisplay = new Lang.Class({
this._onRestacked();
},
zoomFromOverview: function() {
for (let i = 0; i < this._workspacesViews.length; i++) {
this._workspacesViews[i].hide();
}
},
hide: function() {
this._controls.hide();
this._thumbnailsBox.hide();
@@ -620,120 +597,12 @@ const WorkspacesDisplay = new Lang.Class({
this._windowDragEndId = 0;
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy();
this._workspacesViews = null;
for (let i = 0; i < this._workspaces.length; i++)
for (let w = 0; w < this._workspaces[i].length; w++) {
this._workspaces[i][w].disconnectAll();
this._workspaces[i][w].destroy();
}
},
_setupSwipeScrolling: function() {
if (this._swipeScrollBeginId)
Main.overview.disconnect(this._swipeScrollBeginId);
this._swipeScrollBeginId = 0;
if (this._swipeScrollEndId)
Main.overview.disconnect(this._swipeScrollEndId);
this._swipeScrollEndId = 0;
if (!this.actor.mapped)
return;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(this._scrollAdjustment,
direction);
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
Lang.bind(this, function() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].startSwipeScroll();
}));
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
Lang.bind(this, function(overview, result) {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll(result);
}));
},
_workspacesOnlyOnPrimaryChanged: function() {
this._workspacesOnlyOnPrimary = this._settings.get_boolean('workspaces-only-on-primary');
if (!Main.overview.visible)
return;
this._updateWorkspacesViews();
},
_updateWorkspacesViews: function() {
if (this._workspacesViews)
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy();
if (this._workspaces)
for (let i = 0; i < this._workspaces.length; i++)
for (let w = 0; w < this._workspaces[i].length; w++)
this._workspaces[i][w].destroy();
this._workspacesViews = [];
this._workspaces = [];
let monitors = Main.layoutManager.monitors;
for (let i = 0; i < monitors.length; i++) {
if (this._workspacesOnlyOnPrimary && i != this._primaryIndex)
continue; // we are only interested in the primary monitor
let monitorWorkspaces = [];
for (let w = 0; w < global.screen.n_workspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
monitorWorkspaces.push(new Workspace.Workspace(metaWorkspace, i));
}
this._workspaces.push(monitorWorkspaces);
let view = new WorkspacesView(monitorWorkspaces);
if (this._workspacesOnlyOnPrimary || i == this._primaryIndex) {
this._scrollAdjustment = view.scrollAdjustment;
this._scrollAdjustment.connect('notify::value',
Lang.bind(this, this._scrollValueChanged));
this._setupSwipeScrolling();
}
this._workspacesViews.push(view);
this.workspacesView.destroy();
this.workspacesView = null;
for (let w = 0; w < this._workspaces.length; w++) {
this._workspaces[w].disconnectAll();
this._workspaces[w].destroy();
}
this._updateWorkspacesGeometry();
for (let i = 0; i < this._workspacesViews.length; i++)
global.overlay_group.add_actor(this._workspacesViews[i].actor);
},
_scrollValueChanged: function() {
if (this._workspacesOnlyOnPrimary)
return;
for (let i = 0; i < this._workspacesViews.length; i++) {
if (i == this._primaryIndex)
continue;
let adjustment = this._workspacesViews[i].scrollAdjustment;
// the adjustments work in terms of workspaces, so the
// values map directly
adjustment.value = this._scrollAdjustment.value;
}
},
_getPrimaryView: function() {
if (!this._workspacesViews)
return null;
if (this._workspacesOnlyOnPrimary)
return this._workspacesViews[0];
else
return this._workspacesViews[this._primaryIndex];
},
activeWorkspaceHasMaximizedWindows: function() {
return this._getPrimaryView().getActiveWorkspace().hasMaximizedWindows();
},
// zoomFraction property allows us to tween the controls sliding in and out
@@ -806,37 +675,8 @@ const WorkspacesDisplay = new Lang.Class({
this._updateWorkspacesGeometry();
},
_parentSet: function(actor, oldParent) {
if (oldParent && this._notifyOpacityId)
oldParent.disconnect(this._notifyOpacityId);
this._notifyOpacityId = 0;
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
function() {
let newParent = this.actor.get_parent();
if (!newParent)
return;
// This is kinda hackish - we want the primary view to
// appear as parent of this.actor, though in reality it
// is added directly to overlay_group
this._notifyOpacityId = newParent.connect('notify::opacity',
Lang.bind(this, function() {
let opacity = this.actor.get_parent().opacity;
let primaryView = this._getPrimaryView();
if (!primaryView)
return;
primaryView.actor.opacity = opacity;
if (opacity == 0)
primaryView.actor.hide();
else
primaryView.actor.show();
}));
}));
},
_updateWorkspacesGeometry: function() {
if (!this._workspacesViews)
if (!this.workspacesView)
return;
let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
@@ -857,6 +697,8 @@ const WorkspacesDisplay = new Lang.Class({
let clipX = rtl ? x + controlsVisible : x;
let clipY = y + (fullHeight - clipHeight) / 2;
this.workspacesView.setClipRect(clipX, clipY, clipWidth, clipHeight);
if (this._zoomOut) {
width -= controlsNatural;
if (rtl)
@@ -871,28 +713,7 @@ const WorkspacesDisplay = new Lang.Class({
let difference = fullHeight - height;
y += difference / 2;
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == this._primaryIndex) {
this._workspacesViews[m].setClipRect(clipX, clipY,
clipWidth, clipHeight);
this._workspacesViews[m].setGeometry(x, y, width, height,
difference);
m++;
} else if (!this._workspacesOnlyOnPrimary) {
this._workspacesViews[m].setClipRect(monitors[i].x,
monitors[i].y,
monitors[i].width,
monitors[i].height);
this._workspacesViews[m].setGeometry(monitors[i].x,
monitors[i].y,
monitors[i].width,
monitors[i].height, 0);
m++;
}
}
this.workspacesView.setGeometry(x, y, width, height, difference);
},
_onRestacked: function() {
@@ -904,14 +725,12 @@ const WorkspacesDisplay = new Lang.Class({
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].syncStacking(stackIndices);
this.workspacesView.syncStacking(stackIndices);
this._thumbnailsBox.syncStacking(stackIndices);
},
_workspacesChanged: function() {
let oldNumWorkspaces = this._workspaces[0].length;
let oldNumWorkspaces = this._workspaces.length;
let newNumWorkspaces = global.screen.n_workspaces;
let active = global.screen.get_active_workspace_index();
@@ -921,24 +740,15 @@ const WorkspacesDisplay = new Lang.Class({
this._updateAlwaysZoom();
this._updateZoom();
if (this._workspacesViews == null)
if (this.workspacesView == null)
return;
let lostWorkspaces = [];
if (newNumWorkspaces > oldNumWorkspaces) {
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (this._workspacesOnlyOnPrimaryChanged &&
i != this._primaryIndex)
continue;
// Assume workspaces are only added at the end
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
this._workspaces[m++][w] =
new Workspace.Workspace(metaWorkspace, i);
}
// Assume workspaces are only added at the end
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
this._workspaces[w] = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
}
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
@@ -949,28 +759,25 @@ const WorkspacesDisplay = new Lang.Class({
let removedNum = oldNumWorkspaces - newNumWorkspaces;
for (let w = 0; w < oldNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
if (this._workspaces[0][w].metaWorkspace != metaWorkspace) {
if (this._workspaces[w].metaWorkspace != metaWorkspace) {
removedIndex = w;
break;
}
}
for (let i = 0; i < this._workspaces.length; i++) {
lostWorkspaces = this._workspaces[i].splice(removedIndex,
removedNum);
lostWorkspaces = this._workspaces.splice(removedIndex,
removedNum);
for (let l = 0; l < lostWorkspaces.length; l++) {
lostWorkspaces[l].disconnectAll();
lostWorkspaces[l].destroy();
}
for (let l = 0; l < lostWorkspaces.length; l++) {
lostWorkspaces[l].disconnectAll();
lostWorkspaces[l].destroy();
}
this._thumbnailsBox.removeThumbmails(removedIndex, removedNum);
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
newNumWorkspaces);
this.workspacesView.updateWorkspaces(oldNumWorkspaces,
newNumWorkspaces);
},
_updateZoom : function() {
@@ -982,7 +789,7 @@ const WorkspacesDisplay = new Lang.Class({
this._zoomOut = shouldZoom;
this._updateWorkspacesGeometry();
if (!this._workspacesViews)
if (!this.workspacesView)
return;
Tweener.addTween(this,
@@ -990,8 +797,7 @@ const WorkspacesDisplay = new Lang.Class({
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad' });
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].updateWindowPositions();
this.workspacesView.updateWindowPositions();
}
},

View File

@@ -35,7 +35,6 @@ kn
ku
lt
lv
mk
mr
ms
nb

View File

@@ -36,7 +36,6 @@ js/ui/status/volume.js
js/ui/telepathyClient.js
js/ui/userMenu.js
js/ui/viewSelector.js
js/ui/wanda.js
js/ui/windowAttentionHandler.js
src/gvc/gvc-mixer-control.c
src/main.c

706
po/be.po

File diff suppressed because it is too large Load Diff

664
po/bg.po

File diff suppressed because it is too large Load Diff

647
po/cs.po

File diff suppressed because it is too large Load Diff

757
po/da.po

File diff suppressed because it is too large Load Diff

618
po/es.po

File diff suppressed because it is too large Load Diff

778
po/fa.po

File diff suppressed because it is too large Load Diff

913
po/fi.po

File diff suppressed because it is too large Load Diff

756
po/gl.po

File diff suppressed because it is too large Load Diff

735
po/he.po

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@ msgstr ""
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2011-10-04 20:49+0000\n"
"PO-Revision-Date: 2012-01-04 10:19+0100\n"
"PO-Revision-Date: 2011-10-17 10:30+0200\n"
"Last-Translator: Luca Ferretti <lferrett@gnome.org>\n"
"Language-Team: Italian <tp@lists.linux.it>\n"
"MIME-Version: 1.0\n"
@@ -583,7 +583,7 @@ msgstr[1] "Il sistema verrà spento automaticamente tra %d secondi."
#: ../js/ui/endSessionDialog.js:87
msgid "Powering off the system."
msgstr "Spegnimento del sistema."
msgstr "pegnimento del sistema."
#: ../js/ui/endSessionDialog.js:98
msgid "Click Restart to quit these applications and restart the system."

864
po/ja.po

File diff suppressed because it is too large Load Diff

920
po/lt.po

File diff suppressed because it is too large Load Diff

1639
po/mk.po

File diff suppressed because it is too large Load Diff

745
po/nb.po

File diff suppressed because it is too large Load Diff

1908
po/nn.po

File diff suppressed because it is too large Load Diff

1630
po/ro.po

File diff suppressed because it is too large Load Diff

817
po/ru.po

File diff suppressed because it is too large Load Diff

720
po/sl.po

File diff suppressed because it is too large Load Diff

747
po/te.po

File diff suppressed because it is too large Load Diff

788
po/tr.po

File diff suppressed because it is too large Load Diff

694
po/uk.po

File diff suppressed because it is too large Load Diff

740
po/vi.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -179,8 +179,6 @@ gnome_shell_real_CPPFLAGS = $(gnome_shell_cflags)
gnome_shell_real_LDADD = libgnome-shell.la $(libgnome_shell_la_LIBADD)
gnome_shell_real_DEPENDENCIES = libgnome-shell.la
EXTRA_DIST += test-gapplication.js
########################################
shell_recorder_sources = \

View File

@@ -323,7 +323,7 @@ gnome_shell_plugin_xevent_filter (MetaPlugin *plugin,
#endif
if ((xev->xany.type == EnterNotify || xev->xany.type == LeaveNotify)
&& xev->xcrossing.window == clutter_x11_get_stage_window (CLUTTER_STAGE (meta_plugin_get_stage (plugin))))
&& xev->xcrossing.window == clutter_x11_get_stage_window (CLUTTER_STAGE (clutter_stage_get_default ())))
{
/* If the pointer enters a child of the stage window (eg, a
* trayicon), we want to consider it to still be in the stage,

View File

@@ -114,7 +114,10 @@ sniff_async_ready_cb (GObject *source,
{
InvocationData *data = user_data;
gchar **types;
gint idx;
GError *error = NULL;
GVariantBuilder *builder;
GVariant *result;
types = shell_mime_sniffer_sniff_finish (SHELL_MIME_SNIFFER (source),
res, &error);
@@ -126,8 +129,16 @@ sniff_async_ready_cb (GObject *source,
goto out;
}
g_dbus_method_invocation_return_value (data->invocation,
g_variant_new ("(^as)", types));
builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
for (idx = 0; types[idx] != NULL; idx++)
g_variant_builder_add (builder, "s", types[idx]);
result = g_variant_new ("(as)", builder);
g_dbus_method_invocation_return_value (data->invocation, result);
g_variant_unref (result);
g_variant_builder_unref (builder);
g_strfreev (types);
out:

View File

@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include <cogl-pango/cogl-pango.h>
#include <clutter/clutter.h>
#include <clutter/x11/clutter-x11.h>
#include <gdk/gdk.h>
@@ -158,6 +159,157 @@ shell_dbus_init (gboolean replace)
g_object_unref (session);
}
static void
constrain_tooltip (StTooltip *tooltip,
const ClutterGeometry *geometry,
ClutterGeometry *adjusted_geometry,
gpointer data)
{
const ClutterGeometry *tip_area = st_tooltip_get_tip_area (tooltip);
ShellGlobal *global = shell_global_get ();
MetaScreen *screen = shell_global_get_screen (global);
int n_monitors = meta_screen_get_n_monitors (screen);
int i;
*adjusted_geometry = *geometry;
/* A point that determines what screen we'll constrain to */
int x = tip_area->x + tip_area->width / 2;
int y = tip_area->y + tip_area->height / 2;
for (i = 0; i < n_monitors; i++)
{
MetaRectangle rect;
meta_screen_get_monitor_geometry (screen, i, &rect);
if (x >= rect.x && x < rect.x + rect.width &&
y >= rect.y && y < rect.y + rect.height)
{
if (adjusted_geometry->x + adjusted_geometry->width > rect.x + rect.width)
adjusted_geometry->x = rect.x + rect.width - adjusted_geometry->width;
if (adjusted_geometry->x < rect.x)
adjusted_geometry->x = rect.x;
if (adjusted_geometry->y + adjusted_geometry->height > rect.y + rect.height)
adjusted_geometry->y = rect.y + rect.height - adjusted_geometry->height;
if (adjusted_geometry->y < rect.y)
adjusted_geometry->y = rect.y;
return;
}
}
}
static void
update_font_options (GtkSettings *settings)
{
StThemeContext *context;
ClutterStage *stage;
ClutterBackend *backend;
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;
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);
st_tooltip_set_constrain_func (stage, constrain_tooltip, NULL, NULL);
/* 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 ();
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.
*/
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
shell_fonts_init (void)
{
GtkSettings *settings;
CoglPangoFontMap *fontmap;
/* Disable text mipmapping; it causes problems on pre-GEM Intel
* drivers and we should just be rendering text at the right
* size rather than scaling it. If we do effects where we dynamically
* zoom labels, then we might want to reconsider.
*/
fontmap = COGL_PANGO_FONT_MAP (clutter_get_font_map ());
cogl_pango_font_map_set_use_mipmapping (fontmap, FALSE);
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);
}
static void
shell_prefs_init (void)
{
@@ -171,6 +323,100 @@ shell_prefs_init (void)
OVERRIDES_SCHEMA);
}
/* This is an IBus workaround. The flow of events with IBus is that every time
* it gets gets a key event, it:
*
* Sends it to the daemon via D-Bus asynchronously
* When it gets an reply, synthesizes a new GdkEvent and puts it into the
* GDK event queue with gdk_event_put(), including
* IBUS_FORWARD_MASK = 1 << 25 in the state to prevent a loop.
*
* (Normally, IBus uses the GTK+ key snooper mechanism to get the key
* events early, but since our key events aren't visible to GTK+ key snoopers,
* IBus will instead get the events via the standard
* GtkIMContext.filter_keypress() mechanism.)
*
* There are a number of potential problems here; probably the worst
* problem is that IBus doesn't forward the timestamp with the event
* so that every key event that gets delivered ends up with
* GDK_CURRENT_TIME. This creates some very subtle bugs; for example
* if you have IBus running and a keystroke is used to trigger
* launching an application, focus stealing prevention won't work
* right. http://code.google.com/p/ibus/issues/detail?id=1184
*
* In any case, our normal flow of key events is:
*
* GDK filter function => clutter_x11_handle_event => clutter actor
*
* So, if we see a key event that gets delivered via the GDK event handler
* function - then we know it must be one of these synthesized events, and
* we should push it back to clutter.
*
* To summarize, the full key event flow with IBus is:
*
* GDK filter function
* => Mutter
* => gnome_shell_plugin_xevent_filter()
* => clutter_x11_handle_event()
* => clutter event delivery to actor
* => gtk_im_context_filter_event()
* => sent to IBus daemon
* => response received from IBus daemon
* => gdk_event_put()
* => GDK event handler
* => <this function>
* => clutter_event_put()
* => clutter event delivery to actor
*
* Anything else we see here we just pass on to the normal GDK event handler
* gtk_main_do_event().
*/
static void
gnome_shell_gdk_event_handler (GdkEvent *event_gdk,
gpointer data)
{
if (event_gdk->type == GDK_KEY_PRESS || event_gdk->type == GDK_KEY_RELEASE)
{
ClutterActor *stage;
Window stage_xwindow;
stage = clutter_stage_get_default ();
stage_xwindow = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
if (GDK_WINDOW_XID (event_gdk->key.window) == stage_xwindow)
{
ClutterDeviceManager *device_manager = clutter_device_manager_get_default ();
ClutterInputDevice *keyboard = clutter_device_manager_get_core_device (device_manager,
CLUTTER_KEYBOARD_DEVICE);
ClutterEvent *event_clutter = clutter_event_new ((event_gdk->type == GDK_KEY_PRESS) ?
CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE);
event_clutter->key.time = event_gdk->key.time;
event_clutter->key.flags = CLUTTER_EVENT_NONE;
event_clutter->key.stage = CLUTTER_STAGE (stage);
event_clutter->key.source = NULL;
/* This depends on ClutterModifierType and GdkModifierType being
* identical, which they are currently. (They both match the X
* modifier state in the low 16-bits and have the same extensions.) */
event_clutter->key.modifier_state = event_gdk->key.state;
event_clutter->key.keyval = event_gdk->key.keyval;
event_clutter->key.hardware_keycode = event_gdk->key.hardware_keycode;
event_clutter->key.unicode_value = gdk_keyval_to_unicode (event_clutter->key.keyval);
event_clutter->key.device = keyboard;
clutter_event_put (event_clutter);
clutter_event_free (event_clutter);
return;
}
}
gtk_main_do_event (event_gdk);
}
static void
malloc_statistics_callback (ShellPerfLog *perf_log,
gpointer data)
@@ -313,9 +559,12 @@ main (int argc, char **argv)
shell_dbus_init (meta_get_replace_current_wm ());
shell_a11y_init ();
shell_fonts_init ();
shell_perf_log_init ();
shell_prefs_init ();
gdk_event_handler_set (gnome_shell_gdk_event_handler, NULL, NULL);
g_irepository_prepend_search_path (GNOME_SHELL_PKGLIBDIR);
#if HAVE_BLUETOOTH
g_irepository_prepend_search_path (BLUETOOTH_DIR);

View File

@@ -63,6 +63,7 @@ int
main(int argc, char **argv)
{
GOptionContext *context;
ClutterActor *stage;
GError *error = NULL;
ShellGlobal *global;
GjsContext *js_context;
@@ -123,8 +124,9 @@ main(int argc, char **argv)
filename = argv[1];
}
stage = clutter_stage_get_default ();
title = g_filename_display_basename (filename);
g_set_prgname (title);
clutter_stage_set_title (CLUTTER_STAGE (stage), title);
g_free (title);
#if HAVE_BLUETOOTH

View File

@@ -40,8 +40,13 @@ typedef struct {
gboolean window_sort_stale : 1;
/* See GApplication documentation */
GDBusMenuModel *remote_menu;
gint name_watcher_id;
gchar *dbus_name;
GDBusProxy *app_proxy;
GActionGroup *remote_actions;
GMenuModel *remote_menu;
GActionMuxer *muxer;
GCancellable *dbus_cancellable;
} ShellAppRunningState;
/**
@@ -94,8 +99,14 @@ enum {
static guint shell_app_signals[LAST_SIGNAL] = { 0 };
static void create_running_state (ShellApp *app);
static void setup_running_state (ShellApp *app, MetaWindow *window);
static void unref_running_state (ShellAppRunningState *state);
static void on_dbus_name_appeared (GDBusConnection *bus,
const gchar *name,
const gchar *name_owner,
gpointer user_data);
static void on_dbus_name_disappeared (GDBusConnection *bus,
const gchar *name,
gpointer user_data);
G_DEFINE_TYPE (ShellApp, shell_app, G_TYPE_OBJECT)
@@ -115,6 +126,9 @@ shell_app_get_property (GObject *gobject,
case PROP_ID:
g_value_set_string (value, shell_app_get_id (app));
break;
case PROP_DBUS_ID:
g_value_set_string (value, shell_app_get_dbus_id (app));
break;
case PROP_ACTION_GROUP:
if (app->running_state)
g_value_set_object (value, app->running_state->muxer);
@@ -172,6 +186,15 @@ window_backed_app_get_icon (ShellApp *app,
return actor;
}
const char *
shell_app_get_dbus_id (ShellApp *app)
{
if (app->running_state)
return app->running_state->dbus_name;
else
return NULL;
}
/**
* shell_app_create_icon_texture:
*
@@ -540,7 +563,7 @@ shell_app_update_window_actions (ShellApp *app, MetaWindow *window)
{
const char *object_path;
object_path = meta_window_get_gtk_window_object_path (window);
object_path = meta_window_get_dbus_object_path (window);
if (object_path != NULL)
{
GActionGroup *actions;
@@ -548,15 +571,12 @@ shell_app_update_window_actions (ShellApp *app, MetaWindow *window)
actions = g_object_get_data (G_OBJECT (window), "actions");
if (actions == NULL)
{
actions = G_ACTION_GROUP (g_dbus_action_group_get (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
meta_window_get_gtk_unique_bus_name (window),
actions = G_ACTION_GROUP (g_dbus_action_group_get (g_dbus_proxy_get_connection (app->running_state->app_proxy),
meta_window_get_dbus_unique_name (window),
object_path));
g_object_set_data_full (G_OBJECT (window), "actions", actions, g_object_unref);
}
if (!app->running_state->muxer)
app->running_state->muxer = g_action_muxer_new ();
g_action_muxer_insert (app->running_state->muxer, "win", actions);
g_object_notify (G_OBJECT (app), "action-group");
}
@@ -952,6 +972,34 @@ shell_app_on_ws_switch (MetaScreen *screen,
g_signal_emit (app, shell_app_signals[WINDOWS_CHANGED], 0);
}
static void
on_dbus_application_id_changed (MetaWindow *window,
GParamSpec *pspec,
gpointer user_data)
{
const char *appid;
ShellApp *app = SHELL_APP (user_data);
/* Ignore changes in the appid after it's set, shouldn't happen */
if (app->running_state->dbus_name != NULL)
return;
appid = meta_window_get_dbus_application_id (window);
if (!appid)
return;
g_assert (app->running_state != NULL);
app->running_state->dbus_name = g_strdup (appid);
app->running_state->name_watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
appid,
G_BUS_NAME_WATCHER_FLAGS_NONE,
on_dbus_name_appeared,
on_dbus_name_disappeared,
g_object_ref (app),
g_object_unref);
}
void
_shell_app_add_window (ShellApp *app,
MetaWindow *window)
@@ -969,11 +1017,12 @@ _shell_app_add_window (ShellApp *app,
g_signal_connect (window, "unmanaged", G_CALLBACK(shell_app_on_unmanaged), app);
g_signal_connect (window, "notify::user-time", G_CALLBACK(shell_app_on_user_time_changed), app);
setup_running_state (app, window);
if (app->state != SHELL_APP_STATE_STARTING)
shell_app_state_transition (app, SHELL_APP_STATE_RUNNING);
g_signal_connect (window, "notify::dbus-application-id", G_CALLBACK(on_dbus_application_id_changed), app);
on_dbus_application_id_changed (window, NULL, app);
g_object_thaw_notify (G_OBJECT (app));
g_signal_emit (app, shell_app_signals[WINDOWS_CHANGED], 0);
@@ -990,6 +1039,7 @@ _shell_app_remove_window (ShellApp *app,
g_signal_handlers_disconnect_by_func (window, G_CALLBACK(shell_app_on_unmanaged), app);
g_signal_handlers_disconnect_by_func (window, G_CALLBACK(shell_app_on_user_time_changed), app);
g_signal_handlers_disconnect_by_func (window, G_CALLBACK(on_dbus_application_id_changed), app);
g_object_unref (window);
app->running_state->windows = g_slist_remove (app->running_state->windows, window);
@@ -999,6 +1049,134 @@ _shell_app_remove_window (ShellApp *app,
g_signal_emit (app, shell_app_signals[WINDOWS_CHANGED], 0);
}
static void
on_dbus_proxy_gotten (GObject *initable,
GAsyncResult *result,
gpointer user_data)
{
ShellApp *self = SHELL_APP (user_data);
ShellAppRunningState *state = self->running_state;
GError *error = NULL;
GVariant *menu_property;
state->app_proxy = g_dbus_proxy_new_finish (result,
&error);
if (error)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
{
g_warning ("Unexpected error while creating application proxy: %s", error->message);
}
g_clear_error (&error);
g_clear_object (&state->dbus_cancellable);
if (state->name_watcher_id)
{
g_bus_unwatch_name (state->name_watcher_id);
state->name_watcher_id = 0;
}
g_free (state->dbus_name);
state->dbus_name = NULL;
g_object_unref (self);
return;
}
/* on to the second step, the primary action group */
state->remote_actions = (GActionGroup*)g_dbus_action_group_get (
g_dbus_proxy_get_connection (state->app_proxy),
g_dbus_proxy_get_name (state->app_proxy),
g_dbus_proxy_get_object_path (state->app_proxy));
state->muxer = g_action_muxer_new ();
g_action_muxer_insert (state->muxer, "app", state->remote_actions);
g_strfreev (g_action_group_list_actions (state->remote_actions));
g_object_notify (G_OBJECT (self), "action-group");
menu_property = g_dbus_proxy_get_cached_property (state->app_proxy, "AppMenu");
if (menu_property && g_variant_n_children (menu_property) > 0)
{
const gchar *object_path;
g_variant_get_child (menu_property, 0, "&o", &object_path);
state->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (g_dbus_proxy_get_connection (state->app_proxy),
state->dbus_name,
object_path));
g_object_notify (G_OBJECT (self), "menu");
}
}
static void
on_dbus_name_appeared (GDBusConnection *bus,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
ShellApp *self = SHELL_APP (user_data);
ShellAppRunningState *state = self->running_state;
char *object_path;
g_assert (state != NULL);
object_path = g_strconcat ("/", name, NULL);
g_strdelimit (object_path, ".", '/');
if (!state->dbus_cancellable)
state->dbus_cancellable = g_cancellable_new ();
/* first step: the application proxy */
g_dbus_proxy_new (bus,
G_DBUS_PROXY_FLAGS_NONE,
NULL, /* interface info */
name_owner,
object_path,
"org.gtk.Application",
state->dbus_cancellable,
on_dbus_proxy_gotten,
g_object_ref (self));
g_object_notify (G_OBJECT (self), "dbus-id");
g_free (object_path);
}
static void
on_dbus_name_disappeared (GDBusConnection *bus,
const gchar *name,
gpointer user_data)
{
ShellApp *self = SHELL_APP (user_data);
ShellAppRunningState *state = self->running_state;
g_assert (state != NULL);
if (state->dbus_cancellable)
{
g_cancellable_cancel (state->dbus_cancellable);
g_clear_object (&state->dbus_cancellable);
}
g_clear_object (&state->app_proxy);
g_clear_object (&state->remote_actions);
g_clear_object (&state->remote_menu);
g_clear_object (&state->muxer);
g_free (state->dbus_name);
state->dbus_name = NULL;
g_bus_unwatch_name (state->name_watcher_id);
state->name_watcher_id = 0;
}
/**
* shell_app_get_pids:
* @app: a #ShellApp
@@ -1211,47 +1389,6 @@ create_running_state (ShellApp *app)
app->running_state->refcount = 1;
app->running_state->workspace_switch_id =
g_signal_connect (screen, "workspace-switched", G_CALLBACK(shell_app_on_ws_switch), app);
app->running_state->muxer = g_action_muxer_new ();
}
static void
setup_running_state (ShellApp *app,
MetaWindow *window)
{
/* We assume that 'gtk-unique-bus-name', gtk-application-object-path'
* and 'gtk-app-menu-object-path' are the same for all windows which
* have it set.
*
* It could be possible, however, that the first window we see
* belonging to the app didn't have them set. For this reason, we
* take the values from the first window that has them set and ignore
* all the rest (until the app is stopped and restarted).
*/
if (app->running_state->remote_menu == NULL)
{
const gchar *application_object_path;
const gchar *app_menu_object_path;
const gchar *unique_bus_name;
GDBusConnection *session;
GDBusActionGroup *actions;
application_object_path = meta_window_get_gtk_application_object_path (window);
app_menu_object_path = meta_window_get_gtk_app_menu_object_path (window);
unique_bus_name = meta_window_get_gtk_unique_bus_name (window);
if (application_object_path == NULL || app_menu_object_path == NULL || unique_bus_name == NULL)
return;
session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
g_assert (session != NULL);
app->running_state->remote_menu = g_dbus_menu_model_get (session, unique_bus_name, app_menu_object_path);
actions = g_dbus_action_group_get (session, unique_bus_name, application_object_path);
g_action_muxer_insert (app->running_state->muxer, "app", G_ACTION_GROUP (actions));
g_object_unref (actions);
g_object_unref (session);
}
}
static void
@@ -1268,8 +1405,20 @@ unref_running_state (ShellAppRunningState *state)
screen = shell_global_get_screen (shell_global_get ());
g_signal_handler_disconnect (screen, state->workspace_switch_id);
if (state->dbus_cancellable)
{
g_cancellable_cancel (state->dbus_cancellable);
g_object_unref (state->dbus_cancellable);
}
g_clear_object (&state->app_proxy);
g_clear_object (&state->remote_actions);
g_clear_object (&state->remote_menu);
g_clear_object (&state->muxer);
g_free (state->dbus_name);
if (state->name_watcher_id)
g_bus_unwatch_name (state->name_watcher_id);
g_slice_free (ShellAppRunningState, state);
}
@@ -1514,6 +1663,20 @@ shell_app_class_init(ShellAppClass *klass)
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/**
* ShellApp:dbus-id:
*
* The DBus well-known name of the application, if one can be associated
* to this ShellApp (it means that the application is using GApplication)
*/
g_object_class_install_property (gobject_class,
PROP_DBUS_ID,
g_param_spec_string ("dbus-id",
"Application DBus Id",
"The DBus well-known name of the application",
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/**
* ShellApp:action-group:
*

View File

@@ -41,6 +41,8 @@ const char *shell_app_get_id (ShellApp *app);
GMenuTreeEntry *shell_app_get_tree_entry (ShellApp *app);
GDesktopAppInfo *shell_app_get_app_info (ShellApp *app);
const char *shell_app_get_dbus_id (ShellApp *app);
ClutterActor *shell_app_create_icon_texture (ShellApp *app, int size);
ClutterActor *shell_app_get_faded_icon (ShellApp *app, int size);
const char *shell_app_get_name (ShellApp *app);

View File

@@ -84,8 +84,7 @@ shell_embedded_window_hide (GtkWidget *widget)
{
ShellEmbeddedWindow *window = SHELL_EMBEDDED_WINDOW (widget);
if (window->priv->actor)
clutter_actor_queue_relayout (CLUTTER_ACTOR (window->priv->actor));
clutter_actor_queue_relayout (CLUTTER_ACTOR (window->priv->actor));
GTK_WIDGET_CLASS (shell_embedded_window_parent_class)->hide (widget);
}

View File

@@ -15,7 +15,6 @@
#endif
#include <X11/extensions/Xfixes.h>
#include <cogl-pango/cogl-pango.h>
#include <canberra.h>
#include <clutter/glx/clutter-glx.h>
#include <clutter/x11/clutter-x11.h>
@@ -794,249 +793,6 @@ global_stage_after_paint (ClutterStage *stage,
"clutter.stagePaintDone");
}
static void
constrain_tooltip (StTooltip *tooltip,
const ClutterGeometry *geometry,
ClutterGeometry *adjusted_geometry,
gpointer data)
{
const ClutterGeometry *tip_area = st_tooltip_get_tip_area (tooltip);
ShellGlobal *global = shell_global_get ();
MetaScreen *screen = shell_global_get_screen (global);
int n_monitors = meta_screen_get_n_monitors (screen);
int i;
*adjusted_geometry = *geometry;
/* A point that determines what screen we'll constrain to */
int x = tip_area->x + tip_area->width / 2;
int y = tip_area->y + tip_area->height / 2;
for (i = 0; i < n_monitors; i++)
{
MetaRectangle rect;
meta_screen_get_monitor_geometry (screen, i, &rect);
if (x >= rect.x && x < rect.x + rect.width &&
y >= rect.y && y < rect.y + rect.height)
{
if (adjusted_geometry->x + adjusted_geometry->width > rect.x + rect.width)
adjusted_geometry->x = rect.x + rect.width - adjusted_geometry->width;
if (adjusted_geometry->x < rect.x)
adjusted_geometry->x = rect.x;
if (adjusted_geometry->y + adjusted_geometry->height > rect.y + rect.height)
adjusted_geometry->y = rect.y + rect.height - adjusted_geometry->height;
if (adjusted_geometry->y < rect.y)
adjusted_geometry->y = rect.y;
return;
}
}
}
static void
update_font_options (GtkSettings *settings,
ClutterStage *stage)
{
StThemeContext *context;
ClutterBackend *backend;
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;
g_object_get (settings,
"gtk-xft-dpi", &dpi,
"gtk-xft-antialias", &antialias,
"gtk-xft-hinting", &hinting,
"gtk-xft-hintstyle", &hint_style_str,
NULL);
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);
st_tooltip_set_constrain_func (stage, constrain_tooltip, NULL, NULL);
/* 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 ();
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.
*/
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, CLUTTER_STAGE (data));
}
static void
shell_fonts_init (ClutterStage *stage)
{
GtkSettings *settings;
CoglPangoFontMap *fontmap;
/* Disable text mipmapping; it causes problems on pre-GEM Intel
* drivers and we should just be rendering text at the right
* size rather than scaling it. If we do effects where we dynamically
* zoom labels, then we might want to reconsider.
*/
fontmap = COGL_PANGO_FONT_MAP (clutter_get_font_map ());
cogl_pango_font_map_set_use_mipmapping (fontmap, FALSE);
settings = gtk_settings_get_default ();
g_object_connect (settings,
"signal::notify::gtk-xft-dpi",
G_CALLBACK (settings_notify_cb), stage,
"signal::notify::gtk-xft-antialias",
G_CALLBACK (settings_notify_cb), stage,
"signal::notify::gtk-xft-hinting",
G_CALLBACK (settings_notify_cb), stage,
"signal::notify::gtk-xft-hintstyle",
G_CALLBACK (settings_notify_cb), stage,
NULL);
update_font_options (settings, stage);
}
/* This is an IBus workaround. The flow of events with IBus is that every time
* it gets gets a key event, it:
*
* Sends it to the daemon via D-Bus asynchronously
* When it gets an reply, synthesizes a new GdkEvent and puts it into the
* GDK event queue with gdk_event_put(), including
* IBUS_FORWARD_MASK = 1 << 25 in the state to prevent a loop.
*
* (Normally, IBus uses the GTK+ key snooper mechanism to get the key
* events early, but since our key events aren't visible to GTK+ key snoopers,
* IBus will instead get the events via the standard
* GtkIMContext.filter_keypress() mechanism.)
*
* There are a number of potential problems here; probably the worst
* problem is that IBus doesn't forward the timestamp with the event
* so that every key event that gets delivered ends up with
* GDK_CURRENT_TIME. This creates some very subtle bugs; for example
* if you have IBus running and a keystroke is used to trigger
* launching an application, focus stealing prevention won't work
* right. http://code.google.com/p/ibus/issues/detail?id=1184
*
* In any case, our normal flow of key events is:
*
* GDK filter function => clutter_x11_handle_event => clutter actor
*
* So, if we see a key event that gets delivered via the GDK event handler
* function - then we know it must be one of these synthesized events, and
* we should push it back to clutter.
*
* To summarize, the full key event flow with IBus is:
*
* GDK filter function
* => Mutter
* => gnome_shell_plugin_xevent_filter()
* => clutter_x11_handle_event()
* => clutter event delivery to actor
* => gtk_im_context_filter_event()
* => sent to IBus daemon
* => response received from IBus daemon
* => gdk_event_put()
* => GDK event handler
* => <this function>
* => clutter_event_put()
* => clutter event delivery to actor
*
* Anything else we see here we just pass on to the normal GDK event handler
* gtk_main_do_event().
*/
static void
gnome_shell_gdk_event_handler (GdkEvent *event_gdk,
gpointer data)
{
if (event_gdk->type == GDK_KEY_PRESS || event_gdk->type == GDK_KEY_RELEASE)
{
ClutterActor *stage;
Window stage_xwindow;
stage = CLUTTER_ACTOR (data);
stage_xwindow = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
if (GDK_WINDOW_XID (event_gdk->key.window) == stage_xwindow)
{
ClutterDeviceManager *device_manager = clutter_device_manager_get_default ();
ClutterInputDevice *keyboard = clutter_device_manager_get_core_device (device_manager,
CLUTTER_KEYBOARD_DEVICE);
ClutterEvent *event_clutter = clutter_event_new ((event_gdk->type == GDK_KEY_PRESS) ?
CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE);
event_clutter->key.time = event_gdk->key.time;
event_clutter->key.flags = CLUTTER_EVENT_NONE;
event_clutter->key.stage = CLUTTER_STAGE (stage);
event_clutter->key.source = NULL;
/* This depends on ClutterModifierType and GdkModifierType being
* identical, which they are currently. (They both match the X
* modifier state in the low 16-bits and have the same extensions.) */
event_clutter->key.modifier_state = event_gdk->key.state;
event_clutter->key.keyval = event_gdk->key.keyval;
event_clutter->key.hardware_keycode = event_gdk->key.hardware_keycode;
event_clutter->key.unicode_value = gdk_keyval_to_unicode (event_clutter->key.keyval);
event_clutter->key.device = keyboard;
clutter_event_put (event_clutter);
clutter_event_free (event_clutter);
return;
}
}
gtk_main_do_event (event_gdk);
}
void
_shell_global_set_plugin (ShellGlobal *global,
MetaPlugin *plugin)
@@ -1082,10 +838,6 @@ _shell_global_set_plugin (ShellGlobal *global,
g_signal_connect (global->meta_display, "notify::focus-window",
G_CALLBACK (focus_window_changed), global);
shell_fonts_init (global->stage);
gdk_event_handler_set (gnome_shell_gdk_event_handler, global->stage, NULL);
global->focus_manager = st_focus_manager_get_for_stage (global->stage);
}

View File

@@ -340,6 +340,104 @@ shell_tp_client_grab_contact_list_changed (ShellTpClient *self,
/* Telepathy utility functions */
/**
* ShellGetTpContactCb:
* @connection: The connection
* @contacts: (element-type TelepathyGLib.Contact): List of contacts
* @failed: Array of failed contacts
*/
static void
shell_global_get_tp_contacts_cb (TpConnection *self,
guint n_contacts,
TpContact * const *contacts,
guint n_failed,
const TpHandle *failed,
const GError *error,
gpointer user_data,
GObject *weak_object)
{
int i;
GList *contact_list = NULL;
for (i = 0; i < n_contacts; i++) {
contact_list = g_list_append(contact_list, contacts[i]);
}
TpHandle *failed_list = g_new0 (TpHandle, n_failed + 1);
memcpy(failed_list, failed, n_failed);
((ShellGetTpContactCb)user_data)(self, contact_list, failed_list);
}
/**
* shell_get_tp_contacts:
* @self: A connection, which must be ready
* @n_handles: Number of handles in handles
* @handles: (array length=n_handles) (element-type uint): Array of handles
* @n_features: Number of features in features
* @features: (array length=n_features) (allow-none) (element-type uint):
* Array of features
* @callback: (scope async): User callback to run when the contacts are ready
*
* Wrap tp_connection_get_contacts_by_handle so we can transform the array
* into a null-terminated one, which gjs can handle.
* We send the original callback to tp_connection_get_contacts_by_handle as
* user_data, and we have our own function as callback, which does the
* transforming.
*/
void
shell_get_tp_contacts (TpConnection *self,
guint n_handles,
const TpHandle *handles,
guint n_features,
const TpContactFeature *features,
ShellGetTpContactCb callback)
{
tp_connection_get_contacts_by_handle(self, n_handles, handles,
n_features, features,
shell_global_get_tp_contacts_cb,
callback, NULL, NULL);
}
static void
shell_global_get_self_contact_features_cb (TpConnection *connection,
guint n_contacts,
TpContact * const *contacts,
const GError *error,
gpointer user_data,
GObject *weak_object)
{
if (error != NULL) {
g_print ("Failed to upgrade self contact: %s", error->message);
return;
}
((ShellGetSelfContactFeaturesCb)user_data)(connection, *contacts);
}
/**
* shell_get_self_contact_features:
* @self: A connection, which must be ready
* @n_features: Number of features in features
* @features: (array length=n_features) (allow-none) (element-type uint):
* Array of features
* @callback: (scope async): User callback to run when the contact is ready
*
* Wrap tp_connection_upgrade_contacts due to the lack of support for
* proper arrays arguments in GJS.
*/
void
shell_get_self_contact_features (TpConnection *self,
guint n_features,
const TpContactFeature *features,
ShellGetSelfContactFeaturesCb callback)
{
TpContact *self_contact = tp_connection_get_self_contact (self);
tp_connection_upgrade_contacts (self, 1, &self_contact,
n_features, features,
shell_global_get_self_contact_features_cb,
callback, NULL, NULL);
}
/**
* shell_get_contact_events:

View File

@@ -102,6 +102,24 @@ void shell_tp_client_grab_contact_list_changed (ShellTpClient *self,
TpConnection *conn);
/* Telepathy utility functions */
typedef void (*ShellGetTpContactCb) (TpConnection *connection,
GList *contacts,
TpHandle *failed);
void shell_get_tp_contacts (TpConnection *self,
guint n_handles,
const TpHandle *handles,
guint n_features,
const TpContactFeature *features,
ShellGetTpContactCb callback);
typedef void (*ShellGetSelfContactFeaturesCb) (TpConnection *connection,
TpContact *contact);
void shell_get_self_contact_features (TpConnection *self,
guint n_features,
const TpContactFeature *features,
ShellGetSelfContactFeaturesCb callback);
void shell_get_contact_events (TplLogManager *log_manager,
TpAccount *account,

View File

@@ -321,29 +321,19 @@ shell_xfixes_cursor_class_init (ShellXFixesCursorClass *klass)
}
/**
* shell_xfixes_cursor_get_for_stage:
* @stage: (transfer none): The #ClutterStage to get the cursor for
* shell_xfixes_cursor_get_default:
*
* Return value: (transfer none): A #ShellXFixesCursor instance
* Return value: (transfer none): The global #ShellXFixesCursor singleton
*/
ShellXFixesCursor *
shell_xfixes_cursor_get_for_stage (ClutterStage *stage)
shell_xfixes_cursor_get_default ()
{
ShellXFixesCursor *instance;
static GQuark xfixes_cursor_quark;
if (G_UNLIKELY (xfixes_cursor_quark == 0))
xfixes_cursor_quark = g_quark_from_static_string ("gnome-shell-xfixes-cursor");
instance = g_object_get_qdata (G_OBJECT (stage), xfixes_cursor_quark);
static ShellXFixesCursor *instance = NULL;
if (instance == NULL)
{
instance = g_object_new (SHELL_TYPE_XFIXES_CURSOR,
"stage", stage,
NULL);
g_object_set_qdata (G_OBJECT (stage), xfixes_cursor_quark, instance);
}
instance = g_object_new (SHELL_TYPE_XFIXES_CURSOR,
"stage", clutter_stage_get_default (),
NULL);
return instance;
}

View File

@@ -19,7 +19,7 @@ typedef struct _ShellXFixesCursorClass ShellXFixesCursorClass;
GType shell_xfixes_cursor_get_type (void) G_GNUC_CONST;
ShellXFixesCursor *shell_xfixes_cursor_get_for_stage (ClutterStage *stage);
ShellXFixesCursor *shell_xfixes_cursor_get_default (void);
void shell_xfixes_cursor_show (ShellXFixesCursor *xfixes_cursor);
void shell_xfixes_cursor_hide (ShellXFixesCursor *xfixes_cursor);

View File

@@ -174,20 +174,6 @@ st_icon_dispose (GObject *gobject)
G_OBJECT_CLASS (st_icon_parent_class)->dispose (gobject);
}
static void
st_icon_finalize (GObject *gobject)
{
StIconPrivate *priv = ST_ICON (gobject)->priv;
if (priv->icon_name)
{
g_free (priv->icon_name);
priv->icon_name = NULL;
}
G_OBJECT_CLASS (st_icon_parent_class)->finalize (gobject);
}
static void
st_icon_get_preferred_height (ClutterActor *actor,
gfloat for_width,
@@ -331,7 +317,6 @@ st_icon_class_init (StIconClass *klass)
object_class->get_property = st_icon_get_property;
object_class->set_property = st_icon_set_property;
object_class->dispose = st_icon_dispose;
object_class->finalize = st_icon_finalize;
actor_class->get_preferred_height = st_icon_get_preferred_height;
actor_class->get_preferred_width = st_icon_get_preferred_width;

View File

@@ -1226,9 +1226,9 @@ load_sliced_image (GSimpleAsyncResult *result,
width = gdk_pixbuf_get_width (pix);
height = gdk_pixbuf_get_height (pix);
for (y = 0; y < height; y += data->grid_height)
for (y = 0; y < height; y += data->grid_width)
{
for (x = 0; x < width; x += data->grid_width)
for (x = 0; x < width; x += data->grid_height)
{
GdkPixbuf *pixbuf = gdk_pixbuf_new_subpixbuf (pix, x, y, data->grid_width, data->grid_height);
g_assert (pixbuf != NULL);

View File

@@ -5,7 +5,6 @@
* Copyright 2009, 2010 Red Hat, Inc.
* Copyright 2009, 2010 Florian Müllner
* Copyright 2010 Intel Corporation.
* Copyright 2011 Quentin "Sardem FF7" Glidic
*
* Contains code derived from:
* rectangle.c: Rounded rectangle.
@@ -391,110 +390,69 @@ st_theme_node_lookup_corner (StThemeNode *node,
return material;
}
static void
get_background_scale (StThemeNode *node,
gdouble painting_area_width,
gdouble painting_area_height,
gdouble background_image_width,
gdouble background_image_height,
gdouble *scale_w,
gdouble *scale_h)
{
*scale_w = -1.0;
*scale_h = -1.0;
switch (node->background_size)
{
case ST_BACKGROUND_SIZE_AUTO:
*scale_w = 1.0;
break;
case ST_BACKGROUND_SIZE_CONTAIN:
if (background_image_width > background_image_height)
*scale_w = painting_area_width / background_image_width;
else
*scale_w = painting_area_height / background_image_height;
break;
case ST_BACKGROUND_SIZE_COVER:
if (background_image_width < background_image_height)
*scale_w = painting_area_width / background_image_width;
else
*scale_w = painting_area_height / background_image_height;
break;
case ST_BACKGROUND_SIZE_FIXED:
if (node->background_size_w > -1)
{
*scale_w = node->background_size_w / background_image_width;
if (node->background_size_h > -1)
*scale_h = node->background_size_h / background_image_height;
}
else if (node->background_size_h > -1)
*scale_w = node->background_size_h / background_image_height;
break;
}
if (*scale_h < 0.0)
*scale_h = *scale_w;
}
static void
get_background_coordinates (StThemeNode *node,
gdouble painting_area_width,
gdouble painting_area_height,
gdouble background_image_width,
gdouble background_image_height,
gdouble *x,
gdouble *y)
{
/* honor the specified position if any */
if (node->background_position_set)
{
*x = node->background_position_x;
*y = node->background_position_y;
}
else
{
/* center the background on the widget */
*x = (painting_area_width / 2.0) - (background_image_width / 2.0);
*y = (painting_area_height / 2.0) - (background_image_height / 2.0);
}
}
static void
get_background_position (StThemeNode *self,
const ClutterActorBox *allocation,
ClutterActorBox *result)
{
gdouble painting_area_width, painting_area_height;
gdouble background_image_width, background_image_height;
gdouble x, y;
gdouble scale_w, scale_h;
gfloat w, h;
/* get the background image size */
background_image_width = allocation->x2 - allocation->x1;
background_image_height = allocation->y2 - allocation->y1;
result->x1 = result->y1 = 0;
result->x2 = allocation->x2 - allocation->x1;
result->y2 = allocation->y2 - allocation->y1;
/* get the painting area size */
painting_area_width = cogl_texture_get_width (self->background_texture);
painting_area_height = cogl_texture_get_height (self->background_texture);
w = cogl_texture_get_width (self->background_texture);
h = cogl_texture_get_height (self->background_texture);
/* scale if requested */
get_background_scale (self,
painting_area_width, painting_area_height,
background_image_width, background_image_height,
&scale_w, &scale_h);
background_image_width *= scale_w;
background_image_height *= scale_h;
/* scale the background into the allocated bounds, when not being absolutely positioned */
if ((w > result->x2 || h > result->y2) && !self->background_position_set)
{
gint new_h, new_w, offset;
gint box_w, box_h;
/* get coordinates */
get_background_coordinates (self,
painting_area_width, painting_area_height,
background_image_width, background_image_height,
&x, &y);
box_w = (int) result->x2;
box_h = (int) result->y2;
/* place the background image */
result->x1 = x;
result->y1 = y;
result->x2 = result->x1 + background_image_width;
result->y2 = result->y1 + background_image_height;
/* scale to fit */
new_h = (int)((h / w) * ((gfloat) box_w));
new_w = (int)((w / h) * ((gfloat) box_h));
if (new_h > box_h)
{
/* center for new width */
offset = ((box_w) - new_w) * 0.5;
result->x1 = offset;
result->x2 = offset + new_w;
result->y2 = box_h;
}
else
{
/* center for new height */
offset = ((box_h) - new_h) * 0.5;
result->y1 = offset;
result->y2 = offset + new_h;
result->x2 = box_w;
}
}
else
{
/* honor the specified position if any */
if (self->background_position_set)
{
result->x1 = self->background_position_x;
result->y1 = self->background_position_y;
}
else
{
/* center the background on the widget */
result->x1 = (int)(((allocation->x2 - allocation->x1) / 2) - (w / 2));
result->y1 = (int)(((allocation->y2 - allocation->y1) / 2) - (h / 2));
}
result->x2 = result->x1 + w;
result->y2 = result->y1 + h;
}
}
/* Use of this function marks code which doesn't support
@@ -575,13 +533,12 @@ create_cairo_pattern_of_background_image (StThemeNode *node,
cairo_content_t content;
cairo_matrix_t matrix;
const char *file;
double height_ratio, width_ratio;
int file_width;
int file_height;
StTextureCache *texture_cache;
gdouble background_image_width, background_image_height;
gdouble x, y;
gdouble scale_w, scale_h;
file = st_theme_node_get_background_image (node);
texture_cache = st_texture_cache_get_default ();
@@ -596,39 +553,90 @@ create_cairo_pattern_of_background_image (StThemeNode *node,
content = cairo_surface_get_content (surface);
pattern = cairo_pattern_create_for_surface (surface);
background_image_width = cairo_image_surface_get_width (surface);
background_image_height = cairo_image_surface_get_height (surface);
file_width = cairo_image_surface_get_width (surface);
file_height = cairo_image_surface_get_height (surface);
height_ratio = file_height / node->alloc_height;
width_ratio = file_width / node->alloc_width;
*needs_background_fill = TRUE;
if ((file_width > node->alloc_width || file_height > node->alloc_height)
&& !node->background_position_set)
{
double scale_factor;
double x_offset, y_offset;
cairo_matrix_init_identity (&matrix);
if (width_ratio > height_ratio)
{
double scaled_height;
get_background_scale (node,
node->alloc_width, node->alloc_height,
background_image_width, background_image_height,
&scale_w, &scale_h);
if ((scale_w != 1) || (scale_h != 1))
cairo_matrix_scale (&matrix, 1.0/scale_w, 1.0/scale_h);
background_image_width *= scale_w;
background_image_height *= scale_h;
/* center vertically */
get_background_coordinates (node,
node->alloc_width, node->alloc_height,
background_image_width, background_image_height,
&x, &y);
cairo_matrix_translate (&matrix, -x, -y);
scale_factor = width_ratio;
scaled_height = file_height / scale_factor;
/* If it's opaque, fills up the entire allocated
* area, then don't bother doing a background fill first
*/
if (content != CAIRO_CONTENT_COLOR_ALPHA
&& x >= 0
&& -x + background_image_width >= node->alloc_width
&& y >= 0
&& -y + background_image_height >= node->alloc_height)
*needs_background_fill = FALSE;
x_offset = 0.;
y_offset = - (node->alloc_height / 2. - scaled_height / 2.);
}
else
{
double scaled_width;
cairo_pattern_set_matrix (pattern, &matrix);
/* center horizontally */
scale_factor = height_ratio;
scaled_width = file_width / scale_factor;
y_offset = 0.;
x_offset = - (node->alloc_width / 2. - scaled_width / 2.);
}
cairo_matrix_init_scale (&matrix, scale_factor, scale_factor);
cairo_matrix_translate (&matrix, x_offset, y_offset);
cairo_pattern_set_matrix (pattern, &matrix);
/* If it's opaque, and when scaled, fills up the entire allocated
* area, then don't bother doing a background fill first
*/
if (content != CAIRO_CONTENT_COLOR_ALPHA && width_ratio == height_ratio)
*needs_background_fill = FALSE;
}
else
{
double x_offset, y_offset;
if (node->background_position_set)
{
x_offset = -node->background_position_x;
y_offset = -node->background_position_y;
}
else
{
if (node->alloc_width > file_width)
x_offset = - (node->alloc_width / 2.0 - file_width / 2.0);
else
x_offset = - (file_width / 2.0 - node->alloc_width / 2.0);
if (node->alloc_height > file_height)
y_offset = - (node->alloc_height / 2.0 - file_height / 2.0);
else
y_offset = - (file_height / 2.0 - node->alloc_height / 2.0);
}
/* If it's opaque, and when translated, fills up the entire allocated
* area, then don't bother doing a background fill first
*/
if (content != CAIRO_CONTENT_COLOR_ALPHA
&& -x_offset <= 0
&& -x_offset + file_width >= node->alloc_width
&& -y_offset <= 0
&& -y_offset + file_height >= node->alloc_height)
*needs_background_fill = FALSE;
cairo_matrix_init_translate (&matrix, x_offset, y_offset);
cairo_pattern_set_matrix (pattern, &matrix);
}
return pattern;
}
@@ -1306,8 +1314,6 @@ st_theme_node_render_resources (StThemeNode *node,
StShadow *background_image_shadow_spec;
const char *background_image;
g_return_if_fail (width > 0 && height > 0);
texture_cache = st_texture_cache_get_default ();
/* FIXME - need to separate this into things that need to be recomputed on
@@ -1411,11 +1417,9 @@ st_theme_node_render_resources (StThemeNode *node,
else if (node->background_color.alpha > 0 || has_border)
{
CoglHandle buffer, offscreen;
int texture_width = ceil (width);
int texture_height = ceil (height);
buffer = cogl_texture_new_with_size (texture_width,
texture_height,
buffer = cogl_texture_new_with_size (width,
height,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY);
offscreen = cogl_offscreen_new_to_texture (buffer);
@@ -1423,14 +1427,9 @@ st_theme_node_render_resources (StThemeNode *node,
if (offscreen != COGL_INVALID_HANDLE)
{
ClutterActorBox box = { 0, 0, width, height };
CoglColor clear_color;
cogl_push_framebuffer (offscreen);
cogl_ortho (0, width, height, 0, 0, 1.0);
cogl_color_set_from_4ub (&clear_color, 0, 0, 0, 0);
cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
st_theme_node_paint_borders (node, &box, 0xFF);
cogl_pop_framebuffer ();
cogl_handle_unref (offscreen);
@@ -1929,9 +1928,6 @@ st_theme_node_paint (StThemeNode *node,
allocation.x2 = width;
allocation.y2 = height;
if (width <= 0 || height <= 0)
return;
if (node->alloc_width != width || node->alloc_height != height)
st_theme_node_render_resources (node, width, height);

View File

@@ -3,7 +3,6 @@
* st-theme-node-private.h: private structures and functions for StThemeNode
*
* Copyright 2009, 2010 Red Hat, Inc.
* Copyright 2011 Quentin "Sardem FF7" Glidic
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -25,7 +24,6 @@
#include <gdk/gdk.h>
#include "st-theme-node.h"
#include "st-types.h"
G_BEGIN_DECLS
@@ -46,9 +44,6 @@ struct _StThemeNode {
int background_position_x;
int background_position_y;
gboolean background_position_set : 1;
StBackgroundSize background_size;
gint background_size_w;
gint background_size_h;
ClutterColor foreground_color;
ClutterColor border_color[4];

View File

@@ -7,7 +7,6 @@
* Copyright 2009, 2010 Florian Müllner
* Copyright 2010 Adel Gadllah
* Copyright 2010 Giovanni Campagna
* Copyright 2011 Quentin "Sardem FF7" Glidic
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -91,12 +90,6 @@ st_theme_node_dispose (GObject *gobject)
node->border_image = NULL;
}
if (node->icon_colors)
{
st_icon_colors_unref (node->icon_colors);
node->icon_colors = NULL;
}
G_OBJECT_CLASS (st_theme_node_parent_class)->dispose (gobject);
}
@@ -1580,7 +1573,6 @@ _st_theme_node_ensure_background (StThemeNode *node)
node->background_color = TRANSPARENT_COLOR;
node->background_gradient_type = ST_GRADIENT_NONE;
node->background_position_set = FALSE;
node->background_size = ST_BACKGROUND_SIZE_AUTO;
ensure_properties (node);
@@ -1608,7 +1600,6 @@ _st_theme_node_ensure_background (StThemeNode *node)
g_free (node->background_image);
node->background_image = NULL;
node->background_position_set = FALSE;
node->background_size = ST_BACKGROUND_SIZE_AUTO;
for (term = decl->value; term; term = term->next)
{
@@ -1665,44 +1656,6 @@ _st_theme_node_ensure_background (StThemeNode *node)
else
node->background_position_set = TRUE;
}
else if (strcmp (property_name, "-size") == 0)
{
if (decl->value->type == TERM_IDENT)
{
if (strcmp (decl->value->content.str->stryng->str, "contain") == 0)
node->background_size = ST_BACKGROUND_SIZE_CONTAIN;
else if (strcmp (decl->value->content.str->stryng->str, "cover") == 0)
node->background_size = ST_BACKGROUND_SIZE_COVER;
else if ((strcmp (decl->value->content.str->stryng->str, "auto") == 0) && (decl->value->next) && (decl->value->next->type == TERM_NUMBER))
{
GetFromTermResult result = get_length_from_term_int (node, decl->value->next, FALSE, &node->background_size_h);
node->background_size_w = -1;
node->background_size = (result == VALUE_FOUND) ? ST_BACKGROUND_SIZE_FIXED : ST_BACKGROUND_SIZE_AUTO;
}
else
node->background_size = ST_BACKGROUND_SIZE_AUTO;
}
else if (decl->value->type == TERM_NUMBER)
{
GetFromTermResult result = get_length_from_term_int (node, decl->value, FALSE, &node->background_size_w);
if (result == VALUE_NOT_FOUND)
continue;
node->background_size = ST_BACKGROUND_SIZE_FIXED;
if ((decl->value->next) && (decl->value->next->type == TERM_NUMBER))
{
result = get_length_from_term_int (node, decl->value->next, FALSE, &node->background_size_h);
if (result == VALUE_FOUND)
continue;
}
node->background_size_h = -1;
}
else
node->background_size = ST_BACKGROUND_SIZE_AUTO;
}
else if (strcmp (property_name, "-color") == 0)
{
GetFromTermResult result;

View File

@@ -49,13 +49,6 @@ typedef enum {
ST_ICON_DOCUMENT
} StIconType;
typedef enum {
ST_BACKGROUND_SIZE_AUTO,
ST_BACKGROUND_SIZE_CONTAIN,
ST_BACKGROUND_SIZE_COVER,
ST_BACKGROUND_SIZE_FIXED
} StBackgroundSize;
G_END_DECLS
#endif /* __ST_TYPES_H__ */

View File

@@ -432,7 +432,7 @@ main (int argc, char **argv)
theme = st_theme_new ("st/test-theme.css",
NULL, NULL);
stage = clutter_stage_new ();
stage = clutter_stage_get_default ();
context = st_theme_context_get_for_stage (CLUTTER_STAGE (stage));
st_theme_context_set_theme (context, theme);
st_theme_context_set_resolution (context, 96.);

View File

@@ -68,7 +68,7 @@ function main() {
section = new Gio.Menu();
section.append('Checkbox', 'app.toggle');
section.append('Disabled', 'app.disable');
menu.append_section('Subsection', section);
menu.append_section(null, section);
// empty sections or submenus should be invisible
menu.append_section('Empty section', new Gio.Menu());

View File

@@ -36,8 +36,7 @@ int main (int argc, char **argv)
clutter_color_from_string (&red, "red");
clutter_color_from_string (&green, "green");
clutter_color_from_string (&blue, "blue");
stage = clutter_stage_new ();
g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
stage = clutter_stage_get_default ();
text = g_object_new (CLUTTER_TYPE_TEXT,
"text", "Red",

View File

@@ -2,7 +2,6 @@ noinst_SCRIPTS = run-test.sh
EXTRA_DIST = run-test.sh.in
TEST_JS = \
interactive/background-size.js \
interactive/borders.js \
interactive/border-radius.js \
interactive/border-width.js \
@@ -17,14 +16,10 @@ TEST_JS = \
interactive/scroll-view-sizing.js \
interactive/table.js \
interactive/transitions.js \
testcommon/100-200.svg \
testcommon/200-100.svg \
testcommon/200-200.svg \
testcommon/border-image.png \
testcommon/face-plain.png \
testcommon/ui.js \
unit/format.js \
unit/insertSorted.js \
unit/markup.js \
unit/jsParse.js \
unit/url.js

View File

@@ -1,89 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const UI = imports.testcommon.ui;
UI.init();
let stage = Clutter.Stage.get_default();
stage.width = 1024;
stage.height = 768;
let vbox = new St.BoxLayout({ width: stage.width,
height: stage.height,
style: 'background: #ffee88;' });
stage.add_actor(vbox);
let scroll = new St.ScrollView();
vbox.add(scroll, { expand: true });
let vbox = new St.BoxLayout({ vertical: true,
style: 'padding: 10px;'
+ 'spacing: 20px;' });
scroll.add_actor(vbox);
let tbox = null;
function addTestCase(image, size, backgroundSize) {
let obin = new St.Bin({ style: 'border: 3px solid green;' });
tbox.add(obin);
let bin = new St.Bin({ style_class: 'background-image-' + image,
width: size.width,
height: size.height,
style: 'border: 1px solid transparent;'
+ 'background-size: ' + backgroundSize + ';',
x_fill: true,
y_fill: true
});
obin.set_child(bin);
bin.set_child(new St.Label({ text: backgroundSize,
style: 'font-size: 15px;'
+ 'text-align: center;'
}));
}
function addTestLine(image, size, backgroundSizes) {
vbox.add(new St.Label({ text: image + '.svg / ' + size.width + '×' + size.height,
style: 'font-size: 15px;'
+ 'text-align: center;'
}));
tbox = new St.BoxLayout({ style: 'spacing: 20px;' });
vbox.add(tbox);
if (backgroundSizes.length == 2)
addTestCase(image, size, "auto");
for each (let s in backgroundSizes)
addTestCase(image, size, s);
}
let size1 = { width: 200, height: 200 }
let size2 = { width: 250, height: 250 }
let size3 = { width: 100, height: 100 }
// fixed size
addTestLine('200-200', size1, ["200px 200px", "100px 100px", "100px 200px"]);
// same size
addTestLine('200-200', size1, ["contain", "cover"]);
// smaller
addTestLine('200-200', size2, ["contain", "cover"]);
// larger
addTestLine('200-200', size3, ["contain", "cover"]);
addTestLine('200-100', size1, ["contain", "cover"]);
addTestLine('200-100', size2, ["contain", "cover"]);
addTestLine('200-100', size3, ["contain", "cover"]);
addTestLine('100-200', size1, ["contain", "cover"]);
addTestLine('100-200', size2, ["contain", "cover"]);
addTestLine('100-200', size3, ["contain", "cover"]);
stage.show();
Clutter.main();
stage.destroy();

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 200" width="100" height="200">
<path
d="
M 2,2 h 96 v 196 h -96 v -196
M 8,8 h 84 v 184 h -84 v -184
"
fill="white"
stroke="blue"
stroke-width="2"
stroke-linecap="square"
/>
<path
d="
M 10,10 h 20 v 20 h -20 v -20
"
fill="green"
/>
</svg>

Before

Width:  |  Height:  |  Size: 518 B

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 100" width="200" height="100">
<path
d="
M 2,2 h 196 v 96 h -196 v -96
M 8,8 h 184 v 84 h -184 v -84
"
fill="white"
stroke="blue"
stroke-width="2"
stroke-linecap="square"
/>
<path
d="
M 10,10 h 20 v 20 h -20 v -20
"
fill="green"
/>
</svg>

Before

Width:  |  Height:  |  Size: 518 B

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 200" width="200" height="200">
<path
d="
M 2,2 h 196 v 196 h -196 v -196
M 8,8 h 184 v 184 h -184 v -184
"
fill="white"
stroke="blue"
stroke-width="2"
stroke-linecap="square"
/>
<path
d="
M 10,10 h 20 v 20 h -20 v -20
"
fill="green"
/>
</svg>

Before

Width:  |  Height:  |  Size: 522 B

View File

@@ -37,18 +37,6 @@ stage {
border-image: url('border-image.png') 16;
}
.background-image-200-200 {
background-image: url('200-200.svg');
}
.background-image-100-200 {
background-image: url('100-200.svg');
}
.background-image-200-100 {
background-image: url('200-100.svg');
}
.background-gradient {
background-gradient-start: rgba(127, 255, 127, .6);
background-gradient-end: rgba(127, 127, 255, .6);

View File

@@ -1,76 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
// Test cases for Util.insertSorted
const JsUnit = imports.jsUnit;
// Needed so that Util can bring some UI stuff
// we don't actually use
const Environment = imports.ui.environment;
Environment.init();
const Util = imports.misc.util;
function assertArrayEquals(errorMessage, array1, array2) {
JsUnit.assertEquals(errorMessage + ' length',
array1.length, array2.length);
for (let j = 0; j < array1.length; j++) {
JsUnit.assertEquals(errorMessage + ' item ' + j,
array1[j], array2[j]);
}
}
function cmp(one, two) {
return one-two;
}
let arrayInt = [1, 2, 3, 5, 6];
Util.insertSorted(arrayInt, 4, cmp);
assertArrayEquals('first test', [1,2,3,4,5,6], arrayInt);
// no comparator, integer sorting is implied
Util.insertSorted(arrayInt, 3);
assertArrayEquals('second test', [1,2,3,3,4,5,6], arrayInt);
let obj1 = { a: 1 };
let obj2 = { a: 2, b: 0 };
let obj3 = { a: 2, b: 1 };
let obj4 = { a: 3 };
function objCmp(one, two) {
return one.a - two.a;
}
let arrayObj = [obj1, obj3, obj4];
// obj2 compares equivalent to obj3, should be
// inserted before
Util.insertSorted(arrayObj, obj2, objCmp);
assertArrayEquals('object test', [obj1, obj2, obj3, obj4], arrayObj);
function checkedCmp(one, two) {
if (typeof one != 'number' ||
typeof two != 'number')
throw new TypeError('Invalid type passed to checkedCmp');
return one-two;
}
let arrayEmpty = [];
// check that no comparisons are made when
// inserting in a empty array
Util.insertSorted(arrayEmpty, 3, checkedCmp);
// Insert at the end and check that we don't
// access past it
Util.insertSorted(arrayEmpty, 4, checkedCmp);
Util.insertSorted(arrayEmpty, 5, checkedCmp);
// Some more insertions
Util.insertSorted(arrayEmpty, 2, checkedCmp);
Util.insertSorted(arrayEmpty, 1, checkedCmp);
assertArrayEquals('checkedCmp test', [1, 2, 3, 4, 5], arrayEmpty);