Back to index

unity  6.0.0
compizminimizedwindowhandler.h
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2011 Canonical Ltd.
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018  *
00019  * Authored By:
00020  * Sam Spilsbury <sam.spilsbury@canonical.com>
00021  */
00022 
00023 #ifndef _COMPIZ_COMPIZMINIMIZEDWINDOWHANDLER_H
00024 #define _COMPIZ_COMPIZMINIMIZEDWINDOWHANDLER_H
00025 
00026 #include <core/core.h>
00027 #include "minimizedwindowhandler.h"
00028 #include "comptransientfor.h"
00029 #include <memory>
00030 
00031 // Will be merged back into compiz
00032 namespace compiz {
00033 
00034 class PrivateCompizMinimizedWindowHandler
00035 {
00036 public:
00037 
00038   PrivateCompizMinimizedWindowHandler () {};
00039 
00040   CompWindow         *mWindow;
00041 };
00042 
00043 template <typename Screen, typename Window>
00044 class CompizMinimizedWindowHandler:
00045     public MinimizedWindowHandler
00046 {
00047 public:
00048 
00049   CompizMinimizedWindowHandler (CompWindow *w, compiz::WindowInputRemoverLockAcquireInterface *lock_acquire);
00050   ~CompizMinimizedWindowHandler ();
00051 
00052   void setVisibility (bool visible);
00053   unsigned int getPaintMask ();
00054 
00055   void minimize ();
00056   void unminimize ();
00057 
00058   void updateFrameRegion (CompRegion &r);
00059 
00060   void windowNotify (CompWindowNotify n);
00061 
00062   static void setFunctions (bool keepMinimized);
00063   static void handleCompizEvent (const char *, const char *, CompOption::Vector &);
00064   static void handleEvent (XEvent *event);
00065   static std::list<CompWindow *> minimizingWindows;
00066 
00067   typedef CompizMinimizedWindowHandler<Screen, Window> Type;
00068   typedef std::list <Type *> List;
00069 protected:
00070 
00071   std::vector<unsigned int> getTransients ();
00072 
00073 private:
00074 
00075   PrivateCompizMinimizedWindowHandler *priv;
00076   static bool handleEvents;
00077   static List minimizedWindows;
00078 };
00079 }
00080 
00081 /* XXX minimizedWindows should be removed because it is dangerous to keep
00082  *     a list of windows separate to compiz-core. The list could get out of
00083  *     sync and cause more crashes like LP: #918329, LP: #864758.
00084  */
00085 template <typename Screen, typename Window>
00086 typename compiz::CompizMinimizedWindowHandler<Screen, Window>::List compiz::CompizMinimizedWindowHandler<Screen, Window>::minimizedWindows;
00087 
00088 template <typename Screen, typename Window>
00089 CompWindowList compiz::CompizMinimizedWindowHandler<Screen, Window>::minimizingWindows;
00090 
00091 template <typename Screen, typename Window>
00092 bool compiz::CompizMinimizedWindowHandler<Screen, Window>::handleEvents = true;
00093 
00094 template <typename Screen, typename Window>
00095 compiz::CompizMinimizedWindowHandler<Screen, Window>::CompizMinimizedWindowHandler(CompWindow *w, compiz::WindowInputRemoverLockAcquireInterface *lock_acquire) :
00096   MinimizedWindowHandler (screen->dpy(), w->id(), lock_acquire)
00097 {
00098   priv = new PrivateCompizMinimizedWindowHandler();
00099 
00100   priv->mWindow = w;
00101 
00102 }
00103 
00104 template <typename Screen, typename Window>
00105 compiz::CompizMinimizedWindowHandler<Screen, Window>::~CompizMinimizedWindowHandler ()
00106 {
00107   minimizingWindows.remove (priv->mWindow);
00108   minimizedWindows.remove (this);
00109 }
00110 
00111 template <typename Screen, typename Window>
00112 std::vector<unsigned int>
00113 compiz::CompizMinimizedWindowHandler<Screen, Window>::getTransients ()
00114 {
00115   std::vector <unsigned int> transients;
00116 
00117   for (CompWindow *w : screen->windows())
00118   {
00119     compiz::CompTransientForReader reader (w);
00120 
00121     if (reader.isTransientFor (priv->mWindow->id()) ||
00122         reader.isGroupTransientFor (priv->mWindow->id()))
00123       transients.push_back (w->id());
00124   }
00125 
00126   return transients;
00127 }
00128 
00129 template <typename Screen, typename Window>
00130 void
00131 compiz::CompizMinimizedWindowHandler<Screen, Window>::setVisibility (bool visible)
00132 {
00133   MinimizedWindowHandler::setVisibility (visible, priv->mWindow->id());
00134 
00135   CompositeWindow::get (priv->mWindow)->addDamage();
00136 }
00137 
00138 template <typename Screen, typename Window>
00139 void
00140 compiz::CompizMinimizedWindowHandler<Screen, Window>::minimize ()
00141 {
00142   Atom          wmState = XInternAtom (screen->dpy(), "WM_STATE", 0);
00143   unsigned long data[2];
00144 
00145   std::vector<unsigned int> transients = getTransients();
00146 
00147   handleEvents = true;
00148   priv->mWindow->windowNotify (CompWindowNotifyMinimize);
00149   priv->mWindow->changeState (priv->mWindow->state() | CompWindowStateHiddenMask);
00150 
00151   minimizedWindows.push_back (this);
00152 
00153   for (unsigned int &w : transients)
00154   {
00155     CompWindow *win = screen->findWindow (w);
00156 
00157     if (win)
00158     {
00159       Window *w = Window::get (win);
00160       if (!w->mMinimizeHandler)
00161         w->mMinimizeHandler.reset (new Type (win, w));
00162       w->mMinimizeHandler->minimize();
00163     }
00164   }
00165 
00166   priv->mWindow->windowNotify (CompWindowNotifyHide);
00167   setVisibility (false);
00168 
00169   data[0] = IconicState;
00170   data[1] = None;
00171 
00172   XChangeProperty (screen->dpy(), priv->mWindow->id(), wmState, wmState,
00173                    32, PropModeReplace, (unsigned char *) data, 2);
00174 
00175   priv->mWindow->changeState (priv->mWindow->state() | CompWindowStateHiddenMask);
00176 
00177   /* Don't allow other windows to be focused by moveInputFocusToOtherWindow */
00178   for (auto mh : minimizedWindows)
00179     mh->priv->mWindow->focusSetEnabled (Window::get (mh->priv->mWindow), false);
00180 
00181   priv->mWindow->moveInputFocusToOtherWindow();
00182 
00183   for (auto mh : minimizedWindows)
00184     mh->priv->mWindow->focusSetEnabled (Window::get (mh->priv->mWindow), true);
00185 }
00186 
00187 template <typename Screen, typename Window>
00188 void
00189 compiz::CompizMinimizedWindowHandler<Screen, Window>::windowNotify (CompWindowNotify n)
00190 {
00191   if (n == CompWindowNotifyFocusChange && priv->mWindow->minimized())
00192   {
00193     for (auto mh : minimizedWindows)
00194       mh->priv->mWindow->focusSetEnabled (Window::get (mh->priv->mWindow), false);
00195 
00196     priv->mWindow->moveInputFocusToOtherWindow();
00197 
00198     for (auto mh : minimizedWindows)
00199       mh->priv->mWindow->focusSetEnabled (Window::get (mh->priv->mWindow), true);
00200   }
00201 }
00202 
00203 template <typename Screen, typename Window>
00204 void
00205 compiz::CompizMinimizedWindowHandler<Screen, Window>::updateFrameRegion (CompRegion &r)
00206 {
00207   unsigned int oldUpdateFrameRegionIndex;
00208   r = CompRegion();
00209 
00210   /* Ensure no other plugins can touch this frame region */
00211   oldUpdateFrameRegionIndex = priv->mWindow->updateFrameRegionGetCurrentIndex();
00212   priv->mWindow->updateFrameRegionSetCurrentIndex (MAXSHORT);
00213   priv->mWindow->updateFrameRegion (r);
00214   priv->mWindow->updateFrameRegionSetCurrentIndex (oldUpdateFrameRegionIndex);
00215 }
00216 
00217 template <typename Screen, typename Window>
00218 void
00219 compiz::CompizMinimizedWindowHandler<Screen, Window>::unminimize()
00220 {
00221   Atom          wmState = XInternAtom (screen->dpy(), "WM_STATE", 0);
00222   unsigned long data[2];
00223 
00224   std::vector<unsigned int> transients = getTransients();
00225 
00226   minimizedWindows.remove (this);
00227 
00228   priv->mWindow->focusSetEnabled (Window::get (priv->mWindow), true);
00229 
00230   priv->mWindow->windowNotify (CompWindowNotifyUnminimize);
00231   priv->mWindow->changeState (priv->mWindow->state() & ~CompWindowStateHiddenMask);
00232   priv->mWindow->windowNotify (CompWindowNotifyShow);
00233 
00234   for (unsigned int &w : transients)
00235   {
00236     CompWindow *win = screen->findWindow (w);
00237 
00238     if (win)
00239     {
00240       Window *w = Window::get (win);
00241       if (w && w->mMinimizeHandler)
00242       {
00243        w->mMinimizeHandler->unminimize();
00244        w->mMinimizeHandler.reset();
00245       }
00246     }
00247   }
00248 
00249   setVisibility (true);
00250 
00251   priv->mWindow->changeState (priv->mWindow->state() & ~CompWindowStateHiddenMask);
00252 
00253   data[0] = NormalState;
00254   data[1] = None;
00255 
00256   XChangeProperty (screen->dpy(), priv->mWindow->id(), wmState, wmState,
00257                    32, PropModeReplace, (unsigned char *) data, 2);
00258 }
00259 
00260 template <typename Screen, typename Window>
00261 unsigned int
00262 compiz::CompizMinimizedWindowHandler<Screen, Window>::getPaintMask ()
00263 {
00264   bool doMask = true;
00265 
00266   for (CompWindow *w : minimizingWindows)
00267   {
00268     if (w->id() == priv->mWindow->id())
00269       doMask = false;
00270     break;
00271   }
00272 
00273   if (doMask)
00274     return PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
00275 
00276   return 0;
00277 }
00278 
00279 template <typename Screen, typename Window>
00280 void
00281 compiz::CompizMinimizedWindowHandler<Screen, Window>::handleCompizEvent (const char *pluginName,
00282                                                                          const char *eventName,
00283                                                                          CompOption::Vector &o)
00284 {
00285   if (!handleEvents)
00286     return;
00287 
00288   if (strncmp (pluginName, "animation", 9) == 0 &&
00289       strncmp (eventName, "window_animation", 16) == 0)
00290   {
00291     if (CompOption::getStringOptionNamed (o, "type", "") == "minimize")
00292     {
00293       CompWindow *w = screen->findWindow (CompOption::getIntOptionNamed (
00294                                             o, "window", 0));
00295       if (w)
00296       {
00297         if (CompOption::getBoolOptionNamed (o, "active", false))
00298           minimizingWindows.push_back (w);
00299         else
00300         {
00301           /* Ugly hack for LP#977189 */
00302          CompositeWindow::get (w)->release();
00303          GLWindow::get (w)->release();
00304           minimizingWindows.remove (w);
00305         }
00306       }
00307     }
00308   }
00309 
00310   if (!CompOption::getBoolOptionNamed (o, "active", false) &&
00311       minimizingWindows.empty())
00312   {
00313     handleEvents = false;
00314   }
00315 }
00316 
00317 template <typename Screen, typename Window>
00318 void
00319 compiz::CompizMinimizedWindowHandler<Screen, Window>::handleEvent (XEvent *event)
00320 {
00321   /* Ignore sent events from the InputRemover */
00322   if (screen->XShape() && event->type ==
00323       screen->shapeEvent() + ShapeNotify &&
00324       !event->xany.send_event)
00325   {
00326     CompWindow *w = screen->findWindow (((XShapeEvent *) event)->window);
00327 
00328     if (w)
00329     {
00330       Window *pw = Window::get (w);
00331       Type *compizMinimizeHandler = pw->mMinimizeHandler.get();
00332 
00333       /* Restore and re-save input shape and remove */
00334       if (compizMinimizeHandler)
00335       {
00336         compizMinimizeHandler->setVisibility (true);
00337         compizMinimizeHandler->setVisibility (false);
00338       }
00339     }
00340   }
00341 }
00342 
00343 template <typename Screen, typename Window>
00344 void
00345 compiz::CompizMinimizedWindowHandler<Screen, Window>::setFunctions (bool keepMinimized)
00346 {
00347   for (CompWindow *w : screen->windows())
00348   {
00349     bool m = w->minimized();
00350     bool enable = keepMinimized && w->mapNum() > 0;
00351 
00352     if (m)
00353       w->unminimize();
00354     w->minimizeSetEnabled (Window::get (w), enable);
00355     w->unminimizeSetEnabled (Window::get (w), enable);
00356     w->minimizedSetEnabled (Window::get (w), enable);
00357     if (m)
00358       Window::get (w)->window->minimize();
00359   }
00360 }
00361 
00362 #endif