Compare commits
7 Commits
citadel
...
wip/gcampa
Author | SHA1 | Date | |
---|---|---|---|
|
3e79d293f7 | ||
|
d457073c10 | ||
|
8b2864ee70 | ||
|
af1c799246 | ||
|
f6aa0ee532 | ||
|
b0e22a795e | ||
|
f91671498b |
180
js/ui/layout.js
180
js/ui/layout.js
@ -1,6 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const ClutterX11 = imports.gi.ClutterX11;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
@ -15,9 +16,9 @@ const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||
const STARTUP_ANIMATION_TIME = 0.2;
|
||||
const STARTUP_ANIMATION_TIME = 1;
|
||||
const KEYBOARD_ANIMATION_TIME = 0.15;
|
||||
const PLYMOUTH_TRANSITION_TIME = 1;
|
||||
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
|
||||
|
||||
const MonitorConstraint = new Lang.Class({
|
||||
Name: 'MonitorConstraint',
|
||||
@ -111,7 +112,6 @@ const LayoutManager = new Lang.Class({
|
||||
this.primaryIndex = -1;
|
||||
this._keyboardIndex = -1;
|
||||
this._hotCorners = [];
|
||||
this._background = null;
|
||||
this._leftPanelBarrier = 0;
|
||||
this._rightPanelBarrier = 0;
|
||||
|
||||
@ -120,6 +120,42 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
this._trackedActors = [];
|
||||
|
||||
// Normally, the stage is always covered so Clutter doesn't need to clear
|
||||
// it; however it becomes visible during the startup animation
|
||||
// See the comment below for a longer explanation
|
||||
global.stage.color = DEFAULT_BACKGROUND_COLOR;
|
||||
|
||||
// Set up stage hierarchy to group all UI actors under one container.
|
||||
this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
|
||||
this.uiGroup.connect('allocate',
|
||||
function (actor, box, flags) {
|
||||
let children = actor.get_children();
|
||||
for (let i = 0; i < children.length; i++)
|
||||
children[i].allocate_preferred_size(flags);
|
||||
});
|
||||
this.uiGroup.connect('get-preferred-width',
|
||||
function(actor, forHeight, alloc) {
|
||||
let width = global.stage.width;
|
||||
[alloc.min_size, alloc.natural_size] = [width, width];
|
||||
});
|
||||
this.uiGroup.connect('get-preferred-height',
|
||||
function(actor, forWidth, alloc) {
|
||||
let height = global.stage.height;
|
||||
[alloc.min_size, alloc.natural_size] = [height, height];
|
||||
});
|
||||
|
||||
global.window_group.reparent(this.uiGroup);
|
||||
|
||||
// Now, you might wonder why we went through all the hoops to implement
|
||||
// the GDM greeter inside an X11 compositor, to do this at the end...
|
||||
// However, hiding this is necessary to avoid showing the background during
|
||||
// the initial animation, before Gdm.LoginDialog covers everything
|
||||
if (Main.sessionMode.isGreeter)
|
||||
global.window_group.hide();
|
||||
|
||||
global.overlay_group.reparent(this.uiGroup);
|
||||
global.stage.add_child(this.uiGroup);
|
||||
|
||||
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
|
||||
visible: false,
|
||||
clip_to_allocation: true,
|
||||
@ -135,7 +171,7 @@ const LayoutManager = new Lang.Class({
|
||||
Lang.bind(this, this._panelBoxChanged));
|
||||
|
||||
this.trayBox = new St.Widget({ name: 'trayBox',
|
||||
layout_manager: new Clutter.BinLayout() });
|
||||
layout_manager: new Clutter.BinLayout() });
|
||||
this.addChrome(this.trayBox);
|
||||
|
||||
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
|
||||
@ -161,7 +197,8 @@ const LayoutManager = new Lang.Class({
|
||||
Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
|
||||
Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||
this._startupAnimation();
|
||||
|
||||
this._prepareStartupAnimation();
|
||||
},
|
||||
|
||||
_overviewShowing: function() {
|
||||
@ -254,7 +291,7 @@ const LayoutManager = new Lang.Class({
|
||||
if (!haveTopLeftCorner)
|
||||
continue;
|
||||
|
||||
let corner = new HotCorner();
|
||||
let corner = new HotCorner(this);
|
||||
this._hotCorners.push(corner);
|
||||
corner.actor.set_position(cornerX, cornerY);
|
||||
this.addChrome(corner.actor);
|
||||
@ -376,51 +413,106 @@ const LayoutManager = new Lang.Class({
|
||||
return this._keyboardIndex;
|
||||
},
|
||||
|
||||
_startupAnimation: function() {
|
||||
this.panelBox.translation_y = -this.panelBox.height;
|
||||
_acquireRootBackground: function() {
|
||||
let rootpmap = Shell.util_get_root_background();
|
||||
let texture = ClutterX11.TexturePixmap.new_with_pixmap(rootpmap);
|
||||
// The texture size might not match the screen size, for example
|
||||
// if the session has a different XRandR configuration than the greeter
|
||||
texture.x = 0;
|
||||
texture.y = 0;
|
||||
texture.width = global.screen_width;
|
||||
texture.height = global.screen_height;
|
||||
texture.set_automatic(true);
|
||||
|
||||
let plymouthTransitionRunning = false;
|
||||
|
||||
// If we're the greeter, put up the xrootpmap actor
|
||||
// and fade it out to have a nice transition from plymouth
|
||||
// to the greeter. Otherwise, we'll just animate the panel,
|
||||
// as usual.
|
||||
if (Main.sessionMode.isGreeter) {
|
||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||
if (this._background != null) {
|
||||
Main.uiGroup.add_actor(this._background);
|
||||
Tweener.addTween(this._background,
|
||||
{ opacity: 0,
|
||||
time: PLYMOUTH_TRANSITION_TIME,
|
||||
transition: 'linear',
|
||||
onComplete: this._fadeBackgroundComplete,
|
||||
onCompleteScope: this });
|
||||
plymouthTransitionRunning = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!plymouthTransitionRunning)
|
||||
this._fadeBackgroundComplete();
|
||||
this._rootTexture = texture;
|
||||
},
|
||||
|
||||
_fadeBackgroundComplete: function() {
|
||||
// Startup Animations
|
||||
//
|
||||
// We have two different animations, depending on whether we're a greeter
|
||||
// or a normal session.
|
||||
//
|
||||
// In the greeter, we want to animate the panel from the top, and smoothly
|
||||
// fade the login dialog on top of whatever plymouth left on screen, which we
|
||||
// grab as a X11 texture_from_pixmap.
|
||||
// Here we just have the code to animate the panel, the login dialog animation
|
||||
// is handled by modalDialog.js
|
||||
//
|
||||
// In a normal session, we want to take the root background, which now holds
|
||||
// the final frame of the GDM greeter, and slide it from the bottom, while
|
||||
// at the same time scaling the UI contents of the new shell on top of the
|
||||
// stage background.
|
||||
//
|
||||
// Usually, we don't want to paint the stage background color because the
|
||||
// MetaBackgroundActor inside global.window_group covers the entirety of the
|
||||
// screen. So, we set no_clear_hint at the end of the animation.
|
||||
|
||||
_prepareStartupAnimation: function() {
|
||||
// Set ourselves to FULLSCREEN input mode while the animation is running
|
||||
// so events don't get delivered to X11 windows (which are distorted by the animation)
|
||||
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
|
||||
|
||||
this._acquireRootBackground();
|
||||
|
||||
if (Main.sessionMode.isGreeter) {
|
||||
global.stage.insert_child_below(this._rootTexture, null);
|
||||
|
||||
this._panelBox.translation_y = -this._panelBox.height;
|
||||
} else {
|
||||
global.stage.insert_child_above(this._rootTexture, null);
|
||||
|
||||
this.uiGroup.set_pivot_point(0.5, 0.5);
|
||||
this.uiGroup.scale_x = this.uiGroup.scale_y = 0;
|
||||
}
|
||||
},
|
||||
|
||||
startupAnimation: function() {
|
||||
if (Main.sessionMode.isGreeter)
|
||||
this._startupAnimationGreeter();
|
||||
else
|
||||
this._startupAnimationSession();
|
||||
},
|
||||
|
||||
_startupAnimationGreeter: function() {
|
||||
// Don't animate the strut
|
||||
this._freezeUpdateRegions();
|
||||
|
||||
if (this._background != null) {
|
||||
this._background.destroy();
|
||||
this._background = null;
|
||||
}
|
||||
|
||||
Tweener.addTween(this.panelBox,
|
||||
Tweener.addTween(this._panelBox,
|
||||
{ translation_y: 0,
|
||||
time: STARTUP_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: this._startupAnimationComplete,
|
||||
onCompleteScope: this
|
||||
});
|
||||
onCompleteScope: this });
|
||||
},
|
||||
|
||||
_startupAnimationSession: function() {
|
||||
// Don't animate the strut
|
||||
this._freezeUpdateRegions();
|
||||
|
||||
Tweener.addTween(this._rootTexture,
|
||||
{ translation_y: -global.screen_height,
|
||||
time: STARTUP_ANIMATION_TIME,
|
||||
transition: 'linear' });
|
||||
|
||||
Tweener.addTween(this.uiGroup,
|
||||
{ scale_x: 1,
|
||||
scale_y: 1,
|
||||
time: STARTUP_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: this._startupAnimationComplete,
|
||||
onCompleteScope: this });
|
||||
},
|
||||
|
||||
_startupAnimationComplete: function() {
|
||||
// At this point, the UI group is covering everything, so
|
||||
// we no longer need to clear the stage
|
||||
global.stage.no_clear_hint = true;
|
||||
|
||||
global.stage_input_mode = Shell.StageInputMode.NORMAL;
|
||||
|
||||
this._rootTexture.destroy();
|
||||
this._rootTexture = null;
|
||||
|
||||
this.emit('panel-box-changed');
|
||||
this._thawUpdateRegions();
|
||||
},
|
||||
@ -506,7 +598,7 @@ const LayoutManager = new Lang.Class({
|
||||
// monitor (it will be hidden whenever a fullscreen window is visible,
|
||||
// and shown otherwise)
|
||||
addChrome: function(actor, params) {
|
||||
Main.uiGroup.add_actor(actor);
|
||||
this.uiGroup.add_actor(actor);
|
||||
this._trackActor(actor, params);
|
||||
},
|
||||
|
||||
@ -557,7 +649,7 @@ const LayoutManager = new Lang.Class({
|
||||
//
|
||||
// Removes @actor from the chrome
|
||||
removeChrome: function(actor) {
|
||||
Main.uiGroup.remove_actor(actor);
|
||||
this.uiGroup.remove_actor(actor);
|
||||
this._untrackActor(actor);
|
||||
},
|
||||
|
||||
@ -576,7 +668,7 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
let actorData = Params.parse(params, defaultParams);
|
||||
actorData.actor = actor;
|
||||
actorData.isToplevel = actor.get_parent() == Main.uiGroup;
|
||||
actorData.isToplevel = actor.get_parent() == this.uiGroup;
|
||||
actorData.visibleId = actor.connect('notify::visible',
|
||||
Lang.bind(this, this._queueUpdateRegions));
|
||||
actorData.allocationId = actor.connect('notify::allocation',
|
||||
@ -612,7 +704,7 @@ const LayoutManager = new Lang.Class({
|
||||
} else {
|
||||
let i = this._findActor(actor);
|
||||
let actorData = this._trackedActors[i];
|
||||
actorData.isToplevel = (newParent == Main.uiGroup);
|
||||
actorData.isToplevel = (newParent == this.uiGroup);
|
||||
}
|
||||
},
|
||||
|
||||
@ -812,7 +904,7 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
if (actorData.affectsInputRegion &&
|
||||
actorData.actor.get_paint_visibility() &&
|
||||
!Main.uiGroup.get_skip_paint(actorData.actor))
|
||||
!this.uiGroup.get_skip_paint(actorData.actor))
|
||||
rects.push(rect);
|
||||
|
||||
if (!actorData.affectsStruts)
|
||||
|
@ -38,7 +38,6 @@ const XdndHandler = imports.ui.xdndHandler;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
|
||||
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
|
||||
|
||||
let componentManager = null;
|
||||
let panel = null;
|
||||
@ -63,6 +62,7 @@ let magnifier = null;
|
||||
let xdndHandler = null;
|
||||
let keyboard = null;
|
||||
let layoutManager = null;
|
||||
let background = null;
|
||||
let _startDate;
|
||||
let _defaultCssStylesheet = null;
|
||||
let _cssStylesheet = null;
|
||||
@ -111,38 +111,17 @@ function start() {
|
||||
|
||||
tracker.connect('startup-sequence-changed', _queueCheckWorkspaces);
|
||||
|
||||
// The stage is always covered so Clutter doesn't need to clear it; however
|
||||
// the color is used as the default contents for the Mutter root background
|
||||
// actor so set it anyways.
|
||||
global.stage.color = DEFAULT_BACKGROUND_COLOR;
|
||||
global.stage.no_clear_hint = true;
|
||||
// Setup the stage hierarchy early
|
||||
layoutManager = new Layout.LayoutManager();
|
||||
// For backward compatibility
|
||||
uiGroup = layoutManager.uiGroup;
|
||||
|
||||
let backgroundActor = global.window_group.background;
|
||||
background = backgroundActor.settings;
|
||||
|
||||
_defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
|
||||
loadTheme();
|
||||
|
||||
// Set up stage hierarchy to group all UI actors under one container.
|
||||
uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
|
||||
uiGroup.connect('allocate',
|
||||
function (actor, box, flags) {
|
||||
let children = uiGroup.get_children();
|
||||
for (let i = 0; i < children.length; i++)
|
||||
children[i].allocate_preferred_size(flags);
|
||||
});
|
||||
uiGroup.connect('get-preferred-width',
|
||||
function(actor, forHeight, alloc) {
|
||||
let width = global.stage.width;
|
||||
[alloc.min_size, alloc.natural_size] = [width, width];
|
||||
});
|
||||
uiGroup.connect('get-preferred-height',
|
||||
function(actor, forWidth, alloc) {
|
||||
let height = global.stage.height;
|
||||
[alloc.min_size, alloc.natural_size] = [height, height];
|
||||
});
|
||||
global.window_group.reparent(uiGroup);
|
||||
global.overlay_group.reparent(uiGroup);
|
||||
global.stage.add_actor(uiGroup);
|
||||
|
||||
layoutManager = new Layout.LayoutManager();
|
||||
xdndHandler = new XdndHandler.XdndHandler();
|
||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||
overview = new Overview.Overview();
|
||||
@ -196,6 +175,14 @@ function start() {
|
||||
|
||||
ExtensionDownloader.init();
|
||||
ExtensionSystem.init();
|
||||
|
||||
// Run the startup animation as soon as the mainloop is idle enough
|
||||
// This is necessary to have it smooth and without interruptions from
|
||||
// completed IO tasks
|
||||
GLib.idle_add(GLib.PRIORITY_LOW, function() {
|
||||
layoutManager.startupAnimation();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
let _workspaces = [];
|
||||
|
@ -122,7 +122,8 @@ const Overview = new Lang.Class({
|
||||
// one. Instances of this class share a single CoglTexture behind the
|
||||
// scenes which allows us to show the background with different
|
||||
// rendering options without duplicating the texture data.
|
||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||
this._background = new Meta.BackgroundActor({ screen: global.screen,
|
||||
settings: Main.background });
|
||||
this._background.add_glsl_snippet(Meta.SnippetHook.FRAGMENT,
|
||||
GLSL_DIM_EFFECT_DECLARATIONS,
|
||||
GLSL_DIM_EFFECT_CODE,
|
||||
|
@ -644,7 +644,7 @@ const ActivitiesButton = new Lang.Class({
|
||||
|
||||
this.actor.label_actor = this._label;
|
||||
|
||||
this.hotCorner = new Layout.HotCorner();
|
||||
this.hotCorner = new Layout.HotCorner(Main.layoutManager);
|
||||
container.add_actor(this.hotCorner.actor);
|
||||
|
||||
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
||||
|
@ -52,36 +52,16 @@ const SUMMARY_ICON_SIZE = 48;
|
||||
const STANDARD_FADE_TIME = 10;
|
||||
const SHORT_FADE_TIME = 0.3;
|
||||
|
||||
function sample(offx, offy) {
|
||||
return 'texel += texture2D (sampler, tex_coord.st + pixel_step * ' +
|
||||
'vec2 (' + offx + ',' + offy + '));\n'
|
||||
}
|
||||
const GLSL_BLUR_EFFECT_DECLARATIONS = ' \
|
||||
uniform vec2 pixel_step;\n \
|
||||
uniform float desaturation;\n \
|
||||
vec4 apply_blur(in sampler2D sampler, in vec2 tex_coord) {\n \
|
||||
vec4 texel;\n \
|
||||
texel = texture2D (sampler, tex_coord.st);\n'
|
||||
+ sample(-1.0, -1.0)
|
||||
+ sample( 0.0, -1.0)
|
||||
+ sample(+1.0, -1.0)
|
||||
+ sample(-1.0, 0.0)
|
||||
+ sample(+1.0, 0.0)
|
||||
+ sample(-1.0, +1.0)
|
||||
+ sample( 0.0, +1.0)
|
||||
+ sample(+1.0, +1.0) + ' \
|
||||
texel /= 9.0;\n \
|
||||
return texel;\n \
|
||||
}\n \
|
||||
const GLSL_EFFECT_DECLARATIONS = ' \
|
||||
uniform float desaturation; \n \
|
||||
vec3 desaturate (const vec3 color)\n \
|
||||
{\n \
|
||||
const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n \
|
||||
vec3 gray = vec3 (dot (gray_conv, color));\n \
|
||||
return vec3 (mix (color.rgb, gray, desaturation));\n \
|
||||
}';
|
||||
const GLSL_BLUR_EFFECT_CODE = ' \
|
||||
cogl_texel = apply_blur(cogl_sampler, cogl_tex_coord.st);\n \
|
||||
cogl_texel.rgb = desaturate(cogl_texel.rgb);\n';
|
||||
const GLSL_EFFECT_CODE = ' \
|
||||
cogl_color_out.rgb = desaturate(cogl_color_out.rgb);\n';
|
||||
|
||||
|
||||
const Clock = new Lang.Class({
|
||||
@ -467,16 +447,16 @@ const ScreenShield = new Lang.Class({
|
||||
name: 'lockScreenContents' });
|
||||
this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
||||
|
||||
let backgroundActor = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||
backgroundActor.add_glsl_snippet(Meta.SnippetHook.TEXTURE_LOOKUP,
|
||||
GLSL_BLUR_EFFECT_DECLARATIONS,
|
||||
GLSL_BLUR_EFFECT_CODE,
|
||||
true);
|
||||
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
||||
|
||||
let backgroundActor = new Meta.BackgroundActor({ screen: global.screen,
|
||||
settings: this._settings });
|
||||
backgroundActor.add_glsl_snippet(Meta.SnippetHook.FRAGMENT,
|
||||
GLSL_EFFECT_DECLARATIONS,
|
||||
GLSL_EFFECT_CODE,
|
||||
false);
|
||||
backgroundActor.set_uniform_float('desaturation',
|
||||
1, 1, [0.6]);
|
||||
backgroundActor.connect('notify::size', function(actor) {
|
||||
actor.set_uniform_float('pixel_step', 2, 1, [1/actor.width, 1/actor.height]);
|
||||
});
|
||||
|
||||
this._background = new St.Bin({ style_class: 'screen-shield-background',
|
||||
child: backgroundActor });
|
||||
@ -531,8 +511,6 @@ const ScreenShield = new Lang.Class({
|
||||
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
|
||||
this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.deactivate(false); }));
|
||||
|
||||
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
||||
|
||||
this._isModal = false;
|
||||
this._hasLockScreen = false;
|
||||
this._isGreeter = false;
|
||||
|
@ -170,7 +170,8 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||
this._background = new Meta.BackgroundActor({ screen: global.screen,
|
||||
settings: Main.background });
|
||||
this._contents.add_actor(this._background);
|
||||
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
|
@ -292,7 +292,7 @@ libgnome_shell_la_LIBADD = \
|
||||
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
|
||||
|
||||
Shell-0.1.gir: libgnome-shell.la St-1.0.gir
|
||||
Shell_0_1_gir_INCLUDES = Clutter-1.0 ClutterX11-1.0 Meta-3.0 TelepathyGLib-0.12 TelepathyLogger-0.2 Soup-2.4 GMenu-3.0 NetworkManager-1.0 NMClient-1.0
|
||||
Shell_0_1_gir_INCLUDES = Clutter-1.0 ClutterX11-1.0 Meta-3.0 TelepathyGLib-0.12 TelepathyLogger-0.2 Soup-2.4 GMenu-3.0 NetworkManager-1.0 NMClient-1.0 xlib-2.0
|
||||
Shell_0_1_gir_CFLAGS = $(libgnome_shell_la_CPPFLAGS) -I $(srcdir)
|
||||
Shell_0_1_gir_LIBS = libgnome-shell.la
|
||||
Shell_0_1_gir_FILES = $(libgnome_shell_la_gir_sources)
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#ifdef HAVE__NL_TIME_FIRST_WEEKDAY
|
||||
#include <langinfo.h>
|
||||
@ -430,3 +432,56 @@ shell_util_create_pixbuf_from_data (const guchar *data,
|
||||
bits_per_sample, width, height, rowstride,
|
||||
(GdkPixbufDestroyNotify) g_free, NULL);
|
||||
}
|
||||
|
||||
Pixmap
|
||||
shell_util_get_root_background (void)
|
||||
{
|
||||
Display *display;
|
||||
Pixmap pixmap;
|
||||
Window rootwin;
|
||||
Atom xrootpmap;
|
||||
Atom actual_type;
|
||||
int actual_format;
|
||||
unsigned long n_items;
|
||||
unsigned long bytes_after;
|
||||
unsigned char *buffer;
|
||||
|
||||
display = gdk_x11_get_default_xdisplay ();
|
||||
|
||||
xrootpmap = gdk_x11_atom_to_xatom (gdk_atom_intern_static_string ("_XROOTPMAP_ID"));
|
||||
rootwin = gdk_x11_get_default_root_xwindow ();
|
||||
|
||||
gdk_error_trap_push ();
|
||||
actual_type = None;
|
||||
buffer = NULL;
|
||||
if (XGetWindowProperty (display, rootwin, xrootpmap,
|
||||
0, G_MAXLONG,
|
||||
False, XA_PIXMAP, &actual_type, &actual_format,
|
||||
&n_items,
|
||||
&bytes_after,
|
||||
&buffer) != Success ||
|
||||
actual_type == None)
|
||||
{
|
||||
if (buffer)
|
||||
XFree (buffer);
|
||||
gdk_error_trap_pop_ignored ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gdk_error_trap_pop () != Success ||
|
||||
n_items == 0 ||
|
||||
actual_type != XA_PIXMAP ||
|
||||
actual_format != 32)
|
||||
{
|
||||
if (buffer)
|
||||
XFree (buffer);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pixmap = *((Pixmap*) buffer);
|
||||
|
||||
XFree (buffer);
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <clutter/clutter.h>
|
||||
#include <libsoup/soup.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gdk/gdkx.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -46,6 +47,8 @@ GdkPixbuf *shell_util_create_pixbuf_from_data (const guchar *data,
|
||||
int height,
|
||||
int rowstride);
|
||||
|
||||
Pixmap shell_util_get_root_background (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_UTIL_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user