Bug 578584 - Use the wallpaper for the overlay background
The overlay looks nicer with the root window pixmap drawn on the background. It is scaled up to twice the size, with positioning based on the rule of thirds. The sideshow animations shown when entering or leaving the overlay and toggling the extended view were implemented by Marina Zhurakhinskaya. They replace the old method of having a black rectangle behind the workspaces that partly covers the sideshow during transitions. configure.ac: Add gdk-x11, clutter-x11 and clutter-glx modules. overlay.js: Add a root window pixmap actor, make sideshow width definitions more logical, replace the way the sideshow animates when entering or leaving the overlay. workspaces.js: Remove the backdrop, add helper functions for the overlay transitions. shell-global.[ch]: Add a method that creates an actor displaying the root window pixmap and returning clones of it.
This commit is contained in:
parent
822ef09350
commit
7c8cb8450c
@ -38,7 +38,7 @@ fi
|
|||||||
|
|
||||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||||
|
|
||||||
PKG_CHECK_MODULES(MUTTER_PLUGIN, gtk+-2.0 dbus-glib-1 metacity-plugins gjs-gi-1.0 libgnome-menu $recorder_modules)
|
PKG_CHECK_MODULES(MUTTER_PLUGIN, gtk+-2.0 dbus-glib-1 metacity-plugins gjs-gi-1.0 libgnome-menu gdk-x11-2.0 clutter-x11-0.9 clutter-glx-0.9 $recorder_modules)
|
||||||
PKG_CHECK_MODULES(TIDY, clutter-0.9)
|
PKG_CHECK_MODULES(TIDY, clutter-0.9)
|
||||||
PKG_CHECK_MODULES(BIG, clutter-0.9 gtk+-2.0 librsvg-2.0)
|
PKG_CHECK_MODULES(BIG, clutter-0.9 gtk+-2.0 librsvg-2.0)
|
||||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
|
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
|
||||||
|
204
js/ui/overlay.js
204
js/ui/overlay.js
@ -18,8 +18,12 @@ const Panel = imports.ui.panel;
|
|||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const Workspaces = imports.ui.workspaces;
|
const Workspaces = imports.ui.workspaces;
|
||||||
|
|
||||||
const OVERLAY_BACKGROUND_COLOR = new Clutter.Color();
|
const ROOT_OVERLAY_COLOR = new Clutter.Color();
|
||||||
OVERLAY_BACKGROUND_COLOR.from_pixel(0x000000ff);
|
ROOT_OVERLAY_COLOR.from_pixel(0x000000bb);
|
||||||
|
|
||||||
|
// The factor to scale the overlay wallpaper with. This should not be less
|
||||||
|
// than 3/2, because the rule of thirds is used for positioning (see below).
|
||||||
|
const BACKGROUND_SCALE = 2;
|
||||||
|
|
||||||
const LABEL_HEIGHT = 16;
|
const LABEL_HEIGHT = 16;
|
||||||
// We use SIDESHOW_PAD for the padding on the left side of the sideshow and as a gap
|
// We use SIDESHOW_PAD for the padding on the left side of the sideshow and as a gap
|
||||||
@ -138,19 +142,23 @@ Sideshow.prototype = {
|
|||||||
let asideXFactor = wideScreen ? WORKSPACES_X_FACTOR_ASIDE_MODE_WIDE_SCREEN : WORKSPACES_X_FACTOR_ASIDE_MODE_REGULAR_SCREEN;
|
let asideXFactor = wideScreen ? WORKSPACES_X_FACTOR_ASIDE_MODE_WIDE_SCREEN : WORKSPACES_X_FACTOR_ASIDE_MODE_REGULAR_SCREEN;
|
||||||
this._expandedSideshowColumns = wideScreen ? EXPANDED_SIDESHOW_COLUMNS_WIDE_SCREEN : EXPANDED_SIDESHOW_COLUMNS_REGULAR_SCREEN;
|
this._expandedSideshowColumns = wideScreen ? EXPANDED_SIDESHOW_COLUMNS_WIDE_SCREEN : EXPANDED_SIDESHOW_COLUMNS_REGULAR_SCREEN;
|
||||||
|
|
||||||
this._width = displayGridColumnWidth - SIDESHOW_PAD;
|
this._width = displayGridColumnWidth;
|
||||||
|
this._displayWidth = this._width - SIDESHOW_PAD;
|
||||||
|
|
||||||
|
this._expandedWidth = displayGridColumnWidth * asideXFactor;
|
||||||
|
|
||||||
// this figures out the additional width we can give to the display in the 'More' mode,
|
// this figures out the additional width we can give to the display in the 'More' mode,
|
||||||
// assuming that we want to keep the columns the same width in both modes
|
// assuming that we want to keep the columns the same width in both modes
|
||||||
this._additionalWidth = ((this._width + SIDESHOW_PAD) / SIDESHOW_COLUMNS) *
|
this._additionalWidth = (this._width / SIDESHOW_COLUMNS) *
|
||||||
(this._expandedSideshowColumns - SIDESHOW_COLUMNS);
|
(this._expandedSideshowColumns - SIDESHOW_COLUMNS);
|
||||||
|
|
||||||
let previewWidth = displayGridColumnWidth * asideXFactor - this._width -
|
let previewWidth = this._expandedWidth - this._width -
|
||||||
this._additionalWidth - SIDESHOW_SECTION_SPACING * 2;
|
this._additionalWidth - SIDESHOW_SECTION_SPACING;
|
||||||
|
|
||||||
let global = Shell.Global.get();
|
let global = Shell.Global.get();
|
||||||
this.actor = new Clutter.Group();
|
this.actor = new Clutter.Group();
|
||||||
this._searchEntry = new SearchEntry(this._width);
|
this.actor.height = global.screen_height;
|
||||||
|
this._searchEntry = new SearchEntry(this._displayWidth);
|
||||||
this.actor.add_actor(this._searchEntry.actor);
|
this.actor.add_actor(this._searchEntry.actor);
|
||||||
|
|
||||||
this._searchEntry.actor.set_position(SIDESHOW_PAD, Panel.PANEL_HEIGHT + SIDESHOW_PAD);
|
this._searchEntry.actor.set_position(SIDESHOW_PAD, Panel.PANEL_HEIGHT + SIDESHOW_PAD);
|
||||||
@ -246,8 +254,7 @@ Sideshow.prototype = {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
this._appsSection = new Big.Box({ background_color: OVERLAY_BACKGROUND_COLOR,
|
this._appsSection = new Big.Box({ x: SIDESHOW_PAD,
|
||||||
x: SIDESHOW_PAD,
|
|
||||||
y: this._searchEntry.actor.y + this._searchEntry.actor.height,
|
y: this._searchEntry.actor.y + this._searchEntry.actor.height,
|
||||||
padding_top: SIDESHOW_SECTION_PADDING_TOP,
|
padding_top: SIDESHOW_SECTION_PADDING_TOP,
|
||||||
spacing: SIDESHOW_SECTION_SPACING});
|
spacing: SIDESHOW_SECTION_SPACING});
|
||||||
@ -265,7 +272,7 @@ Sideshow.prototype = {
|
|||||||
|
|
||||||
this._appsContent = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
|
this._appsContent = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
|
||||||
this._appsSection.append(this._appsContent, Big.BoxPackFlags.EXPAND);
|
this._appsSection.append(this._appsContent, Big.BoxPackFlags.EXPAND);
|
||||||
this._appDisplay = new AppDisplay.AppDisplay(this._width, this._itemDisplayHeight / 2, SIDESHOW_COLUMNS, SIDESHOW_PAD);
|
this._appDisplay = new AppDisplay.AppDisplay(this._displayWidth, this._itemDisplayHeight / 2, SIDESHOW_COLUMNS, SIDESHOW_PAD);
|
||||||
let sideArea = this._appDisplay.getSideArea();
|
let sideArea = this._appDisplay.getSideArea();
|
||||||
sideArea.hide();
|
sideArea.hide();
|
||||||
this._appsContent.append(sideArea, Big.BoxPackFlags.NONE);
|
this._appsContent.append(sideArea, Big.BoxPackFlags.NONE);
|
||||||
@ -286,8 +293,7 @@ Sideshow.prototype = {
|
|||||||
this._appsDisplayControlBox = new Big.Box({x_align: Big.BoxAlignment.CENTER});
|
this._appsDisplayControlBox = new Big.Box({x_align: Big.BoxAlignment.CENTER});
|
||||||
this._appsDisplayControlBox.append(this._appDisplay.displayControl, Big.BoxPackFlags.NONE);
|
this._appsDisplayControlBox.append(this._appDisplay.displayControl, Big.BoxPackFlags.NONE);
|
||||||
|
|
||||||
this._docsSection = new Big.Box({ background_color: OVERLAY_BACKGROUND_COLOR,
|
this._docsSection = new Big.Box({ x: SIDESHOW_PAD,
|
||||||
x: SIDESHOW_PAD,
|
|
||||||
y: this._appsSection.y + this._appsSection.height,
|
y: this._appsSection.y + this._appsSection.height,
|
||||||
padding_top: SIDESHOW_SECTION_PADDING_TOP,
|
padding_top: SIDESHOW_SECTION_PADDING_TOP,
|
||||||
spacing: SIDESHOW_SECTION_SPACING});
|
spacing: SIDESHOW_SECTION_SPACING});
|
||||||
@ -298,7 +304,7 @@ Sideshow.prototype = {
|
|||||||
height: LABEL_HEIGHT});
|
height: LABEL_HEIGHT});
|
||||||
this._docsSection.append(this._docsText, Big.BoxPackFlags.EXPAND);
|
this._docsSection.append(this._docsText, Big.BoxPackFlags.EXPAND);
|
||||||
|
|
||||||
this._docDisplay = new DocDisplay.DocDisplay(this._width, this._itemDisplayHeight - this._appsContent.height, SIDESHOW_COLUMNS, SIDESHOW_PAD);
|
this._docDisplay = new DocDisplay.DocDisplay(this._displayWidth, this._itemDisplayHeight - this._appsContent.height, SIDESHOW_COLUMNS, SIDESHOW_PAD);
|
||||||
this._docsSection.append(this._docDisplay.actor, Big.BoxPackFlags.EXPAND);
|
this._docsSection.append(this._docDisplay.actor, Big.BoxPackFlags.EXPAND);
|
||||||
|
|
||||||
let moreDocsBox = new Big.Box({x_align: Big.BoxAlignment.END});
|
let moreDocsBox = new Big.Box({x_align: Big.BoxAlignment.END});
|
||||||
@ -316,7 +322,7 @@ Sideshow.prototype = {
|
|||||||
this._docsDisplayControlBox = new Big.Box({x_align: Big.BoxAlignment.CENTER});
|
this._docsDisplayControlBox = new Big.Box({x_align: Big.BoxAlignment.CENTER});
|
||||||
this._docsDisplayControlBox.append(this._docDisplay.displayControl, Big.BoxPackFlags.NONE);
|
this._docsDisplayControlBox.append(this._docDisplay.displayControl, Big.BoxPackFlags.NONE);
|
||||||
|
|
||||||
this._details = new Big.Box({ x: SIDESHOW_PAD + this._width + this._additionalWidth + SIDESHOW_SECTION_SPACING,
|
this._details = new Big.Box({ x: this._width + this._additionalWidth + SIDESHOW_SECTION_SPACING,
|
||||||
y: Panel.PANEL_HEIGHT + SIDESHOW_PAD,
|
y: Panel.PANEL_HEIGHT + SIDESHOW_PAD,
|
||||||
width: previewWidth,
|
width: previewWidth,
|
||||||
height: global.screen_height - Panel.PANEL_HEIGHT - SIDESHOW_PAD - bottomHeight,
|
height: global.screen_height - Panel.PANEL_HEIGHT - SIDESHOW_PAD - bottomHeight,
|
||||||
@ -451,6 +457,13 @@ Sideshow.prototype = {
|
|||||||
onCompleteScope: this
|
onCompleteScope: this
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.actor.set_clip(0, 0, this.actor.width, this.actor.height);
|
||||||
|
Tweener.addTween(this.actor,
|
||||||
|
{ clipWidthRight: this._expandedWidth,
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: "easeOutQuad"
|
||||||
|
});
|
||||||
|
|
||||||
this.emit('more-activated');
|
this.emit('more-activated');
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -464,7 +477,7 @@ Sideshow.prototype = {
|
|||||||
this._moreAppsLink.actor.hide();
|
this._moreAppsLink.actor.hide();
|
||||||
|
|
||||||
this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height);
|
this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height);
|
||||||
|
this.actor.set_clip(0, 0, this.actor.width, this.actor.height);
|
||||||
this._docDisplay.show();
|
this._docDisplay.show();
|
||||||
|
|
||||||
// We need to be reducing the clip on the applications section so that the last application to
|
// We need to be reducing the clip on the applications section so that the last application to
|
||||||
@ -483,7 +496,11 @@ Sideshow.prototype = {
|
|||||||
time: ANIMATION_TIME,
|
time: ANIMATION_TIME,
|
||||||
transition: "easeOutQuad"
|
transition: "easeOutQuad"
|
||||||
});
|
});
|
||||||
|
Tweener.addTween(this.actor,
|
||||||
|
{ clipWidthRight: this._width,
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: "easeOutQuad"
|
||||||
|
});
|
||||||
this.emit('less-activated');
|
this.emit('less-activated');
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -492,6 +509,7 @@ Sideshow.prototype = {
|
|||||||
_onAppsSectionExpanded: function() {
|
_onAppsSectionExpanded: function() {
|
||||||
this._appsSection.remove_clip();
|
this._appsSection.remove_clip();
|
||||||
this._docDisplay.hide();
|
this._docDisplay.hide();
|
||||||
|
this.actor.remove_clip();
|
||||||
},
|
},
|
||||||
|
|
||||||
// Updates the applications section to contain fewer items. Selects the first item in the
|
// Updates the applications section to contain fewer items. Selects the first item in the
|
||||||
@ -500,6 +518,7 @@ Sideshow.prototype = {
|
|||||||
// Removes the clip from the documents section, so that the clip does not limit the size of
|
// Removes the clip from the documents section, so that the clip does not limit the size of
|
||||||
// the section if it is expanded later.
|
// the section if it is expanded later.
|
||||||
_onAppsSectionReduced: function() {
|
_onAppsSectionReduced: function() {
|
||||||
|
this.actor.remove_clip();
|
||||||
if (this._moreAppsMode != STATE_PENDING_INACTIVE)
|
if (this._moreAppsMode != STATE_PENDING_INACTIVE)
|
||||||
return;
|
return;
|
||||||
this._moreAppsMode = STATE_INACTIVE;
|
this._moreAppsMode = STATE_INACTIVE;
|
||||||
@ -516,7 +535,7 @@ Sideshow.prototype = {
|
|||||||
_updateAppsSection: function() {
|
_updateAppsSection: function() {
|
||||||
if (this._moreAppsMode) {
|
if (this._moreAppsMode) {
|
||||||
// Subtract one from columns since we are displaying menus
|
// Subtract one from columns since we are displaying menus
|
||||||
this._appDisplay.setExpanded(true, this._width, this._additionalWidth,
|
this._appDisplay.setExpanded(true, this._displayWidth, this._additionalWidth,
|
||||||
this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT,
|
this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT,
|
||||||
this._expandedSideshowColumns - 1);
|
this._expandedSideshowColumns - 1);
|
||||||
this._moreAppsLink.setText("Less...");
|
this._moreAppsLink.setText("Less...");
|
||||||
@ -524,7 +543,7 @@ Sideshow.prototype = {
|
|||||||
this.actor.add_actor(this._details);
|
this.actor.add_actor(this._details);
|
||||||
this._details.append(this._appDisplay.selectedItemDetails, Big.BoxPackFlags.NONE);
|
this._details.append(this._appDisplay.selectedItemDetails, Big.BoxPackFlags.NONE);
|
||||||
} else {
|
} else {
|
||||||
this._appDisplay.setExpanded(false, this._width, 0,
|
this._appDisplay.setExpanded(false, this._displayWidth, 0,
|
||||||
this._appsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT,
|
this._appsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT,
|
||||||
SIDESHOW_COLUMNS);
|
SIDESHOW_COLUMNS);
|
||||||
this._moreAppsLink.setText("More...");
|
this._moreAppsLink.setText("More...");
|
||||||
@ -550,6 +569,8 @@ Sideshow.prototype = {
|
|||||||
this._moreDocsLink.actor.hide();
|
this._moreDocsLink.actor.hide();
|
||||||
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
|
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
|
||||||
|
|
||||||
|
this.actor.set_clip(0, 0, this.actor.width, this.actor.height);
|
||||||
|
|
||||||
// Move the selection to the docs section if it was in the apps section.
|
// Move the selection to the docs section if it was in the apps section.
|
||||||
this._appDisplay.unsetSelected();
|
this._appDisplay.unsetSelected();
|
||||||
if (!this._docDisplay.hasSelected())
|
if (!this._docDisplay.hasSelected())
|
||||||
@ -575,6 +596,13 @@ Sideshow.prototype = {
|
|||||||
onComplete: this._onDocsSectionExpanded,
|
onComplete: this._onDocsSectionExpanded,
|
||||||
onCompleteScope: this
|
onCompleteScope: this
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Tweener.addTween(this.actor,
|
||||||
|
{ clipWidthRight: this._expandedWidth,
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: "easeOutQuad"
|
||||||
|
});
|
||||||
|
|
||||||
this.emit('more-activated');
|
this.emit('more-activated');
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -589,7 +617,7 @@ Sideshow.prototype = {
|
|||||||
this._moreDocsLink.actor.hide();
|
this._moreDocsLink.actor.hide();
|
||||||
|
|
||||||
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
|
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
|
||||||
|
this.actor.set_clip(0, 0, this.actor.width, this.actor.height);
|
||||||
this._appsContent.show();
|
this._appsContent.show();
|
||||||
|
|
||||||
Tweener.addTween(this._docsSection,
|
Tweener.addTween(this._docsSection,
|
||||||
@ -606,6 +634,12 @@ Sideshow.prototype = {
|
|||||||
time: ANIMATION_TIME,
|
time: ANIMATION_TIME,
|
||||||
transition: "easeOutQuad"
|
transition: "easeOutQuad"
|
||||||
});
|
});
|
||||||
|
Tweener.addTween(this.actor,
|
||||||
|
{ clipWidthRight: this._width,
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: "easeOutQuad"
|
||||||
|
});
|
||||||
|
|
||||||
this.emit('less-activated');
|
this.emit('less-activated');
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -614,6 +648,7 @@ Sideshow.prototype = {
|
|||||||
_onDocsSectionExpanded: function() {
|
_onDocsSectionExpanded: function() {
|
||||||
this._docsSection.remove_clip();
|
this._docsSection.remove_clip();
|
||||||
this._appsContent.hide();
|
this._appsContent.hide();
|
||||||
|
this.actor.remove_clip();
|
||||||
},
|
},
|
||||||
|
|
||||||
// Updates the documents section to contain fewer items. Selects the first item in the
|
// Updates the documents section to contain fewer items. Selects the first item in the
|
||||||
@ -622,6 +657,7 @@ Sideshow.prototype = {
|
|||||||
// Removes the clip from the applications section, so that the clip does not limit the size of
|
// Removes the clip from the applications section, so that the clip does not limit the size of
|
||||||
// the section if it is expanded later.
|
// the section if it is expanded later.
|
||||||
_onDocsSectionReduced: function() {
|
_onDocsSectionReduced: function() {
|
||||||
|
this.actor.remove_clip();
|
||||||
this._updateDocsSection();
|
this._updateDocsSection();
|
||||||
if (!this._docDisplay.hasItems())
|
if (!this._docDisplay.hasItems())
|
||||||
this._appDisplay.selectFirstItem();
|
this._appDisplay.selectFirstItem();
|
||||||
@ -634,7 +670,7 @@ Sideshow.prototype = {
|
|||||||
// changed, which is ensured by _setMoreDocsMode() and _unsetMoreDocsMode() functions.
|
// changed, which is ensured by _setMoreDocsMode() and _unsetMoreDocsMode() functions.
|
||||||
_updateDocsSection: function() {
|
_updateDocsSection: function() {
|
||||||
if (this._moreDocsMode) {
|
if (this._moreDocsMode) {
|
||||||
this._docDisplay.setExpanded(true, this._width, this._additionalWidth,
|
this._docDisplay.setExpanded(true, this._displayWidth, this._additionalWidth,
|
||||||
this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT,
|
this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT,
|
||||||
this._expandedSideshowColumns);
|
this._expandedSideshowColumns);
|
||||||
this._moreDocsLink.setText("Less...");
|
this._moreDocsLink.setText("Less...");
|
||||||
@ -642,7 +678,7 @@ Sideshow.prototype = {
|
|||||||
this.actor.add_actor(this._details);
|
this.actor.add_actor(this._details);
|
||||||
this._details.append(this._docDisplay.selectedItemDetails, Big.BoxPackFlags.NONE);
|
this._details.append(this._docDisplay.selectedItemDetails, Big.BoxPackFlags.NONE);
|
||||||
} else {
|
} else {
|
||||||
this._docDisplay.setExpanded(false, this._width, 0,
|
this._docDisplay.setExpanded(false, this._displayWidth, 0,
|
||||||
this._docsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT,
|
this._docsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT,
|
||||||
SIDESHOW_COLUMNS);
|
SIDESHOW_COLUMNS);
|
||||||
this._moreDocsLink.setText("More...");
|
this._moreDocsLink.setText("More...");
|
||||||
@ -684,14 +720,25 @@ Overlay.prototype = {
|
|||||||
this.visible = false;
|
this.visible = false;
|
||||||
this._hideInProgress = false;
|
this._hideInProgress = false;
|
||||||
|
|
||||||
let background = new Clutter.Rectangle({ color: OVERLAY_BACKGROUND_COLOR,
|
// A scaled root pixmap actor is used as a background. It is zoomed in
|
||||||
reactive: true,
|
// to the lower right intersection of the lines that divide the image
|
||||||
x: 0,
|
// evenly in a 3x3 grid. This is based on the rule of thirds, a
|
||||||
y: 0,
|
// compositional rule of thumb in visual arts. The choice for the
|
||||||
width: global.screen_width,
|
// lower right point is based on a quick survey of GNOME wallpapers.
|
||||||
height: global.screen_width });
|
let background = global.create_root_pixmap_actor();
|
||||||
|
background.width = global.screen_width * BACKGROUND_SCALE;
|
||||||
|
background.height = global.screen_height * BACKGROUND_SCALE;
|
||||||
|
background.x = -global.screen_width * (4 * BACKGROUND_SCALE - 3) / 6;
|
||||||
|
background.y = -global.screen_height * (4 * BACKGROUND_SCALE - 3) / 6;
|
||||||
this._group.add_actor(background);
|
this._group.add_actor(background);
|
||||||
|
|
||||||
|
// Draw a semitransparent rectangle over the background for readability.
|
||||||
|
let backOver = new Clutter.Rectangle({ color: ROOT_OVERLAY_COLOR,
|
||||||
|
width: global.screen_width,
|
||||||
|
height: global.screen_height - Panel.PANEL_HEIGHT,
|
||||||
|
y: Panel.PANEL_HEIGHT });
|
||||||
|
this._group.add_actor(backOver);
|
||||||
|
|
||||||
this._group.hide();
|
this._group.hide();
|
||||||
global.overlay_group.add_actor(this._group);
|
global.overlay_group.add_actor(this._group);
|
||||||
|
|
||||||
@ -699,7 +746,6 @@ Overlay.prototype = {
|
|||||||
this._sideshow = new Sideshow();
|
this._sideshow = new Sideshow();
|
||||||
this._group.add_actor(this._sideshow.actor);
|
this._group.add_actor(this._sideshow.actor);
|
||||||
this._workspaces = null;
|
this._workspaces = null;
|
||||||
this._workspacesBackground = null;
|
|
||||||
this._sideshow.connect('activated', function(sideshow) {
|
this._sideshow.connect('activated', function(sideshow) {
|
||||||
// TODO - have some sort of animation/effect while
|
// TODO - have some sort of animation/effect while
|
||||||
// transitioning to the new app. We definitely need
|
// transitioning to the new app. We definitely need
|
||||||
@ -713,17 +759,6 @@ Overlay.prototype = {
|
|||||||
let workspacesX = displayGridColumnWidth * asideXFactor + WORKSPACE_GRID_PADDING;
|
let workspacesX = displayGridColumnWidth * asideXFactor + WORKSPACE_GRID_PADDING;
|
||||||
me._workspaces.addButton.hide();
|
me._workspaces.addButton.hide();
|
||||||
me._workspaces.updatePosition(workspacesX, null);
|
me._workspaces.updatePosition(workspacesX, null);
|
||||||
// lower the sideshow below the workspaces background, so that the workspaces
|
|
||||||
// background covers the parts of the sideshow that are gradually being
|
|
||||||
// revealed from underneath it
|
|
||||||
me._sideshow.actor.lower(me._workspacesBackground);
|
|
||||||
Tweener.addTween(me._workspacesBackground,
|
|
||||||
{ x: displayGridColumnWidth * asideXFactor,
|
|
||||||
time: ANIMATION_TIME,
|
|
||||||
transition: "easeOutQuad",
|
|
||||||
onComplete: me._animationDone,
|
|
||||||
onCompleteScope: me
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this._sideshow.connect('less-activated', function(sideshow) {
|
this._sideshow.connect('less-activated', function(sideshow) {
|
||||||
@ -731,16 +766,6 @@ Overlay.prototype = {
|
|||||||
let workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
|
let workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
|
||||||
me._workspaces.addButton.show();
|
me._workspaces.addButton.show();
|
||||||
me._workspaces.updatePosition(workspacesX, null);
|
me._workspaces.updatePosition(workspacesX, null);
|
||||||
// lower the sideshow below the workspaces background, so that the workspaces
|
|
||||||
// background covers the parts of the sideshow as it slides in over them
|
|
||||||
me._sideshow.actor.lower(me._workspacesBackground);
|
|
||||||
Tweener.addTween(me._workspacesBackground,
|
|
||||||
{ x: displayGridColumnWidth,
|
|
||||||
time: ANIMATION_TIME,
|
|
||||||
transition: "easeOutQuad",
|
|
||||||
onComplete: me._animationDone,
|
|
||||||
onCompleteScope: me
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -790,18 +815,6 @@ Overlay.prototype = {
|
|||||||
let addButtonX = workspacesX + workspacesWidth - addButtonSize;
|
let addButtonX = workspacesX + workspacesWidth - addButtonSize;
|
||||||
let addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5);
|
let addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5);
|
||||||
|
|
||||||
// We use the workspaces background to have it fill the full height of the overlay when we are sliding
|
|
||||||
// the workspaces out to uncover the expanded items display and also when we are sliding the
|
|
||||||
// workspaces back in to gradually cover the expanded items display. If we don't have such background,
|
|
||||||
// we get a few items above or below the workspaces display that disappear or appear abruptly.
|
|
||||||
this._workspacesBackground = new Clutter.Rectangle({ color: OVERLAY_BACKGROUND_COLOR,
|
|
||||||
reactive: false,
|
|
||||||
x: displayGridColumnWidth,
|
|
||||||
y: Panel.PANEL_HEIGHT,
|
|
||||||
width: displayGridColumnWidth * columnsUsed,
|
|
||||||
height: global.screen_height - Panel.PANEL_HEIGHT });
|
|
||||||
this._group.add_actor(this._workspacesBackground);
|
|
||||||
|
|
||||||
this._workspaces = new Workspaces.Workspaces(workspacesWidth, workspacesHeight, workspacesX, workspacesY,
|
this._workspaces = new Workspaces.Workspaces(workspacesWidth, workspacesHeight, workspacesX, workspacesY,
|
||||||
addButtonSize, addButtonX, addButtonY);
|
addButtonSize, addButtonX, addButtonY);
|
||||||
this._group.add_actor(this._workspaces.actor);
|
this._group.add_actor(this._workspaces.actor);
|
||||||
@ -816,11 +829,26 @@ Overlay.prototype = {
|
|||||||
global.window_group.hide();
|
global.window_group.hide();
|
||||||
this._group.show();
|
this._group.show();
|
||||||
|
|
||||||
// Dummy tween, just waiting for the workspace animation
|
// Try to make the menu not too visible behind the empty space between
|
||||||
Tweener.addTween(this,
|
// the workspace previews by sliding in its clipping rectangle.
|
||||||
{ time: ANIMATION_TIME,
|
// We want to finish drawing the sideshow just before the top workspace fully
|
||||||
onComplete: this._animationDone,
|
// slides in on the top. Which means that we have more time to wait before
|
||||||
|
// drawing the sideshow if the active workspace is displayed on the bottom of
|
||||||
|
// the workspaces grid, and almost no time to wait if it is displayed in the top
|
||||||
|
// row of the workspaces grid. The calculations used below try to roughly
|
||||||
|
// capture the animation ratio for when workspaces are covering the top of the overlay
|
||||||
|
// vs. when workspaces are already below the top of the overlay, and apply it
|
||||||
|
// to clipping the sideshow. The clipping is removed in this._showDone().
|
||||||
|
this._sideshow.actor.set_clip(0, 0,
|
||||||
|
this._workspaces.getFullSizeX(),
|
||||||
|
this._sideshow.actor.height);
|
||||||
|
Tweener.addTween(this._sideshow.actor,
|
||||||
|
{ clipWidthRight: this._sideshow._width + WORKSPACE_GRID_PADDING + this._workspaces.getWidthToTopActiveWorkspace(),
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: "easeOutQuad",
|
||||||
|
onComplete: this._showDone,
|
||||||
onCompleteScope: this
|
onCompleteScope: this
|
||||||
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -828,14 +856,28 @@ Overlay.prototype = {
|
|||||||
if (!this.visible || this._hideInProgress)
|
if (!this.visible || this._hideInProgress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
let global = Shell.Global.get();
|
||||||
|
|
||||||
this._hideInProgress = true;
|
this._hideInProgress = true;
|
||||||
// lower the sideshow, so that workspaces display is on top and covers the sideshow while it is sliding out
|
// lower the sideshow, so that workspaces display is on top and covers the sideshow while it is sliding out
|
||||||
this._sideshow.actor.lower(this._workspacesBackground);
|
this._sideshow.actor.lower(this._workspaces.actor);
|
||||||
this._workspaces.hide();
|
this._workspaces.hide();
|
||||||
|
|
||||||
// Dummy tween, just waiting for the workspace animation
|
// Try to make the menu not too visible behind the empty space between
|
||||||
Tweener.addTween(this,
|
// the workspace previews by sliding in its clipping rectangle.
|
||||||
{ time: ANIMATION_TIME,
|
// The logic used is the same as described in this.show(). If the active workspace
|
||||||
|
// is displayed in the top row, than almost full animation time is needed for it
|
||||||
|
// to reach the top of the overlay and cover the sideshow fully, while if the
|
||||||
|
// active workspace is in the lower row, than the top left workspace reaches the
|
||||||
|
// top of the overlay sooner as it is moving out of the way.
|
||||||
|
// The clipping is removed in this._hideDone().
|
||||||
|
this._sideshow.actor.set_clip(0, 0,
|
||||||
|
this._sideshow.actor.width + WORKSPACE_GRID_PADDING + this._workspaces.getWidthToTopActiveWorkspace(),
|
||||||
|
this._sideshow.actor.height);
|
||||||
|
Tweener.addTween(this._sideshow.actor,
|
||||||
|
{ clipWidthRight: this._workspaces.getFullSizeX() + this._workspaces.getWidthToTopActiveWorkspace() - global.screen_width,
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: "easeOutQuad",
|
||||||
onComplete: this._hideDone,
|
onComplete: this._hideDone,
|
||||||
onCompleteScope: this
|
onCompleteScope: this
|
||||||
});
|
});
|
||||||
@ -844,20 +886,19 @@ Overlay.prototype = {
|
|||||||
//// Private methods ////
|
//// Private methods ////
|
||||||
|
|
||||||
// Raises the sideshow to the top, so that we can tell if the pointer is above one of its items.
|
// Raises the sideshow to the top, so that we can tell if the pointer is above one of its items.
|
||||||
// We need to do this every time animation of the workspaces is done bacause the workspaces actor
|
// We need to do this once the workspaces are shown because the workspaces actor currently covers
|
||||||
// currently covers the whole screen, regardless of where the workspaces are actually displayed.
|
// the whole screen, regardless of where the workspaces are actually displayed.
|
||||||
// On the other hand, we need the workspaces to be on top when they are sliding in, out,
|
|
||||||
// and to the side because we want them to cover the sideshow as they do that.
|
|
||||||
//
|
//
|
||||||
// Once we rework the workspaces actor to only cover the area it actually needs, we can
|
// Once we rework the workspaces actor to only cover the area it actually needs, we can
|
||||||
// remove this workaround. Also http://bugzilla.openedhand.com/show_bug.cgi?id=1513 requests being
|
// remove this workaround. Also http://bugzilla.openedhand.com/show_bug.cgi?id=1513 requests being
|
||||||
// able to pick only a reactive actor at a certain position, rather than any actor. Being able
|
// able to pick only a reactive actor at a certain position, rather than any actor. Being able
|
||||||
// to do that would allow us to not have to raise the sideshow.
|
// to do that would allow us to not have to raise the sideshow.
|
||||||
_animationDone: function() {
|
_showDone: function() {
|
||||||
if (this._hideInProgress)
|
if (this._hideInProgress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._sideshow.actor.raise_top();
|
this._sideshow.actor.raise_top();
|
||||||
|
this._sideshow.actor.remove_clip();
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideDone: function() {
|
_hideDone: function() {
|
||||||
@ -868,9 +909,7 @@ Overlay.prototype = {
|
|||||||
this._workspaces.destroy();
|
this._workspaces.destroy();
|
||||||
this._workspaces = null;
|
this._workspaces = null;
|
||||||
|
|
||||||
this._workspacesBackground.destroy();
|
this._sideshow.actor.remove_clip();
|
||||||
this._workspacesBackground = null;
|
|
||||||
|
|
||||||
this._sideshow.hide();
|
this._sideshow.hide();
|
||||||
this._group.hide();
|
this._group.hide();
|
||||||
|
|
||||||
@ -904,3 +943,14 @@ function _clipHeightTopGet(actor) {
|
|||||||
function _clipHeightTopSet(actor, clipHeight) {
|
function _clipHeightTopSet(actor, clipHeight) {
|
||||||
actor.set_clip(0, actor.height - clipHeight, actor.width, clipHeight);
|
actor.set_clip(0, actor.height - clipHeight, actor.width, clipHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tweener.registerSpecialProperty("clipWidthRight", _clipWidthRightGet, _clipWidthRightSet);
|
||||||
|
|
||||||
|
function _clipWidthRightGet(actor) {
|
||||||
|
let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
|
||||||
|
return clipWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _clipWidthRightSet(actor, clipWidth) {
|
||||||
|
actor.set_clip(0, 0, clipWidth, actor.height);
|
||||||
|
}
|
||||||
|
@ -800,26 +800,6 @@ Workspaces.prototype = {
|
|||||||
activeWorkspace.actor.raise_top();
|
activeWorkspace.actor.raise_top();
|
||||||
this._positionWorkspaces(global, activeWorkspace);
|
this._positionWorkspaces(global, activeWorkspace);
|
||||||
|
|
||||||
// Create a backdrop rectangle, so that you don't see the
|
|
||||||
// other parts of the overlay (eg, sidebar) through the gaps
|
|
||||||
// between the workspaces when they're zooming in/out
|
|
||||||
this._backdrop = new Clutter.Rectangle({ color: Overlay.OVERLAY_BACKGROUND_COLOR,
|
|
||||||
x: this._backdropX,
|
|
||||||
y: this._backdropY,
|
|
||||||
width: this._backdropWidth,
|
|
||||||
height: this._backdropHeight
|
|
||||||
});
|
|
||||||
this.actor.add_actor(this._backdrop);
|
|
||||||
this._backdrop.lower_bottom();
|
|
||||||
Tweener.addTween(this._backdrop,
|
|
||||||
{ x: this._x,
|
|
||||||
y: this._y,
|
|
||||||
width: this._width,
|
|
||||||
height: this._height,
|
|
||||||
time: Overlay.ANIMATION_TIME,
|
|
||||||
transition: "easeOutQuad"
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create (+) button
|
// Create (+) button
|
||||||
buttonSize = addButtonSize;
|
buttonSize = addButtonSize;
|
||||||
this.addButton = new Clutter.Texture({ x: addButtonX,
|
this.addButton = new Clutter.Texture({ x: addButtonX,
|
||||||
@ -870,15 +850,6 @@ Workspaces.prototype = {
|
|||||||
|
|
||||||
for (let w = 0; w < this._workspaces.length; w++)
|
for (let w = 0; w < this._workspaces.length; w++)
|
||||||
this._workspaces[w].zoomFromOverlay();
|
this._workspaces[w].zoomFromOverlay();
|
||||||
|
|
||||||
Tweener.addTween(this._backdrop,
|
|
||||||
{ x: this._backdropX,
|
|
||||||
y: this._backdropY,
|
|
||||||
width: this._backdropWidth,
|
|
||||||
height: this._backdropHeight,
|
|
||||||
time: Overlay.ANIMATION_TIME,
|
|
||||||
transition: "easeOutQuad"
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy : function() {
|
destroy : function() {
|
||||||
@ -890,25 +861,36 @@ Workspaces.prototype = {
|
|||||||
|
|
||||||
this.actor.destroy();
|
this.actor.destroy();
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
this._backdrop = null;
|
|
||||||
|
|
||||||
global.screen.disconnect(this._nWorkspacesNotifyId);
|
global.screen.disconnect(this._nWorkspacesNotifyId);
|
||||||
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getFullSizeX : function() {
|
||||||
|
return this._workspaces[0].fullSizeX;
|
||||||
|
},
|
||||||
|
|
||||||
|
// If j-th workspace in the i-th row is active, returns the full width
|
||||||
|
// of j workspaces including empty space if i = 1, or the width of one
|
||||||
|
// workspace.
|
||||||
|
// Used in overlay.js to determine when it is ok to remove the sideshow
|
||||||
|
// during animations for entering and leaving the overlay.
|
||||||
|
getWidthToTopActiveWorkspace : function() {
|
||||||
|
let global = Shell.Global.get();
|
||||||
|
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||||
|
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
||||||
|
|
||||||
|
if (activeWorkspace.gridRow == 0)
|
||||||
|
return (activeWorkspace.gridCol + 1) * global.screen_width + activeWorkspace.gridCol * GRID_SPACING;
|
||||||
|
else
|
||||||
|
return global.screen_width;
|
||||||
|
},
|
||||||
|
|
||||||
// Updates the workspaces display based on the current dimensions and position.
|
// Updates the workspaces display based on the current dimensions and position.
|
||||||
_updateInOverlay : function() {
|
_updateInOverlay : function() {
|
||||||
let global = Shell.Global.get();
|
let global = Shell.Global.get();
|
||||||
|
|
||||||
this._positionWorkspaces(global);
|
this._positionWorkspaces(global);
|
||||||
Tweener.addTween(this._backdrop,
|
|
||||||
{ x: this._x,
|
|
||||||
y: this._y,
|
|
||||||
width: this._width,
|
|
||||||
height: this._height,
|
|
||||||
time: Overlay.ANIMATION_TIME,
|
|
||||||
transition: "easeOutQuad"
|
|
||||||
});
|
|
||||||
|
|
||||||
// Position/scale the desktop windows and their children
|
// Position/scale the desktop windows and their children
|
||||||
for (let w = 0; w < this._workspaces.length; w++)
|
for (let w = 0; w < this._workspaces.length; w++)
|
||||||
@ -973,12 +955,6 @@ Workspaces.prototype = {
|
|||||||
workspace.fullSizeX = (workspace.gridCol - activeWorkspace.gridCol) * (global.screen_width + GRID_SPACING);
|
workspace.fullSizeX = (workspace.gridCol - activeWorkspace.gridCol) * (global.screen_width + GRID_SPACING);
|
||||||
workspace.fullSizeY = (workspace.gridRow - activeWorkspace.gridRow) * (global.screen_height + GRID_SPACING);
|
workspace.fullSizeY = (workspace.gridRow - activeWorkspace.gridRow) * (global.screen_height + GRID_SPACING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// And the backdrop
|
|
||||||
this._backdropX = this._workspaces[0].fullSizeX;
|
|
||||||
this._backdropY = this._workspaces[0].fullSizeY;
|
|
||||||
this._backdropWidth = gridWidth * (global.screen_width + GRID_SPACING) - GRID_SPACING;
|
|
||||||
this._backdropHeight = gridHeight * (global.screen_height + GRID_SPACING) - GRID_SPACING;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_workspacesChanged : function() {
|
_workspacesChanged : function() {
|
||||||
@ -1036,7 +1012,6 @@ Workspaces.prototype = {
|
|||||||
// Slide old workspaces out
|
// Slide old workspaces out
|
||||||
for (let w = 0; w < lostWorkspaces.length; w++) {
|
for (let w = 0; w < lostWorkspaces.length; w++) {
|
||||||
let workspace = lostWorkspaces[w];
|
let workspace = lostWorkspaces[w];
|
||||||
workspace.actor.raise(this._backdrop);
|
|
||||||
workspace.slideOut(function () { workspace.destroy(); });
|
workspace.slideOut(function () { workspace.destroy(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
#include "shell-wm.h"
|
#include "shell-wm.h"
|
||||||
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include <clutter/glx/clutter-glx.h>
|
||||||
#include <clutter/x11/clutter-x11.h>
|
#include <clutter/x11/clutter-x11.h>
|
||||||
|
#include <gdk/gdkx.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -37,6 +39,9 @@ struct _ShellGlobal {
|
|||||||
ShellWM *wm;
|
ShellWM *wm;
|
||||||
gboolean keyboard_grabbed;
|
gboolean keyboard_grabbed;
|
||||||
const char *imagedir;
|
const char *imagedir;
|
||||||
|
|
||||||
|
/* Displays the root window; see shell_global_create_root_pixmap_actor() */
|
||||||
|
ClutterGLXTexturePixmap *root_pixmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -153,6 +158,8 @@ shell_global_init (ShellGlobal *global)
|
|||||||
global->grab_notifier = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
|
global->grab_notifier = GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL));
|
||||||
g_signal_connect (global->grab_notifier, "grab-notify", G_CALLBACK (grab_notify), global);
|
g_signal_connect (global->grab_notifier, "grab-notify", G_CALLBACK (grab_notify), global);
|
||||||
global->grab_active = FALSE;
|
global->grab_active = FALSE;
|
||||||
|
|
||||||
|
global->root_pixmap = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -728,3 +735,129 @@ shell_global_create_vertical_gradient (ClutterColor *top,
|
|||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the global->root_pixmap actor with the root window's pixmap or fails
|
||||||
|
* with a warning.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
update_root_window_pixmap (ShellGlobal *global)
|
||||||
|
{
|
||||||
|
Atom type;
|
||||||
|
int format;
|
||||||
|
gulong nitems;
|
||||||
|
gulong bytes_after;
|
||||||
|
guchar *data;
|
||||||
|
|
||||||
|
if (!XGetWindowProperty (gdk_x11_get_default_xdisplay (),
|
||||||
|
gdk_x11_get_default_root_xwindow (),
|
||||||
|
gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID"),
|
||||||
|
0, LONG_MAX,
|
||||||
|
False,
|
||||||
|
AnyPropertyType,
|
||||||
|
&type, &format, &nitems, &bytes_after, &data) &&
|
||||||
|
type != None)
|
||||||
|
{
|
||||||
|
/* Got a property. */
|
||||||
|
if (type == XA_PIXMAP && format == 32 && nitems == 1)
|
||||||
|
{
|
||||||
|
/* Was what we expected. */
|
||||||
|
clutter_x11_texture_pixmap_set_pixmap (CLUTTER_X11_TEXTURE_PIXMAP (global->root_pixmap),
|
||||||
|
*(Pixmap *)data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning ("Could not get the root window pixmap");
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when the X server emits a root window change event. If the event is
|
||||||
|
* about a new pixmap, update the global->root_pixmap actor.
|
||||||
|
*/
|
||||||
|
static GdkFilterReturn
|
||||||
|
root_window_filter (GdkXEvent *native, GdkEvent *event, gpointer data)
|
||||||
|
{
|
||||||
|
XEvent *xevent = (XEvent *)native;
|
||||||
|
|
||||||
|
if ((xevent->type == PropertyNotify) &&
|
||||||
|
(xevent->xproperty.window == gdk_x11_get_default_root_xwindow ()) &&
|
||||||
|
(xevent->xproperty.atom == gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID")))
|
||||||
|
update_root_window_pixmap (SHELL_GLOBAL (data));
|
||||||
|
|
||||||
|
return GDK_FILTER_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when the root window pixmap actor is destroyed.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
root_pixmap_destroy (GObject *sender, gpointer data)
|
||||||
|
{
|
||||||
|
ShellGlobal *global = SHELL_GLOBAL (data);
|
||||||
|
|
||||||
|
gdk_window_remove_filter (gdk_get_default_root_window (),
|
||||||
|
root_window_filter, global);
|
||||||
|
global->root_pixmap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shell_global_create_root_pixmap_actor:
|
||||||
|
* @global: a #ShellGlobal
|
||||||
|
*
|
||||||
|
* Creates an actor showing the root window pixmap.
|
||||||
|
*
|
||||||
|
* Return value: (transfer none): a #ClutterActor with the root window pixmap.
|
||||||
|
* The actor is floating, hence (transfer none).
|
||||||
|
*/
|
||||||
|
ClutterActor *
|
||||||
|
shell_global_create_root_pixmap_actor (ShellGlobal *global)
|
||||||
|
{
|
||||||
|
GdkWindow *window;
|
||||||
|
GdkEventMask events;
|
||||||
|
gboolean created_new_pixmap = FALSE;
|
||||||
|
ClutterActor *clone;
|
||||||
|
|
||||||
|
/* The actor created is actually a ClutterClone of global->root_pixmap. */
|
||||||
|
|
||||||
|
if (global->root_pixmap == NULL)
|
||||||
|
{
|
||||||
|
global->root_pixmap = CLUTTER_GLX_TEXTURE_PIXMAP (clutter_glx_texture_pixmap_new ());
|
||||||
|
|
||||||
|
/* The low and medium quality filters give nearest-neighbor resizing. */
|
||||||
|
clutter_texture_set_filter_quality (CLUTTER_TEXTURE (global->root_pixmap),
|
||||||
|
CLUTTER_TEXTURE_QUALITY_HIGH);
|
||||||
|
|
||||||
|
/* The pixmap actor is only referenced by its clones. */
|
||||||
|
g_object_ref_sink (global->root_pixmap);
|
||||||
|
|
||||||
|
g_signal_connect (G_OBJECT (global->root_pixmap), "destroy",
|
||||||
|
G_CALLBACK (root_pixmap_destroy), global);
|
||||||
|
|
||||||
|
/* Watch the root window for changes. */
|
||||||
|
window = gdk_get_default_root_window ();
|
||||||
|
events = gdk_window_get_events (window);
|
||||||
|
events |= GDK_PROPERTY_CHANGE_MASK;
|
||||||
|
gdk_window_set_events (window, events);
|
||||||
|
/* Metacity handles some root window property updates in its global
|
||||||
|
* event filter, though not this one. For all root window property
|
||||||
|
* updates, the global filter returns GDK_FILTER_CONTINUE, so our
|
||||||
|
* window specific filter will be called.
|
||||||
|
*/
|
||||||
|
gdk_window_add_filter (window, root_window_filter, global);
|
||||||
|
|
||||||
|
update_root_window_pixmap (global);
|
||||||
|
|
||||||
|
created_new_pixmap = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
clone = clutter_clone_new (CLUTTER_ACTOR (global->root_pixmap));
|
||||||
|
|
||||||
|
if (created_new_pixmap)
|
||||||
|
g_object_unref(global->root_pixmap);
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
@ -69,6 +69,8 @@ void shell_global_reexec_self (ShellGlobal *global);
|
|||||||
ClutterCairoTexture *shell_global_create_vertical_gradient (ClutterColor *top,
|
ClutterCairoTexture *shell_global_create_vertical_gradient (ClutterColor *top,
|
||||||
ClutterColor *bottom);
|
ClutterColor *bottom);
|
||||||
|
|
||||||
|
ClutterActor *shell_global_create_root_pixmap_actor (ShellGlobal *global);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __SHELL_GLOBAL_H__ */
|
#endif /* __SHELL_GLOBAL_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user