change geometry w/o compositor restart
This possibly fails on some (older?) ati chip/driver combos -> Waiting for bugreports REVIEW: 103246
This commit is contained in:
parent
0dbfdf4979
commit
d845b60c6c
17 changed files with 196 additions and 35 deletions
22
effects.cpp
22
effects.cpp
|
@ -532,6 +532,13 @@ bool EffectsHandlerImpl::hasKeyboardGrab() const
|
|||
return keyboard_grab_effect != NULL;
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::desktopResized(const QSize &size)
|
||||
{
|
||||
scene->screenGeometryChanged(size);
|
||||
emit screenGeometryChanged(size);
|
||||
Workspace::self()->addRepaintFull();
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::slotPropertyNotify(Toplevel* t, long int atom)
|
||||
{
|
||||
if (!registered_atoms.contains(atom))
|
||||
|
@ -1243,6 +1250,21 @@ bool EffectsHandlerImpl::isEffectLoaded(const QString& name)
|
|||
return false;
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::reloadEffect(Effect *effect)
|
||||
{
|
||||
QString effectName;
|
||||
for (QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); ++it) {
|
||||
if ((*it).second == effect) {
|
||||
effectName = (*it).first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!effectName.isNull()) {
|
||||
unloadEffect(effectName);
|
||||
loadEffect(effectName);
|
||||
}
|
||||
}
|
||||
|
||||
void EffectsHandlerImpl::effectsChanged()
|
||||
{
|
||||
loaded_effects.clear();
|
||||
|
|
|
@ -160,7 +160,9 @@ public:
|
|||
bool borderActivated(ElectricBorder border);
|
||||
void grabbedKeyboardEvent(QKeyEvent* e);
|
||||
bool hasKeyboardGrab() const;
|
||||
void desktopResized(const QSize &size);
|
||||
|
||||
virtual void reloadEffect(Effect *effect);
|
||||
bool loadEffect(const QString& name, bool checkDefault = false);
|
||||
void toggleEffect(const QString& name);
|
||||
void unloadEffect(const QString& name);
|
||||
|
|
|
@ -63,6 +63,7 @@ BlurEffect::BlurEffect()
|
|||
connect(effects, SIGNAL(windowAdded(EffectWindow*)), this, SLOT(slotWindowAdded(EffectWindow*)));
|
||||
connect(effects, SIGNAL(windowDeleted(EffectWindow*)), this, SLOT(slotWindowDeleted(EffectWindow*)));
|
||||
connect(effects, SIGNAL(propertyNotify(EffectWindow*,long)), this, SLOT(slotPropertyNotify(EffectWindow*,long)));
|
||||
connect(effects, SIGNAL(screenGeometryChanged(QSize)), this, SLOT(slotScreenGeometryChanged()));
|
||||
}
|
||||
|
||||
BlurEffect::~BlurEffect()
|
||||
|
@ -76,6 +77,11 @@ BlurEffect::~BlurEffect()
|
|||
delete target;
|
||||
}
|
||||
|
||||
void BlurEffect::slotScreenGeometryChanged()
|
||||
{
|
||||
effects->reloadEffect(this);
|
||||
}
|
||||
|
||||
void BlurEffect::reconfigure(ReconfigureFlags flags)
|
||||
{
|
||||
Q_UNUSED(flags)
|
||||
|
|
|
@ -52,6 +52,7 @@ public Q_SLOTS:
|
|||
void slotWindowAdded(EffectWindow *w);
|
||||
void slotWindowDeleted(EffectWindow *w);
|
||||
void slotPropertyNotify(EffectWindow *w, long atom);
|
||||
void slotScreenGeometryChanged();
|
||||
|
||||
private:
|
||||
QRect expand(const QRect &rect) const;
|
||||
|
|
|
@ -76,8 +76,9 @@ void Workspace::desktopResized()
|
|||
#ifdef KWIN_BUILD_SCREENEDGES
|
||||
m_screenEdge.update(true);
|
||||
#endif
|
||||
if (compositing())
|
||||
compositeResetTimer.start(0);
|
||||
if (effects) {
|
||||
static_cast<EffectsHandlerImpl*>(effects)->desktopResized(geom.size());
|
||||
}
|
||||
}
|
||||
|
||||
void Workspace::saveOldScreenSizes()
|
||||
|
|
|
@ -795,6 +795,16 @@ public:
|
|||
virtual EffectFrame* effectFrame(EffectFrameStyle style, bool staticSize = true,
|
||||
const QPoint& position = QPoint(-1, -1), Qt::Alignment alignment = Qt::AlignCenter) const = 0;
|
||||
|
||||
/**
|
||||
* Allows an effect to trigger a reload of itself.
|
||||
* This can be used by an effect which needs to be reloaded when screen geometry changes.
|
||||
* It is possible that the effect cannot be loaded again as it's supported method does no longer
|
||||
* hold.
|
||||
* @param effect The effect to reload
|
||||
* @since 4.8
|
||||
**/
|
||||
virtual void reloadEffect(Effect *effect) = 0;
|
||||
|
||||
/**
|
||||
* Sends message over DCOP to reload given effect.
|
||||
* @param effectname effect's name without "kwin4_effect_" prefix.
|
||||
|
@ -1033,6 +1043,15 @@ Q_SIGNALS:
|
|||
**/
|
||||
void hideOutline();
|
||||
|
||||
/**
|
||||
* Signal emitted after the screen geometry changed (e.g. add of a monitor).
|
||||
* Effects using displayWidth()/displayHeight() to cache information should
|
||||
* react on this signal and update the caches.
|
||||
* @param size The new screen size
|
||||
* @since 4.8
|
||||
**/
|
||||
void screenGeometryChanged(const QSize &size);
|
||||
|
||||
protected:
|
||||
QVector< EffectPair > loaded_effects;
|
||||
QHash< QString, KLibrary* > effect_libraries;
|
||||
|
|
|
@ -689,6 +689,20 @@ GLShader *ShaderManager::pushShader(ShaderType type, bool reset)
|
|||
return shader;
|
||||
}
|
||||
|
||||
void ShaderManager::resetAllShaders()
|
||||
{
|
||||
if (!m_inited || !m_valid) {
|
||||
return;
|
||||
}
|
||||
pushShader(SimpleShader, true);
|
||||
pushShader(GenericShader, true);
|
||||
pushShader(ColorShader, true);
|
||||
popShader();
|
||||
popShader();
|
||||
popShader();
|
||||
}
|
||||
|
||||
|
||||
void ShaderManager::pushShader(GLShader *shader)
|
||||
{
|
||||
// only bind shader if it is not already bound
|
||||
|
|
|
@ -321,6 +321,13 @@ public:
|
|||
**/
|
||||
void popShader();
|
||||
|
||||
/**
|
||||
* Resets all shaders to the default uniform values.
|
||||
* Only built in shaders are changed.
|
||||
* @since 4.8
|
||||
**/
|
||||
void resetAllShaders();
|
||||
|
||||
/**
|
||||
* Creates a GLShader with a built-in vertex shader and a custom fragment shader.
|
||||
* @param vertex The generic vertex shader
|
||||
|
|
|
@ -120,6 +120,13 @@ void OverlayWindow::setShape(const QRegion& reg)
|
|||
m_shape = reg;
|
||||
}
|
||||
|
||||
void OverlayWindow::resize(const QSize &size)
|
||||
{
|
||||
assert(m_window != None);
|
||||
XResizeWindow(display(), m_window, size.width(), size.height());
|
||||
setShape(QRegion(0, 0, size.width(), size.height()));
|
||||
}
|
||||
|
||||
bool OverlayWindow::isVisible() const
|
||||
{
|
||||
return m_visible;
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
void show();
|
||||
void hide(); // hides and resets overlay window
|
||||
void setShape(const QRegion& reg);
|
||||
void resize(const QSize &size);
|
||||
/// Destroys XComposite overlay window
|
||||
void destroy();
|
||||
Window window() const;
|
||||
|
|
|
@ -426,6 +426,11 @@ OverlayWindow* Scene::overlayWindow()
|
|||
return m_overlayWindow;
|
||||
}
|
||||
|
||||
void Scene::screenGeometryChanged(const QSize &size)
|
||||
{
|
||||
m_overlayWindow->resize(size);
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// Scene::Window
|
||||
//****************************************
|
||||
|
|
7
scene.h
7
scene.h
|
@ -60,6 +60,13 @@ public:
|
|||
virtual void windowAdded(Toplevel*) = 0;
|
||||
// a window has been destroyed
|
||||
virtual void windowDeleted(Deleted*) = 0;
|
||||
/**
|
||||
* Method invoked when the screen geometry is changed.
|
||||
* Reimplementing classes should also invoke the parent method
|
||||
* as it takes care of resizing the overlay window.
|
||||
* @param size The new screen geometry size
|
||||
**/
|
||||
virtual void screenGeometryChanged(const QSize &size);
|
||||
// Flags controlling how painting is done.
|
||||
enum {
|
||||
// Window (or at least part of it) will be painted opaque.
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
virtual void paint(QRegion damage, ToplevelList windows);
|
||||
virtual void windowAdded(Toplevel*);
|
||||
virtual void windowDeleted(Deleted*);
|
||||
virtual void screenGeometryChanged(const QSize &size);
|
||||
|
||||
protected:
|
||||
virtual void paintGenericScreen(int mask, ScreenPaintData data);
|
||||
|
@ -70,6 +71,9 @@ private:
|
|||
bool initBufferConfigs();
|
||||
bool initDrawableConfigs();
|
||||
void waitSync();
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
void setupModelViewProjectionMatrix();
|
||||
#endif
|
||||
void flushBuffer(int mask, QRegion damage);
|
||||
GC gcroot;
|
||||
class FBConfigInfo
|
||||
|
@ -86,6 +90,7 @@ private:
|
|||
#ifndef KWIN_HAVE_OPENGLES
|
||||
Drawable buffer;
|
||||
GLXFBConfig fbcbuffer;
|
||||
bool m_resetModelViewProjectionMatrix;
|
||||
#endif
|
||||
static bool db;
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
|
|
|
@ -218,6 +218,13 @@ void SceneOpenGL::flushBuffer(int mask, QRegion damage)
|
|||
XFlush(display());
|
||||
}
|
||||
|
||||
void SceneOpenGL::screenGeometryChanged(const QSize &size)
|
||||
{
|
||||
glViewport(0,0, size.width(), size.height());
|
||||
Scene::screenGeometryChanged(size);
|
||||
ShaderManager::instance()->resetAllShaders();
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// SceneOpenGL::Texture
|
||||
//****************************************
|
||||
|
|
|
@ -38,6 +38,7 @@ GLXDrawable SceneOpenGL::last_pixmap = None;
|
|||
SceneOpenGL::SceneOpenGL(Workspace* ws)
|
||||
: Scene(ws)
|
||||
, init_ok(false)
|
||||
, m_resetModelViewProjectionMatrix(true)
|
||||
{
|
||||
initGLX();
|
||||
// check for FBConfig support
|
||||
|
@ -100,23 +101,7 @@ SceneOpenGL::SceneOpenGL(Workspace* ws)
|
|||
}
|
||||
|
||||
// OpenGL scene setup
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
float fovy = 60.0f;
|
||||
float aspect = 1.0f;
|
||||
float zNear = 0.1f;
|
||||
float zFar = 100.0f;
|
||||
float ymax = zNear * tan(fovy * M_PI / 360.0f);
|
||||
float ymin = -ymax;
|
||||
float xmin = ymin * aspect;
|
||||
float xmax = ymax * aspect;
|
||||
// swap top and bottom to have OpenGL coordinate system match X system
|
||||
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
float scaleFactor = 1.1 * tan(fovy * M_PI / 360.0f) / ymax;
|
||||
glTranslatef(xmin * scaleFactor, ymax * scaleFactor, -1.1);
|
||||
glScalef((xmax - xmin)*scaleFactor / displayWidth(), -(ymax - ymin)*scaleFactor / displayHeight(), 0.001);
|
||||
setupModelViewProjectionMatrix();
|
||||
if (checkGLError("Init")) {
|
||||
kError(1212) << "OpenGL compositing setup failed";
|
||||
return; // error
|
||||
|
@ -152,6 +137,28 @@ SceneOpenGL::~SceneOpenGL()
|
|||
checkGLError("Cleanup");
|
||||
}
|
||||
|
||||
void SceneOpenGL::setupModelViewProjectionMatrix()
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
float fovy = 60.0f;
|
||||
float aspect = 1.0f;
|
||||
float zNear = 0.1f;
|
||||
float zFar = 100.0f;
|
||||
float ymax = zNear * tan(fovy * M_PI / 360.0f);
|
||||
float ymin = -ymax;
|
||||
float xmin = ymin * aspect;
|
||||
float xmax = ymax * aspect;
|
||||
// swap top and bottom to have OpenGL coordinate system match X system
|
||||
glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
float scaleFactor = 1.1 * tan(fovy * M_PI / 360.0f) / ymax;
|
||||
glTranslatef(xmin * scaleFactor, ymax * scaleFactor, -1.1);
|
||||
glScalef((xmax - xmin)*scaleFactor / displayWidth(), -(ymax - ymin)*scaleFactor / displayHeight(), 0.001);
|
||||
m_resetModelViewProjectionMatrix = false;
|
||||
}
|
||||
|
||||
bool SceneOpenGL::initTfp()
|
||||
{
|
||||
if (glXBindTexImageEXT == NULL || glXReleaseTexImageEXT == NULL)
|
||||
|
@ -451,6 +458,10 @@ void SceneOpenGL::paint(QRegion damage, ToplevelList toplevels)
|
|||
|
||||
grabXServer();
|
||||
glXWaitX();
|
||||
if (m_resetModelViewProjectionMatrix) {
|
||||
// reset model view projection matrix if required
|
||||
setupModelViewProjectionMatrix();
|
||||
}
|
||||
glPushMatrix();
|
||||
int mask = 0;
|
||||
#ifdef CHECK_GL_ERROR
|
||||
|
@ -558,6 +569,33 @@ void SceneOpenGL::flushBuffer(int mask, QRegion damage)
|
|||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::screenGeometryChanged(const QSize &size)
|
||||
{
|
||||
Scene::screenGeometryChanged(size);
|
||||
glViewport(0,0, size.width(), size.height());
|
||||
if (m_overlayWindow->window() == None) {
|
||||
glXMakeCurrent(display(), None, NULL);
|
||||
glXDestroyPixmap(display(), glxbuffer);
|
||||
XFreePixmap(display(), buffer);
|
||||
XVisualInfo* visual = glXGetVisualFromFBConfig(display(), fbcbuffer);
|
||||
buffer = XCreatePixmap(display(), rootWindow(), size.width(), size.height(), visual->depth);
|
||||
XFree(visual);
|
||||
glxbuffer = glXCreatePixmap(display(), fbcbuffer, buffer, NULL);
|
||||
glXMakeCurrent(display(), glxbuffer, ctxbuffer);
|
||||
// TODO: there seems some bug, some clients become black until an eg. un/remap - could be a general pixmap buffer issue, though
|
||||
}
|
||||
else {
|
||||
glXMakeCurrent(display(), None, NULL); // deactivate context ////
|
||||
XMoveResizeWindow(display(), buffer, 0,0, size.width(), size.height());
|
||||
m_overlayWindow->setup(buffer);
|
||||
XSync(display(), false); // ensure X11 stuff has applied ////
|
||||
glXMakeCurrent(display(), glxbuffer, ctxbuffer); // reactivate context ////
|
||||
glViewport(0,0, size.width(), size.height()); // adjust viewport last - should btw. be superflous on the Pixmap buffer - iirc glXCreatePixmap sets the context anyway. ////
|
||||
}
|
||||
ShaderManager::instance()->resetAllShaders();
|
||||
m_resetModelViewProjectionMatrix = true;
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// SceneOpenGL::Texture
|
||||
//****************************************
|
||||
|
|
|
@ -99,8 +99,32 @@ SceneXrender::SceneXrender(Workspace* ws)
|
|||
kError(1212) << "No XFixes v3+ extension available";
|
||||
return;
|
||||
}
|
||||
initXRender(true);
|
||||
}
|
||||
|
||||
SceneXrender::~SceneXrender()
|
||||
{
|
||||
if (!init_ok) {
|
||||
// TODO this probably needs to clean up whatever has been created until the failure
|
||||
m_overlayWindow->destroy();
|
||||
return;
|
||||
}
|
||||
XRenderFreePicture(display(), front);
|
||||
XRenderFreePicture(display(), buffer);
|
||||
buffer = None;
|
||||
m_overlayWindow->destroy();
|
||||
foreach (Window * w, windows)
|
||||
delete w;
|
||||
}
|
||||
|
||||
void SceneXrender::initXRender(bool createOverlay)
|
||||
{
|
||||
init_ok = false;
|
||||
if (front != None)
|
||||
XRenderFreePicture(display(), front);
|
||||
KXErrorHandler xerr;
|
||||
if (m_overlayWindow->create()) {
|
||||
bool haveOverlay = createOverlay ? m_overlayWindow->create() : (m_overlayWindow->window() != None);
|
||||
if (haveOverlay) {
|
||||
m_overlayWindow->setup(None);
|
||||
XWindowAttributes attrs;
|
||||
XGetWindowAttributes(display(), m_overlayWindow->window(), &attrs);
|
||||
|
@ -129,21 +153,6 @@ SceneXrender::SceneXrender(Workspace* ws)
|
|||
init_ok = true;
|
||||
}
|
||||
|
||||
SceneXrender::~SceneXrender()
|
||||
{
|
||||
if (!init_ok) {
|
||||
// TODO this probably needs to clean up whatever has been created until the failure
|
||||
m_overlayWindow->destroy();
|
||||
return;
|
||||
}
|
||||
XRenderFreePicture(display(), front);
|
||||
XRenderFreePicture(display(), buffer);
|
||||
buffer = None;
|
||||
m_overlayWindow->destroy();
|
||||
foreach (Window * w, windows)
|
||||
delete w;
|
||||
}
|
||||
|
||||
bool SceneXrender::initFailed() const
|
||||
{
|
||||
return !init_ok;
|
||||
|
@ -153,6 +162,8 @@ bool SceneXrender::initFailed() const
|
|||
// so it is done manually using this buffer,
|
||||
void SceneXrender::createBuffer()
|
||||
{
|
||||
if (buffer != None)
|
||||
XRenderFreePicture(display(), buffer);
|
||||
Pixmap pixmap = XCreatePixmap(display(), rootWindow(), displayWidth(), displayHeight(), DefaultDepth(display(), DefaultScreen(display())));
|
||||
buffer = XRenderCreatePicture(display(), pixmap, format, 0, 0);
|
||||
XFreePixmap(display(), pixmap); // The picture owns the pixmap now
|
||||
|
@ -774,6 +785,12 @@ XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAl
|
|||
}
|
||||
}
|
||||
|
||||
void SceneXrender::screenGeometryChanged(const QSize &size)
|
||||
{
|
||||
Scene::screenGeometryChanged(size);
|
||||
initXRender(false);
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// SceneXrender::EffectFrame
|
||||
//****************************************
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
virtual void paint(QRegion damage, ToplevelList windows);
|
||||
virtual void windowAdded(Toplevel*);
|
||||
virtual void windowDeleted(Deleted*);
|
||||
virtual void screenGeometryChanged(const QSize &size);
|
||||
Picture bufferPicture();
|
||||
protected:
|
||||
virtual void paintBackground(QRegion region);
|
||||
|
@ -61,6 +62,7 @@ private:
|
|||
void paintTransformedScreen(int mask);
|
||||
void createBuffer();
|
||||
void flushBuffer(int mask, QRegion damage);
|
||||
void initXRender(bool createOverlay);
|
||||
XRenderPictFormat* format;
|
||||
Picture front;
|
||||
static Picture buffer;
|
||||
|
|
Loading…
Reference in a new issue