Back to index

unity  6.0.0
unitydialog.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011 Canonical Ltd
00003  *
00004  * This program is free software: you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License version 3 as
00006  * published by the Free Software Foundation.
00007  *
00008  * This program is distributed in the hope that it will be useful,
00009  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  * GNU General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00015  *
00016  * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
00017  */
00018 
00019 #include "unitydialog.h"
00020 #include <cmath>
00021 #include <boost/lexical_cast.hpp>
00022 
00023 COMPIZ_PLUGIN_20090315(unitydialog, UnityDialogPluginVTable);
00024 
00025 class UnityDialogExp :
00026   public CompMatch::Expression
00027 {
00028 public:
00029   UnityDialogExp(const CompString& str);
00030 
00031   bool evaluate(CompWindow* w);
00032 
00033   bool value;
00034 };
00035 
00036 
00037 UnityDialogExp::UnityDialogExp(const CompString& str) :
00038   value(boost::lexical_cast<int> (str) != 0)
00039 {
00040 }
00041 
00042 bool
00043 UnityDialogExp::evaluate(CompWindow* w)
00044 {
00045   UnityDialogWindow* udw = UnityDialogWindow::get(w);
00046 
00047   return ((value && udw->transientParent()) || (!value && !udw->transientParent()));
00048 }
00049 
00050 CompMatch::Expression*
00051 UnityDialogScreen::matchInitExp(const CompString& str)
00052 {
00053   CompString matchString("transient-dialog=");
00054   /* Create a new match object */
00055 
00056   if (str.find(matchString) == 0)
00057     return new UnityDialogExp(str.substr(matchString.size()));
00058 
00059   return screen->matchInitExp(str);
00060 }
00061 
00062 void
00063 UnityDialogScreen::matchExpHandlerChanged()
00064 {
00065   screen->matchExpHandlerChanged();
00066 
00067   for (CompWindow* w : screen->windows())
00068   {
00069     if (UnityDialogWindow::get(w)->hasParent() ||
00070         UnityDialogWindow::get(w)->hasTransients())
00071       screen->matchPropertyChanged(w);
00072   }
00073 }
00074 
00075 void
00076 UnityDialogWindow::moveToRect(CompRect currentRect, bool sync)
00077 {
00078   CompPoint pos = getChildCenteredPositionForRect(currentRect);
00079 
00080   mSkipNotify = true;
00081   window->move(pos.x() - window->borderRect().x(),
00082                pos.y() - window->borderRect().y(), true);
00083 
00084   if (sync)
00085     window->syncPosition();
00086 
00087   setMaxConstrainingAreas();
00088   mSkipNotify = false;
00089 }
00090 
00091 CompWindow*
00092 UnityDialogWindow::findTopParentWindow()
00093 {
00094   CompWindow*        parent = window, *nextParent = NULL;
00095 
00096   /* Go to the bottom most window in the stack */
00097   while ((nextParent = UnityDialogWindow::get(parent)->mParent))
00098     parent = nextParent;
00099 
00100   /* parent now refers to the top most window */
00101   return parent;
00102 }
00103 
00104 UnityDialogShadeTexture::UnityDialogShadeTexture() :
00105   mPixmap(None),
00106   mTexture(0),
00107   mSurface(NULL),
00108   mCairo(NULL),
00109   mDamage(None)
00110 {
00111   mOffscreenContainer = gtk_offscreen_window_new();
00112   gtk_widget_set_name(mOffscreenContainer, "UnityPanelWidget");
00113   gtk_style_context_add_class(gtk_widget_get_style_context(mOffscreenContainer),
00114                               "menubar");
00115   gtk_widget_set_size_request(mOffscreenContainer, 100, 24);
00116   gtk_widget_show_all(mOffscreenContainer);
00117 
00118   g_signal_connect(gtk_settings_get_default(), "notify::gtk-theme-name",
00119                    G_CALLBACK(UnityDialogShadeTexture::onThemeChanged), this);
00120 
00121   g_object_get(gtk_settings_get_default(), "gtk-theme-name", &mThemeName, NULL);
00122   mStyle = gtk_widget_get_style(mOffscreenContainer);
00123 
00124   context();
00125 }
00126 
00127 UnityDialogShadeTexture::~UnityDialogShadeTexture()
00128 {
00129   gtk_widget_destroy(mOffscreenContainer);
00130   g_free(mThemeName);
00131 
00132   destroy();
00133 }
00134 
00135 void
00136 UnityDialogShadeTexture::destroy()
00137 {
00138   if (mPixmap)
00139   {
00140     XFreePixmap(screen->dpy(), mPixmap);
00141     mPixmap = None;
00142   }
00143   if (mSurface)
00144   {
00145     cairo_surface_destroy(mSurface);
00146     mSurface = NULL;
00147   }
00148   if (mCairo)
00149   {
00150     cairo_destroy(mCairo);
00151     mCairo = NULL;
00152   }
00153 }
00154 
00155 void
00156 UnityDialogShadeTexture::clear()
00157 {
00158   if (mCairo)
00159   {
00160     cairo_save(mCairo);
00161     cairo_set_operator(mCairo, CAIRO_OPERATOR_CLEAR);
00162     cairo_paint(mCairo);
00163     cairo_restore(mCairo);
00164   }
00165 }
00166 
00167 void
00168 UnityDialogShadeTexture::context()
00169 {
00170   if (!mCairo)
00171   {
00172     Screen*      xScreen;
00173     XRenderPictFormat* format;
00174     int     w, h;
00175 
00176     xScreen = ScreenOfDisplay(screen->dpy(), screen->screenNum());
00177 
00178     format = XRenderFindStandardFormat(screen->dpy(),
00179                                        PictStandardARGB32);
00180 
00181     w = 1;
00182     h = 1;
00183 
00184     mPixmap = XCreatePixmap(screen->dpy(), screen->root(), w, h, 32);
00185 
00186     mTexture = GLTexture::bindPixmapToTexture(mPixmap, w, h, 32);
00187 
00188     if (mTexture.empty())
00189     {
00190       compLogMessage("unitydialog", CompLogLevelError,
00191                      "Couldn't bind pixmap 0x%x to texture",
00192                      (int) mPixmap);
00193 
00194       XFreePixmap(screen->dpy(), mPixmap);
00195 
00196       return;
00197     }
00198 
00199     mDamage = XDamageCreate(screen->dpy(), mPixmap,
00200                             XDamageReportRawRectangles);
00201 
00202     mSurface =
00203       cairo_xlib_surface_create_with_xrender_format(screen->dpy(),
00204                                                     mPixmap, xScreen,
00205                                                     format, w, h);
00206 
00207     if (!mSurface)
00208     {
00209       compLogMessage("unitydialog", CompLogLevelError, "Couldn't create surface");
00210 
00211       XFreePixmap(screen->dpy(), mPixmap);
00212       XDamageDestroy(screen->dpy(), mDamage);
00213       mTexture.clear();
00214 
00215       return;
00216     }
00217 
00218     mCairo = cairo_create(mSurface);
00219 
00220     if (!mCairo)
00221     {
00222       compLogMessage("unitydialog", CompLogLevelError, "Couldn't create cairo context");
00223 
00224       cairo_surface_destroy(mSurface);
00225       XFreePixmap(screen->dpy(), mPixmap);
00226       XDamageDestroy(screen->dpy(), mDamage);
00227       mTexture.clear();
00228     }
00229   }
00230 }
00231 
00232 void
00233 UnityDialogShadeTexture::render(float alpha)
00234 {
00235   float divisorMask = 0xffff;
00236   mAlpha = alpha;
00237 
00238   clear();
00239 
00240   cairo_set_line_width(mCairo, 2);
00241   cairo_set_source_rgba(mCairo,
00242                         (mStyle->bg[1].red / divisorMask),
00243                         (mStyle->bg[1].green / divisorMask),
00244                         (mStyle->bg[1].blue / divisorMask),
00245                         (alpha));
00246 
00247   cairo_move_to(mCairo, 0, 0);
00248   cairo_rectangle(mCairo, 0, 0, 1, 1);
00249 
00250   cairo_fill(mCairo);
00251 }
00252 
00253 void
00254 UnityDialogShadeTexture::render()
00255 {
00256   render(mAlpha);
00257 }
00258 
00259 void
00260 UnityDialogShadeTexture::onThemeChanged(GObject*    obj,
00261                                         GParamSpec* pspec,
00262                                         gpointer   data)
00263 {
00264   UnityDialogShadeTexture* self = static_cast<UnityDialogShadeTexture*>(data);
00265 
00266   g_object_get(gtk_settings_get_default(), "gtk-theme-name", &self->mThemeName, NULL);
00267   self->mStyle = gtk_widget_get_style(self->mOffscreenContainer);
00268 
00269   self->render();
00270 }
00271 
00272 const GLTexture::List&
00273 UnityDialogShadeTexture::texture()
00274 {
00275   return mTexture;
00276 }
00277 
00278 bool
00279 UnityDialogWindow::animate(int   ms,
00280                            float fadeTime)
00281 {
00282   if (mTransients.size() && mShadeProgress < OPAQUE)
00283   {
00284     mShadeProgress += OPAQUE * (ms / fadeTime);
00285 
00286     if (mShadeProgress >= OPAQUE)
00287       mShadeProgress = OPAQUE;
00288 
00289     return true;
00290   }
00291   else if (!mTransients.size() && mShadeProgress > 0)
00292   {
00293     mShadeProgress -=  OPAQUE * (ms / fadeTime);
00294 
00295     if (mShadeProgress <= 0)
00296       mShadeProgress = 0;
00297 
00298     return true;
00299   }
00300 
00301   return false;
00302 }
00303 
00304 CompRegion
00305 UnityDialogWindow::getDamageRegion()
00306 {
00307   CompRect damageBounds;
00308   float progress = mShadeProgress / (float) OPAQUE;
00309 
00310   /* Current rect in animation expanded by output + 5 */
00311   damageBounds.setX(mCurrentPos.x() +
00312                     ((mTargetPos.x() - mCurrentPos.x()) * progress));
00313   damageBounds.setY(mCurrentPos.y() +
00314                     ((mTargetPos.y() - mCurrentPos.y()) * progress));
00315   damageBounds.setWidth(window->serverOutputRect().width() + 5);
00316   damageBounds.setHeight(window->serverOutputRect().height() + 5);
00317 
00318   return CompRegion(damageBounds);
00319 }
00320 
00321 void
00322 UnityDialogScreen::preparePaint(int ms)
00323 {
00324   cScreen->preparePaint(ms);
00325 
00326   for (CompWindow* w : mParentWindows)
00327     UnityDialogWindow::get(w)->animate(ms, optionGetFadeTime());
00328 
00329 }
00330 
00331 bool
00332 UnityDialogScreen::glPaintOutput(const GLScreenPaintAttrib& attrib,
00333                                  const GLMatrix&      transform,
00334                                  const CompRegion&      region,
00335                                  CompOutput*        output,
00336                                  unsigned int        mask)
00337 {
00338   mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
00339 
00340   return gScreen->glPaintOutput(attrib, transform, region, output, mask);
00341 }
00342 
00343 void
00344 UnityDialogScreen::donePaint()
00345 {
00346   CompWindowList::iterator it = mParentWindows.begin();
00347 
00348   cScreen->donePaint();
00349 
00350   while (it != mParentWindows.end())
00351   {
00352     CompWindow* w = (*it);
00353     UnityDialogWindow* udw = UnityDialogWindow::get(w);
00354 
00355     if (udw->animate(0, optionGetFadeTime()))
00356     {
00357       CompRegion damage = udw->getDamageRegion();
00358       cScreen->damageRegion(damage);
00359     }
00360     else if (!udw->hasTransients())
00361     {
00362       untrackParent(w);
00363       udw->gWindow->glDrawSetEnabled(udw, false);
00364       udw->gWindow->glPaintSetEnabled(udw, false);
00365 
00366       it = mParentWindows.begin();
00367       continue;
00368     }
00369 
00370     it++;
00371   }
00372 }
00373 
00374 /* Paint the window transformed */
00375 
00376 bool
00377 UnityDialogWindow::glPaint(const GLWindowPaintAttrib& attrib,
00378                            const GLMatrix&        transform,
00379                            const CompRegion&        region,
00380                            unsigned int        mask)
00381 {
00382   GLMatrix wTransform(transform);
00383 
00384   if (mParent)
00385     mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
00386 
00387   if (mTargetPos != mCurrentPos)
00388   {
00389     float progress = mShadeProgress / (float) OPAQUE;
00390     mask |= PAINT_WINDOW_TRANSFORMED_MASK;
00391 
00392     int dx = ((mTargetPos.x() - mCurrentPos.x()) * progress);
00393     int dy = ((mTargetPos.y() - mCurrentPos.y()) * progress);
00394 
00395     dx += mCurrentPos.x() - window->serverBorderRect().x();
00396     dy += mCurrentPos.y() - window->serverBorderRect().y();
00397 
00398     wTransform.translate(dx, dy, 0);
00399 
00400     if (mShadeProgress == OPAQUE)
00401       mTargetPos = mCurrentPos;
00402   }
00403 
00404   return gWindow->glPaint(attrib, wTransform, region, mask);
00405 }
00406 
00407 /* Collect regions and matrices */
00408 void
00409 UnityDialogWindow::glAddGeometry(const GLTexture::MatrixList& matrices,
00410                                  const CompRegion&            region,
00411                                  const CompRegion&            clipRegion,
00412                                  unsigned int                min,
00413                                  unsigned int                max)
00414 {
00415   unity::PaintInfoCollector::Active ()->processGeometry (matrices, region, min, max);
00416 
00417   gWindow->glAddGeometry(matrices, region, clipRegion, min, max);
00418 }
00419 
00420 /* Collect textures */
00421 void
00422 UnityDialogWindow::glDrawTexture(GLTexture*          texture,
00423 #ifdef USE_MODERN_COMPIZ_GL
00424                                  const GLMatrix            &transform,
00425                                  const GLWindowPaintAttrib &attrib,
00426 #else
00427                                  GLFragment::Attrib& fa,
00428 #endif
00429                                  unsigned int       mask)
00430 {
00431   unity::PaintInfoCollector::Active ()->processTexture (texture);
00432 }
00433 
00434 unity::GeometryCollection::GeometryCollection() :
00435   collectedMatrixLists (1),
00436   collectedRegions (1),
00437   collectedMinVertices (1),
00438   collectedMaxVertices (1)
00439 {
00440 }
00441 
00442 bool
00443 unity::GeometryCollection::status ()
00444 {
00445   return (collectedMatrixLists.size () == collectedRegions.size () &&
00446          collectedRegions.size () == collectedMaxVertices.size () &&
00447          collectedMaxVertices.size () == collectedMinVertices.size () &&
00448          collectedMinVertices.size () == collectedMatrixLists.size ());
00449 }
00450 
00451 void
00452 unity::GeometryCollection::addGeometryForWindow (CompWindow *w, const CompRegion &paintRegion)
00453 {
00454   /* We can reset the window geometry since it will be
00455    * re-added later */
00456 #ifdef USE_MODERN_COMPIZ_GL
00457   GLWindow::get (w)->vertexBuffer()->begin();
00458 #else
00459   GLWindow::get (w)->geometry().reset();
00460 #endif
00461 
00462   for (unsigned int i = 0; i < collectedMatrixLists.size (); i++)
00463   {
00464     GLTexture::MatrixList matl = collectedMatrixLists[i];
00465     CompRegion            reg  = collectedRegions[i];
00466     int                   min = collectedMinVertices[i];
00467     int                   max = collectedMaxVertices[i];
00468 
00469     /* Now allow plugins to mess with the geometry of our
00470      * dim (so we get a nice render for things like
00471      * wobbly etc etc */
00472     GLWindow::get (w)->glAddGeometry(matl, reg, paintRegion, min, max);
00473   }
00474 
00475 #ifdef USE_MODERN_COMPIZ_GL
00476   GLWindow::get (w)->vertexBuffer()->end();
00477 #endif
00478 }
00479 
00480 void
00481 unity::GeometryCollection::addGeometry(const GLTexture::MatrixList &ml,
00482                                    const CompRegion            &r,
00483                                    int                         min,
00484                                    int                         max)
00485 {
00486   collectedMatrixLists.push_back (ml);
00487   collectedRegions.push_back (r);
00488   collectedMaxVertices.push_back (max);
00489   collectedMinVertices.push_back (min);
00490 }
00491 
00492 unity::TexGeometryCollection::TexGeometryCollection() :
00493   mTexture (NULL)
00494 {
00495 }
00496 
00497 void
00498 unity::TexGeometryCollection::addGeometry(const GLTexture::MatrixList &ml,
00499                                      const CompRegion            &r,
00500                                      int                         max,
00501                                      int                         min)
00502 {
00503   mGeometries.addGeometry(ml, r, max, min);
00504 }
00505 
00506 void
00507 unity::TexGeometryCollection::setTexture (GLTexture *tex)
00508 {
00509   mTexture = tex;
00510 }
00511 
00512 void
00513 unity::TexGeometryCollection::addGeometriesAndDrawTextureForWindow(CompWindow *w,
00514 #ifdef USE_MODERN_COMPIZ_GL
00515                                                                    const GLMatrix &transform,
00516 #endif
00517                                                                    unsigned int mask)
00518 {
00519   if (mTexture && mGeometries.status ())
00520   {
00521     CompRegion paintRegion = w->region ();
00522     GLWindow   *gWindow = GLWindow::get (w);
00523 
00524     if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
00525       paintRegion = infiniteRegion;
00526 
00527     mGeometries.addGeometryForWindow (w, paintRegion);
00528 
00529 #ifdef USE_MODERN_COMPIZ_GL
00530     UnityDialogScreen *uds = UnityDialogScreen::get (screen);
00531     GLWindowPaintAttrib attrib (gWindow->lastPaintAttrib());
00532     unsigned int glDrawTextureIndex = gWindow->glDrawTextureGetCurrentIndex();
00533     /* Texture rendering set-up */
00534 //    uds->gScreen->setTexEnvMode(GL_MODULATE);
00535     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00536     /* Draw the dim texture with all of it's modified
00537      * geometry glory */
00538     gWindow->glDrawTextureSetCurrentIndex(MAXSHORT);
00539     gWindow->glDrawTexture(mTexture, transform, attrib, mask
00540                                          | PAINT_WINDOW_BLEND_MASK
00541                                          | PAINT_WINDOW_TRANSLUCENT_MASK
00542                                          | PAINT_WINDOW_TRANSFORMED_MASK);
00543     gWindow->glDrawTextureSetCurrentIndex(glDrawTextureIndex);
00544     /* Texture rendering tear-down */
00545     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00546     uds->gScreen->setTexEnvMode(GL_REPLACE);
00547 #else
00548     if (gWindow->geometry().vertices)
00549     {
00550        UnityDialogScreen *uds = UnityDialogScreen::get (screen);
00551        GLFragment::Attrib fa (gWindow->lastPaintAttrib());
00552        unsigned int glDrawTextureIndex = gWindow->glDrawTextureGetCurrentIndex();
00553        /* Texture rendering set-up */
00554        uds->gScreen->setTexEnvMode(GL_MODULATE);
00555        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00556        /* Draw the dim texture with all of it's modified
00557           * geometry glory */
00558        gWindow->glDrawTextureSetCurrentIndex(MAXSHORT);
00559        gWindow->glDrawTexture(mTexture, fa, mask | PAINT_WINDOW_BLEND_MASK
00560                             | PAINT_WINDOW_TRANSLUCENT_MASK |
00561                             PAINT_WINDOW_TRANSFORMED_MASK);
00562        gWindow->glDrawTextureSetCurrentIndex(glDrawTextureIndex);
00563        /* Texture rendering tear-down */
00564        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00565        uds->gScreen->setTexEnvMode(GL_REPLACE);
00566     }
00567 #endif
00568   }
00569 }
00570 
00571 unity::PaintInfoCollector::PaintInfoCollector (CompWindow *w) :
00572   mWindow (w)
00573 {
00574 }
00575 
00576 void
00577 unity::PaintInfoCollector::collect()
00578 {
00579   GLWindow *gWindow = GLWindow::get (mWindow);
00580   UnityDialogWindow *udw = UnityDialogWindow::get (mWindow);
00581   GLMatrix sTransform;
00582 
00583   sTransform.toScreenSpace(&screen->outputDevs()[screen->outputDeviceForGeometry(mWindow->geometry())], -DEFAULT_Z_CAMERA);
00584 
00585   gWindow->glDrawTextureSetEnabled(udw, true);
00586   gWindow->glAddGeometrySetEnabled(udw, true);
00587   gWindow->glDrawSetEnabled(udw, false);
00588   gWindow->glPaintSetEnabled(udw, false);
00589 
00590   mCollection.push_back (unity::TexGeometryCollection ());
00591 
00592   unity::PaintInfoCollector::active_collector = this;
00593 
00594   gWindow->glPaint(gWindow->lastPaintAttrib(), sTransform, infiniteRegion, 0);
00595 
00596   unity::PaintInfoCollector::active_collector = NULL;
00597 
00598   gWindow->glDrawTextureSetEnabled(udw, false);
00599   gWindow->glAddGeometrySetEnabled(udw, false);
00600   gWindow->glDrawSetEnabled(udw, true);
00601   gWindow->glPaintSetEnabled(udw, true);
00602 }
00603 
00604 void
00605 unity::PaintInfoCollector::processGeometry (const GLTexture::MatrixList &ml,
00606                                  const CompRegion            &r,
00607                                  int                         min,
00608                                  int                         max)
00609 {
00610   mCollection.back ().addGeometry (ml, r, min, max);
00611 }
00612 
00613 void
00614 unity::PaintInfoCollector::processTexture (GLTexture *tex)
00615 {
00616   mCollection.back().setTexture (tex);
00617   mCollection.push_back (unity::TexGeometryCollection ());
00618 }
00619 
00620 void
00621 unity::PaintInfoCollector::drawGeometriesForWindow(CompWindow *w,
00622 #ifdef USE_MODERN_COMPIZ_GL
00623                                                    const GLMatrix &transform,
00624 #endif
00625                                                    unsigned int pm)
00626 {
00627   for (unity::TexGeometryCollection &tcg : mCollection)
00628 #if USE_MODERN_COMPIZ_GL
00629     tcg.addGeometriesAndDrawTextureForWindow (w, transform, pm);
00630 #else
00631     tcg.addGeometriesAndDrawTextureForWindow (w, pm);
00632 #endif
00633 }
00634 
00635 unity::PaintInfoCollector * unity::PaintInfoCollector::active_collector = NULL;
00636 
00637 unity::PaintInfoCollector *
00638 unity::PaintInfoCollector::Active ()
00639 {
00640   return active_collector;
00641 }
00642 
00643 /* Draw the window */
00644 
00645 bool
00646 UnityDialogWindow::glDraw(const GLMatrix& transform,
00647 #ifdef USE_MODERN_COMPIZ_GL
00648                           const GLWindowPaintAttrib& attrib,
00649 #else
00650                           GLFragment::Attrib& fragment,
00651 #endif
00652                           const CompRegion& region,
00653                           unsigned int mask)
00654 {
00655   /* We want to set the geometry of the dim to the window
00656    * region */
00657   CompRegion reg = CompRegion(window->x(), window->y(), window->width(), window->height());
00658   CompRegion        paintRegion(region);
00659 
00660   /* Draw the window on the bottom, we will be drawing the
00661    * dim render on top */
00662   bool status = gWindow->glDraw(transform,
00663 #ifdef USE_MODERN_COMPIZ_GL
00664                                 attrib,
00665 #else
00666                                 fragment,
00667 #endif
00668                                 region, mask);
00669 
00670   UNITY_DIALOG_SCREEN(screen);
00671 
00672   for (GLTexture* tex : uds->tex())
00673   {
00674     GLTexture::MatrixList matl;
00675     GLTexture::Matrix     mat = tex->matrix();
00676 #ifdef USE_MODERN_COMPIZ_GL
00677     GLWindowPaintAttrib   wAttrib(attrib);
00678 #endif
00679 
00680     /* We can reset the window geometry since it will be
00681      * re-added later */
00682 #ifdef USE_MODERN_COMPIZ_GL
00683     gWindow->vertexBuffer()->begin();
00684 #else
00685     gWindow->geometry().reset();
00686 #endif
00687 
00688     /* Scale the dim render by the ratio of dim size
00689      * to window size */
00690     mat.xx *= (4) / window->width();
00691     mat.yy *= (4) / window->height();
00692 
00693     /* Not sure what this does, but it is necessary
00694      * (adjusts for scale?) */
00695     mat.x0 -= mat.xx * reg.boundingRect().x1();
00696     mat.y0 -= mat.yy * reg.boundingRect().y1();
00697 
00698     matl.push_back(mat);
00699 
00700     if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
00701       paintRegion = infiniteRegion;
00702 
00703     /* Now allow plugins to mess with the geometry of our
00704      * dim (so we get a nice render for things like
00705      * wobbly etc etc */
00706     gWindow->glAddGeometry(matl, reg, paintRegion);
00707 #ifdef USE_MODERN_COMPIZ_GL
00708     gWindow->vertexBuffer()->end();
00709 #endif
00710 
00711 #ifdef USE_MODERN_COMPIZ_GL
00712     unsigned int glDrawTextureIndex = gWindow->glDrawTextureGetCurrentIndex();
00713     wAttrib.opacity = mShadeProgress;
00714     /* Texture rendering set-up */
00715 //    uds->gScreen->setTexEnvMode(GL_MODULATE);
00716     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00717     /* Draw the dim texture with all of it's modified
00718      * geometry glory */
00719     gWindow->glDrawTextureSetCurrentIndex(MAXSHORT);
00720     gWindow->glDrawTexture(tex, transform, attrib, mask
00721                                               | PAINT_WINDOW_BLEND_MASK
00722                                               | PAINT_WINDOW_TRANSLUCENT_MASK
00723                                               | PAINT_WINDOW_TRANSFORMED_MASK);
00724     gWindow->glDrawTextureSetCurrentIndex(glDrawTextureIndex);
00725     /* Texture rendering tear-down */
00726     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00727     uds->gScreen->setTexEnvMode(GL_REPLACE);
00728 #else
00729     /* Did it succeed? */
00730     if (gWindow->geometry().vertices)
00731     {
00732       unsigned int glDrawTextureIndex = gWindow->glDrawTextureGetCurrentIndex();
00733       fragment.setOpacity(mShadeProgress);
00734       /* Texture rendering set-up */
00735       uds->gScreen->setTexEnvMode(GL_MODULATE);
00736       glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00737       /* Draw the dim texture with all of it's modified
00738        * geometry glory */
00739       gWindow->glDrawTextureSetCurrentIndex(MAXSHORT);
00740       gWindow->glDrawTexture(tex, fragment, mask | PAINT_WINDOW_BLEND_MASK
00741                              | PAINT_WINDOW_TRANSLUCENT_MASK |
00742                              PAINT_WINDOW_TRANSFORMED_MASK);
00743       gWindow->glDrawTextureSetCurrentIndex(glDrawTextureIndex);
00744       /* Texture rendering tear-down */
00745       glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00746       uds->gScreen->setTexEnvMode(GL_REPLACE);
00747     }
00748 #endif
00749   }
00750 
00751   for (CompWindow* w : mTransients)
00752   {
00753     if (GLWindow::get(w)->textures().empty())
00754       GLWindow::get(w)->bind();
00755 
00756     if (!UnityDialogWindow::get(w)->mIsAnimated)
00757     {
00758       unity::PaintInfoCollector pc (w);
00759 
00760       pc.collect();
00761       pc.drawGeometriesForWindow (window,
00762 #ifdef USE_MODERN_COMPIZ_GL
00763                                   transform,
00764 #endif
00765                                   mask);
00766     }
00767   }
00768 
00769   return status;
00770 }
00771 
00772 void
00773 UnityDialogWindow::getAllowedActions(unsigned int& setActions,
00774                                      unsigned int& clearActions)
00775 {
00776   window->getAllowedActions(setActions, clearActions);
00777 
00778   if (!mParent)
00779     return;
00780 
00781   clearActions |= (CompWindowActionMoveMask |
00782                    CompWindowActionMaximizeVertMask |
00783                    CompWindowActionMaximizeHorzMask |
00784                    CompWindowActionResizeMask);
00785 }
00786 
00787 void
00788 UnityDialogWindow::adjustIPW()
00789 {
00790   XWindowChanges xwc;
00791 
00792   if (!mIpw)
00793     return;
00794 
00795   xwc.stack_mode = Above;
00796   xwc.x = window->input().left;
00797   xwc.y = window->input().top;
00798   xwc.width = window->width();
00799   xwc.height = window->height();
00800 
00801   XConfigureWindow(screen->dpy(), mIpw, CWStackMode | CWWidth | CWHeight | CWX | CWY, &xwc);
00802 }
00803 
00804 bool
00805 UnityDialogWindow::addTransient(CompWindow* w)
00806 {
00807   bool alreadyAdded = false;
00808   bool newParent = false;
00809 
00810   if (!mTransients.size())
00811   {
00812     gWindow->glDrawSetEnabled(this, true);
00813     gWindow->glPaintSetEnabled(this, true);
00814     window->grabNotifySetEnabled(this, true);
00815     window->ungrabNotifySetEnabled(this, true);
00816     window->moveNotifySetEnabled(this, true);
00817     cWindow->addDamage();
00818 
00819     if (!mIpw)
00820     {
00821       XSetWindowAttributes attr;
00822 
00823       attr.override_redirect = true;
00824 
00825       mIpw = XCreateWindow(screen->dpy(), window->frame(), window->input().left,
00826                            window->input().top, window->width(), window->height(),
00827                            0, 0, InputOnly, CopyFromParent, CWOverrideRedirect, &attr);
00828 
00829       XSelectInput(screen->dpy(), mIpw, StructureNotifyMask | ButtonPressMask);
00830 
00831       XMapWindow(screen->dpy(), mIpw);
00832       adjustIPW();
00833     }
00834 
00835     mCurrentPos = mTargetPos = window->serverBorderRect().pos();
00836 
00837     newParent = true;
00838   }
00839   else
00840   {
00841     for (CompWindow * tw : mTransients)
00842       if (tw->id() == w->id())
00843         alreadyAdded = true;
00844   }
00845 
00846   if (!alreadyAdded)
00847   {
00848     w->grabNotifySetEnabled(this, true);
00849     w->ungrabNotifySetEnabled(this, true);
00850     w->moveNotifySetEnabled(this, true);
00851     w->getAllowedActionsSetEnabled(this, true);
00852     UnityDialogWindow::get(w)->gWindow->glPaintSetEnabled(UnityDialogWindow::get(w), !mIsAnimated);
00853     UnityDialogWindow::get(w)->mParent = window;
00854     UnityDialogWindow::get(w)->setMaxConstrainingAreas();
00855 
00856     screen->matchPropertyChanged(window);
00857     w->recalcActions();
00858     mTransients.push_back(w);
00859   }
00860 
00861   return newParent;
00862 }
00863 
00864 bool
00865 UnityDialogWindow::removeTransient(CompWindow* w)
00866 {
00867   mTransients.remove(w);
00868 
00869   w->grabNotifySetEnabled(this, false);
00870   w->ungrabNotifySetEnabled(this, false);
00871   w->moveNotifySetEnabled(this, false);
00872   w->getAllowedActionsSetEnabled(this, false);
00873   UnityDialogWindow::get(w)->mParent = NULL;
00874   screen->matchPropertyChanged(window);
00875   w->recalcActions();
00876 
00877   if (!mTransients.size())
00878   {
00879     XWindowChanges xwc;
00880     unsigned int   mask = 0;
00881 
00882     window->ungrabNotifySetEnabled(this, false);
00883     window->grabNotifySetEnabled(this, false);
00884     window->moveNotifySetEnabled(this, false);
00885 
00886     if (mIpw)
00887     {
00888       XDestroyWindow(screen->dpy(), mIpw);
00889       mIpw = None;
00890     }
00891 
00892     if (mDiffXWC.width)
00893     {
00894       xwc.width = window->width() - mDiffXWC.width;
00895       mask |= CWWidth;
00896     }
00897 
00898     if (mDiffXWC.height)
00899     {
00900       xwc.height = window->height() - mDiffXWC.height;
00901       mask |= CWHeight;
00902     }
00903 
00904     if (mask)
00905       window->configureXWindow(mask, &xwc);
00906 
00907     cWindow->addDamage();
00908     window->move(-mOffset.x() - mDiffXWC.x, -mOffset.y() - mDiffXWC.y, true);
00909     window->syncPosition();
00910     cWindow->addDamage();
00911 
00912     memset(&mDiffXWC, 0, sizeof(XWindowChanges));
00913 
00914     mCurrentPos = CompPoint(window->serverBorderRect().x(), window->serverBorderRect().y());
00915     mTargetPos = mCurrentPos + mOffset;
00916     mOffset = CompPoint(0, 0);
00917 
00918     return true;
00919   }
00920 
00921   return false;
00922 }
00923 
00924 void
00925 UnityDialogScreen::trackParent(CompWindow* w)
00926 {
00927   unsigned long* data = new unsigned long;
00928 
00929   *data = 1;
00930 
00931   if (!mParentWindows.size())
00932   {
00933     cScreen->preparePaintSetEnabled(this, true);
00934     gScreen->glPaintOutputSetEnabled(this, true);
00935     cScreen->donePaintSetEnabled(this, true);
00936   }
00937 
00938   /* Set the _UNITY_IS_PARENT property */
00939   XChangeProperty(screen->dpy(), w->id(), mUnityIsParentAtom, XA_CARDINAL,
00940                   32, PropModeReplace, (const unsigned char*) data, 1);
00941 
00942   delete data;
00943 
00944   mParentWindows.push_back(w);
00945 }
00946 
00947 void
00948 UnityDialogScreen::untrackParent(CompWindow* w)
00949 {
00950   CompWindowList::iterator it = std::find(mParentWindows.begin(), mParentWindows.end(), w);
00951 
00952   if (it != mParentWindows.end())
00953   {
00954     mParentWindows.erase(it);
00955 
00956     /* Unset the _UNITY_IS_PARENT property */
00957     XDeleteProperty(screen->dpy(), w->id(), mUnityIsParentAtom);
00958 
00959     if (!mParentWindows.size())
00960     {
00961       cScreen->preparePaintSetEnabled(this, false);
00962       gScreen->glPaintOutputSetEnabled(this, false);
00963       cScreen->donePaintSetEnabled(this, false);
00964     }
00965   }
00966 }
00967 
00968 void
00969 UnityDialogWindow::windowNotify(CompWindowNotify n)
00970 {
00971   switch (n)
00972   {
00973     case CompWindowNotifyClose:
00974 
00975       /* If this window was a transient for some other window
00976          * then decrement the transient count */
00977 
00978       if (mParent)
00979         UnityDialogWindow::get(mParent)->removeTransient(window);
00980 
00981       break;
00982 
00983     case CompWindowNotifyFrameUpdate:
00984 
00985       if (mParent)
00986         moveToRect(mParent->serverBorderRect(), true);
00987 
00988     default:
00989       break;
00990   }
00991 
00992   window->windowNotify(n);
00993 }
00994 
00995 void
00996 UnityDialogWindow::grabNotify(int x, int y,
00997                               unsigned int state,
00998                               unsigned int mask)
00999 {
01000   mGrabMask = mask;
01001 
01002   window->grabNotify(x, y, state, mask);
01003 
01004   if (!mSkipNotify && (mask & CompWindowGrabMoveMask))
01005   {
01006     moveTransientsToRect(NULL, window->serverBorderRect(), true);
01007 
01008     grabTransients(NULL, x, y, state, mask, true);
01009   }
01010 }
01011 
01012 void
01013 UnityDialogWindow::ungrabNotify()
01014 {
01015   mGrabMask = 0;
01016 
01017   window->ungrabNotify();
01018 
01019   if (!mSkipNotify)
01020   {
01021     moveTransientsToRect(NULL, window->serverBorderRect(), true);
01022     grabTransients(NULL, 0, 0, 0, 0, false);
01023   }
01024 }
01025 
01026 void
01027 UnityDialogWindow::resizeNotify(int dx, int dy,
01028                                 int dwidth,
01029                                 int dheight)
01030 {
01031   window->resizeNotify(dx, dy, dwidth, dheight);
01032 
01033   /* The window resized was a parent window, re-center transients */
01034   if (!mSkipNotify)
01035   {
01036     moveTransientsToRect(NULL, window->serverBorderRect(), true);
01037 
01038     if (mIpw)
01039       adjustIPW();
01040 
01041     if (mParent)
01042       UnityDialogWindow::get(mParent)->moveTransientsToRect(NULL, mParent->serverBorderRect(), true);
01043   }
01044 }
01045 
01046 void
01047 UnityDialogWindow::moveNotify(int dx, int dy, bool immediate)
01048 {
01049   window->moveNotify(dx, dy, immediate);
01050 
01051   if (!mSkipNotify)
01052   {
01053     if (mParent && UnityDialogScreen::get(screen)->switchingVp() &&
01054         !(mGrabMask & CompWindowGrabMoveMask))
01055     {
01056       moveParentToRect(window, window->serverBorderRect(), true);
01057     }
01058     else if (mParent)
01059     {
01060       moveToRect(mParent->serverBorderRect(), true);
01061     }
01062     else
01063       moveTransientsToRect(window, window->serverBorderRect(), true);
01064   }
01065 }
01066 
01067 void
01068 UnityDialogWindow::setMaxConstrainingAreas()
01069 {
01070   /* Don't set maximum size hints if they are already set to a value
01071    * that is lower than ours (unlikely, but it has a chance of
01072    * happening so we need to handle this case)
01073    *
01074    * Also, core will set max_width to the same as min_width in the
01075    * case that somehow our requested max_width < min_width, so
01076    * detect this case too.
01077    *
01078    * In the case where we're goign to make the dialog window smaller
01079    * than it actually is, don't allow this, instead make parent window
01080    * at least 1.25x bigger than the dialog window and set the maximum
01081    * size of the dialog window to 0.8x the parent window
01082    */
01083 
01084   bool sizeHintsSet = false;
01085   bool needsWidth, needsHeight;
01086   XWindowChanges xwc;
01087   unsigned int   changeMask = 0;
01088 
01089   if (!(mParent->state() & MAXIMIZE_STATE ||
01090         mParent->state() & CompWindowStateFullscreenMask))
01091   {
01092 
01093     if (mParent->serverBorderRect().width() < window->serverBorderRect().width() * 1.25)
01094     {
01095       xwc.width = window->serverBorderRect().width() * 1.25;
01096       xwc.x = mParent->x() - ((window->serverBorderRect().width() * 1.25) -
01097                               (mParent->serverBorderRect().width())) / 2.0;
01098 
01099       /* Don't ever put the parent window offscreen */
01100       if (xwc.x < screen->workArea().left() + mParent->border().left)
01101         xwc.x = screen->workArea().left() + mParent->border().left;
01102       else if (xwc.x + xwc.width > screen->workArea().right() - mParent->border().right)
01103         xwc.x = screen->workArea().right() - xwc.width - mParent->border().right;
01104 
01105       if (!UnityDialogWindow::get(mParent)->mDiffXWC.width)
01106         UnityDialogWindow::get(mParent)->mDiffXWC.width = xwc.width - mParent->width();
01107       if (!UnityDialogWindow::get(mParent)->mDiffXWC.x)
01108       {
01109         UnityDialogWindow::get(mParent)->mDiffXWC.x = xwc.x - mParent->x();
01110         (UnityDialogWindow::get(mParent))->mCurrentPos += CompPoint(UnityDialogWindow::get(mParent)->mDiffXWC.x, 0);
01111         (UnityDialogWindow::get(mParent))->mTargetPos += CompPoint(UnityDialogWindow::get(mParent)->mDiffXWC.x, 0);
01112       }
01113 
01114       changeMask |= CWX | CWWidth;
01115     }
01116 
01117     if (mParent->serverBorderRect().height() < window->serverBorderRect().height() * 1.25)
01118     {
01119       xwc.height = window->serverBorderRect().height() * 1.25;
01120       xwc.y = mParent->y() - ((window->serverBorderRect().height() * 1.25) -
01121                               (mParent->serverBorderRect().height())) / 2.0;
01122 
01123       /* Don't ever put the parent window offscreen */
01124       if (xwc.y < screen->workArea().top() + mParent->border().top)
01125         xwc.y = screen->workArea().top() + mParent->border().top;
01126       else if (xwc.y + xwc.height > screen->workArea().bottom() - mParent->border().bottom)
01127         xwc.y = screen->workArea().bottom() - xwc.height - mParent->border().bottom;
01128 
01129       if (!UnityDialogWindow::get(mParent)->mDiffXWC.height)
01130         UnityDialogWindow::get(mParent)->mDiffXWC.height = xwc.height - mParent->height();
01131       if (!UnityDialogWindow::get(mParent)->mDiffXWC.y)
01132       {
01133         UnityDialogWindow::get(mParent)->mDiffXWC.y = xwc.y - mParent->y();
01134         (UnityDialogWindow::get(mParent))->mCurrentPos += CompPoint(0, UnityDialogWindow::get(mParent)->mDiffXWC.y);
01135         (UnityDialogWindow::get(mParent))->mTargetPos += CompPoint(0, UnityDialogWindow::get(mParent)->mDiffXWC.y);
01136       }
01137 
01138       changeMask |= CWY | CWHeight;
01139     }
01140 
01141   }
01142 
01143   if (changeMask)
01144     mParent->configureXWindow(changeMask, &xwc);
01145 
01146   needsWidth = mOldHintsSize.width() != window->sizeHints().max_width;
01147 
01148   if (needsWidth)
01149     needsWidth = !(mOldHintsSize.width() && window->sizeHints().max_width ==
01150                    window->sizeHints().min_width);
01151 
01152   needsHeight = mOldHintsSize.height() != window->sizeHints().max_height;
01153 
01154   if (needsHeight)
01155     needsHeight = !(mOldHintsSize.height() && window->sizeHints().max_height ==
01156                     window->sizeHints().min_height);
01157 
01158   if (mParent && (window->sizeHints().flags & PMaxSize) && needsWidth && needsHeight)
01159   {
01160     sizeHintsSet |= ((window->sizeHints().max_width <
01161                       mParent->serverGeometry().width() * 0.8) ||
01162                      (window->sizeHints().max_height <
01163                       mParent->serverGeometry().height() * 0.8));
01164   }
01165 
01166   if (mParent && (!sizeHintsSet))
01167   {
01168     XSizeHints sizeHints = window->sizeHints();
01169 
01170     sizeHints.flags |= PMaxSize;
01171     sizeHints.max_width = mParent->serverGeometry().width() * 0.8;
01172     sizeHints.max_height = mParent->serverGeometry().height() * 0.8;
01173 
01174     mOldHintsSize = CompSize(sizeHints.max_width, sizeHints.max_height);
01175     XSetWMNormalHints(screen->dpy(), window->id(), &sizeHints);
01176   }
01177 }
01178 
01179 
01180 CompPoint
01181 UnityDialogWindow::getChildCenteredPositionForRect(CompRect currentRect)
01182 {
01183   int centeredX = currentRect.x() + (currentRect.width() / 2 -
01184                                      window->serverBorderRect().width() / 2);
01185   int centeredY = currentRect.y() + (currentRect.height() / 2 -
01186                                      window->serverBorderRect().height() / 2);
01187 
01188   return CompPoint(centeredX, centeredY);
01189 }
01190 
01191 CompPoint
01192 UnityDialogWindow::getParentCenteredPositionForRect(CompRect currentRect)
01193 {
01194   int centeredX = currentRect.x() + (currentRect.width() / 2 -
01195                                      window->serverBorderRect().width() / 2);
01196   int centeredY = currentRect.y() + (currentRect.height() / 2 -
01197                                      window->serverBorderRect().height() / 2);
01198 
01199   return CompPoint(centeredX, centeredY);
01200 }
01201 
01202 void
01203 UnityDialogWindow::grabTransients(CompWindow* skip, int x, int y,
01204                                   unsigned int state, unsigned int mask,
01205                                   bool grab)
01206 {
01207   /* Center transients (leave a bit more space
01208    * below) */
01209 
01210   for (CompWindow* cw : mTransients)
01211   {
01212     UnityDialogWindow* udw = UnityDialogWindow::get(cw);
01213 
01214     if (cw == skip)
01215       return;
01216 
01217     udw->mSkipNotify = true;
01218 
01219     if (grab)
01220       udw->grabNotify(x, y, state, mask);
01221     else
01222       udw->ungrabNotify();
01223 
01224     udw->mSkipNotify = false;
01225   }
01226 }
01227 
01228 void
01229 UnityDialogWindow::animateTransients(CompWindow* skip, CompPoint& orig, CompPoint& dest, bool cont)
01230 {
01231   /* Center transients (leave a bit more space
01232    * below) */
01233 
01234   for (CompWindow* cw : mTransients)
01235   {
01236     UnityDialogWindow* udw = UnityDialogWindow::get(cw);
01237     CompRect newRect(dest.x(), dest.y(), window->serverBorderRect().width(), window->serverBorderRect().height());
01238 
01239     if (cw == skip)
01240       return;
01241 
01242     udw->mTargetPos = udw->getChildCenteredPositionForRect(newRect);
01243     udw->mCurrentPos = CompPoint(cw->serverBorderRect().x(), cw->serverBorderRect().y());
01244     udw->mOffset = udw->mTargetPos - udw->mCurrentPos;
01245 
01246     /* New transient position is centered to this window's target position */
01247     if (cont)
01248       udw->animateTransients(NULL, udw->mTargetPos, udw->mCurrentPos, true);
01249   }
01250 }
01251 
01252 void
01253 UnityDialogWindow::animateParent(CompWindow* requestor, CompPoint& orig, CompPoint& dest)
01254 {
01255   if (mParent)
01256   {
01257     if (!(mParent->state() & MAXIMIZE_STATE ||
01258           mParent->state() & CompWindowStateFullscreenMask))
01259     {
01260       UnityDialogWindow* udw = UnityDialogWindow::get(mParent);
01261       CompRect newRect(dest.x(), dest.y(), window->serverBorderRect().width(), window->serverBorderRect().height());
01262 
01263       udw->mTargetPos = udw->getParentCenteredPositionForRect(newRect);
01264       udw->mCurrentPos = CompPoint(mParent->serverBorderRect().x(), mParent->serverBorderRect().y());
01265       udw->mOffset = udw->mTargetPos - udw->mCurrentPos;
01266 
01267       udw->animateTransients(NULL, udw->mTargetPos, udw->mCurrentPos, false);
01268     }
01269   }
01270 }
01271 
01272 void
01273 UnityDialogWindow::moveTransientsToRect(CompWindow* skip, CompRect currentRect, bool sync)
01274 {
01275   /* Center transients (leave a bit more space
01276    * below) */
01277 
01278   for (CompWindow* cw : mTransients)
01279   {
01280     if (cw == skip)
01281       return;
01282 
01283     UnityDialogWindow::get(cw)->moveToRect(currentRect, sync);
01284 
01285     /* Sync all of this window's transients */
01286     if (UnityDialogWindow::get(cw)->mTransients.size())
01287       UnityDialogWindow::get(cw)->moveTransientsToRect(NULL, cw->serverBorderRect(), sync);
01288   }
01289 }
01290 
01291 void
01292 UnityDialogWindow::moveParentToRect(CompWindow*      requestor,
01293                                     CompRect      rect,
01294                                     bool      sync)
01295 {
01296   if (mParent)
01297   {
01298     if (!(mParent->state() & MAXIMIZE_STATE ||
01299           mParent->state() & CompWindowStateFullscreenMask))
01300     {
01301       CompPoint centeredPos = UnityDialogWindow::get(mParent)->getParentCenteredPositionForRect(rect);
01302       UnityDialogWindow::get(mParent)->mSkipNotify = true;
01303 
01304       /* Move the parent window to the requested position */
01305       mParent->move(centeredPos.x() - mParent->borderRect().x(),
01306                     centeredPos.y() - mParent->borderRect().y(), true);
01307 
01308       if (sync)
01309         mParent->syncPosition();
01310 
01311       UnityDialogWindow::get(mParent)->mSkipNotify = false;
01312 
01313       UnityDialogWindow::get(mParent)->moveTransientsToRect(requestor, window->serverBorderRect(), sync);
01314       UnityDialogWindow::get(mParent)->moveParentToRect(window, window->serverBorderRect(), sync);
01315     }
01316   }
01317 
01318 }
01319 
01320 CompWindow*
01321 UnityDialogWindow::transientParent()
01322 {
01323   if (window->transientFor() &&
01324       window->state() & CompWindowStateModalMask &&
01325       !UnityDialogScreen::get(screen)->optionGetAvoidMatch().evaluate(window))
01326   {
01327     Window xid = window->transientFor();
01328 
01329     /* Some stupid applications set the WM_TRANSIENT_FOR to an unmapped window
01330      * but one that is strangely still managed *cough*qt*cough*. Those applications
01331      * deserve to be shot. In any case, we'll need to work around that by assuming
01332      * that this is a modal dialog with *a* parent, so go for the largest window
01333      * in this client group that's not a transient for anything */
01334 
01335     CompWindow* parent = screen->findWindow(xid);
01336 
01337     if (!parent->isViewable() || parent->overrideRedirect())
01338     {
01339       compLogMessage("unitydialog", CompLogLevelWarn, "window 0x%x sets WM_TRANSIENT_FOR" \
01340                      " in a strange way. Workaround around.\n", window->id());
01341       if (parent->clientLeader())
01342       {
01343         CompWindow* candidate = parent;
01344 
01345        for (CompWindow* w : screen->windows())
01346           if (w->clientLeader() == parent->clientLeader() &&
01347               w->isViewable() && !w->overrideRedirect() &&
01348               (w->geometry().width() * w->geometry().height()) >
01349               (candidate->geometry().width() * candidate->geometry().height()))
01350             candidate = w;
01351 
01352         if (candidate != parent)
01353           parent = candidate;
01354         else
01355           parent = NULL;
01356       }
01357     }
01358 
01359     if (parent)
01360       return parent;
01361   }
01362 
01363   return NULL;
01364 }
01365 
01366 bool
01367 UnityDialogWindow::place(CompPoint& pos)
01368 {
01369   CompWindow* parent;
01370 
01371   /* If this window is a transient for some other window,
01372    * increment the transient count and
01373    * enable the dimming on that other window */
01374 
01375   if ((parent = transientParent()) != NULL)
01376     if (UnityDialogWindow::get(parent)->addTransient(window))
01377       UnityDialogScreen::get(screen)->trackParent(parent);
01378 
01379   /* We need to check the final parent window */
01380 
01381   if (mParent)
01382   {
01383     CompWindow::Geometry transientGeometry;
01384     CompRegion transientPos, outputRegion, outsideArea, outsideRegion;
01385     pos = getChildCenteredPositionForRect(mParent->serverBorderRect());
01386     int    hdirection, vdirection;
01387 
01388     transientGeometry = CompWindow::Geometry(pos.x(),
01389                                              pos.y(),
01390                                              window->borderRect().width(),
01391                                              window->borderRect().height(), 0);
01392 
01393     transientPos = CompRegion((CompRect) transientGeometry);
01394     outputRegion = screen->workArea();
01395     outsideRegion = outputRegion;
01396 
01397     /* Create a w->width () px region outside of the output region */
01398     outsideRegion.shrink(-window->borderRect().width(), -window->borderRect().height());
01399 
01400     outsideRegion -= outputRegion;
01401 
01402     if (!(outsideArea = transientPos.intersected(outsideRegion)).isEmpty())
01403     {
01404       CompRect   transientRect;
01405       CompPoint  orig, dest;
01406       int width;
01407       int height;
01408 
01409       hdirection = outsideArea.boundingRect().x() < 0 ? 1 : -1;
01410       vdirection = outsideArea.boundingRect().y() < 0 ? 1 : -1;
01411 
01412       width  = outsideArea.boundingRect().width() >=
01413                window->serverBorderRect().width() ? 0 :
01414                outsideArea.boundingRect().width() * hdirection;
01415       height = outsideArea.boundingRect().height() >=
01416                window->serverBorderRect().height() ? 0 :
01417                outsideArea.boundingRect().height() * vdirection;
01418 
01419       pos += CompPoint(width, height);
01420       transientPos = CompRegion(pos.x(),
01421                                 pos.y(),
01422                                 window->serverBorderRect().width(), window->serverBorderRect().height());
01423       transientRect = transientPos.boundingRect();
01424 
01425       dest = CompPoint(transientRect.x(), transientRect.y());
01426       orig = CompPoint(mParent->serverBorderRect().x(), mParent->serverBorderRect().y());
01427 
01428       animateParent(window, orig, dest);
01429 
01430       moveParentToRect(window, transientRect, true);
01431 
01432     }
01433 
01434     pos -= CompPoint(window->border().left, window->border().top);
01435 
01436     return true;
01437   }
01438 
01439   return window->place(pos);
01440 }
01441 
01442 void
01443 UnityDialogScreen::handleCompizEvent(const char*    plugin,
01444                                      const char*    event,
01445                                      CompOption::Vector&  o)
01446 {
01447   if (strcmp(event, "start_viewport_switch") == 0)
01448   {
01449     mSwitchingVp = true;
01450   }
01451   else if (strcmp(event, "end_viewport_switch") == 0)
01452   {
01453     mSwitchingVp = false;
01454   }
01455   else if (strcmp(event, "window_animation") == 0)
01456   {
01457     CompWindow* w = screen->findWindow(CompOption::getIntOptionNamed(o, "window", 0));
01458     if (w)
01459     {
01460       if (UnityDialogWindow::get(w)->hasParent())
01461       {
01462         UnityDialogWindow::get(w)->setIsAnimated(CompOption::getBoolOptionNamed(o, "active", false));
01463         GLWindow::get(w)->glPaintSetEnabled(UnityDialogWindow::get(w), !UnityDialogWindow::get(w)->isAnimated());
01464       }
01465     }
01466   }
01467 
01468   screen->handleCompizEvent(plugin, event, o);
01469 }
01470 
01471 void
01472 UnityDialogScreen::handleEvent(XEvent* event)
01473 {
01474   CompWindow* w;
01475 
01476   screen->handleEvent(event);
01477 
01478   switch (event->type)
01479   {
01480     case ClientMessage:
01481 
01482       w = screen->findWindow(event->xclient.window);
01483 
01484       if (event->xclient.message_type == mCompizResizeAtom && w)
01485       {
01486         CompRect currentRect(event->xclient.data.l[0] - w->border().left,
01487                              event->xclient.data.l[1] - w->border().top ,
01488                              event->xclient.data.l[2] + w->border().left + w->border().right,
01489                              event->xclient.data.l[3] + w->border().top + w->border().bottom);
01490         UnityDialogWindow* udw = UnityDialogWindow::get(w);
01491 
01492         udw->moveTransientsToRect(NULL, currentRect, false);
01493 
01494       }
01495       break;
01496     case PropertyNotify:
01497 
01498       if (event->xproperty.type == XA_WM_TRANSIENT_FOR)
01499       {
01500         CompWindow* w = screen->findWindow(event->xproperty.window);
01501 
01502         if (w)
01503         {
01504           CompWindow* parent = screen->findWindow(w->transientFor());
01505           UnityDialogWindow* udw = UnityDialogWindow::get(parent);
01506 
01507           if (!udw->hasTransient(w))
01508           {
01509             /* This window got it's transient status updated
01510              * probably because the app was buggy and decided
01511              * to do so after it was mapped. Work around it
01512              */
01513             if (udw->addTransient(w))
01514               trackParent(parent);
01515 
01516             /* re-center all the transients */
01517 
01518             udw->moveTransientsToRect(w, parent->serverBorderRect(), true);
01519           }
01520         }
01521       }
01522       break;
01523     default:
01524       break;
01525   }
01526 }
01527 
01528 void
01529 UnityDialogScreen::optionChanged(CompOption* option,
01530                                  Options    num)
01531 {
01532   mTex->render(optionGetAlpha());
01533 }
01534 
01535 /* Constructors */
01536 
01537 UnityDialogWindow::UnityDialogWindow(CompWindow* w) :
01538   PluginClassHandler <UnityDialogWindow, CompWindow> (w),
01539   window(w),
01540   cWindow(CompositeWindow::get(w)),
01541   gWindow(GLWindow::get(w)),
01542   mSkipNotify(false),
01543   mParent(NULL),
01544   mOldHintsSize(CompSize(0, 0)),
01545   mGrabMask(0),
01546   mShadeProgress(0),
01547   mIpw(None),
01548   mIsAnimated(false)
01549 {
01550   WindowInterface::setHandler(window, true);
01551   GLWindowInterface::setHandler(gWindow, false);
01552 
01553   memset(&mDiffXWC, 0, sizeof(XWindowChanges));
01554 
01555   window->windowNotifySetEnabled(this, true);
01556 }
01557 
01558 UnityDialogWindow::~UnityDialogWindow()
01559 {
01560   /* Handle weird circumstances where windows go away
01561    * without warning */
01562 
01563   UnityDialogScreen::get(screen)->untrackParent(window);
01564 
01565   if (mParent)
01566   {
01567     compLogMessage("unitydialog", CompLogLevelWarn, "Did not get a close notification before window was destroyed!");
01568     UnityDialogWindow::get(mParent)->removeTransient(window);
01569   }
01570 
01571   /* The parent went away, so make sure that
01572    * all the transients know about this one */
01573   if (mTransients.size())
01574   {
01575     compLogMessage("unitydialog", CompLogLevelWarn, "Parent got closed before transients. This is an indication of a buggy app!");
01576     for(CompWindow* w : mTransients)
01577       UnityDialogWindow::get(mParent)->removeTransient(w);
01578   }
01579 }
01580 
01581 UnityDialogScreen::UnityDialogScreen(CompScreen* s) :
01582   PluginClassHandler <UnityDialogScreen, CompScreen> (s),
01583   cScreen(CompositeScreen::get(s)),
01584   gScreen(GLScreen::get(s)),
01585   mSwitchingVp(false),
01586   mCompizResizeAtom(XInternAtom(screen->dpy(),
01587                                 "_COMPIZ_RESIZE_NOTIFY", 0)),
01588   mUnityIsParentAtom(XInternAtom(screen->dpy(),
01589                                  "_UNITY_IS_PARENT", 0))
01590 {
01591   ScreenInterface::setHandler(screen);
01592   CompositeScreenInterface::setHandler(cScreen, false);
01593   GLScreenInterface::setHandler(gScreen, false);
01594 
01595   optionSetAlphaNotify(boost::bind(&UnityDialogScreen::optionChanged, this, _1, _2));
01596 
01597   mTex = new UnityDialogShadeTexture();
01598   mTex->render(optionGetAlpha());
01599 }
01600 
01601 UnityDialogScreen::~UnityDialogScreen()
01602 {
01603   delete mTex;
01604 }
01605 
01606 bool
01607 UnityDialogPluginVTable::init()
01608 {
01609   if (!CompPlugin::checkPluginABI("core", CORE_ABIVERSION) ||
01610       !CompPlugin::checkPluginABI("composite", COMPIZ_COMPOSITE_ABI) ||
01611       !CompPlugin::checkPluginABI("opengl", COMPIZ_OPENGL_ABI))
01612     return false;
01613 
01614   return true;
01615 }