Back to index

unity  6.0.0
unityshell.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /* Compiz unity plugin
00003  * unity.cpp
00004  *
00005  * Copyright (c) 2010-11 Canonical Ltd.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 3
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * Your own copyright notice would go above. You are free to choose whatever
00018  * licence you want, just take note that some compiz code is GPL and you will
00019  * not be able to re-use it if you want to use a different licence.
00020  */
00021 
00022 #include <NuxCore/Logger.h>
00023 #include <Nux/Nux.h>
00024 #include <Nux/HLayout.h>
00025 #include <Nux/BaseWindow.h>
00026 #include <Nux/WindowCompositor.h>
00027 
00028 #include "IconRenderer.h"
00029 #include "Launcher.h"
00030 #include "LauncherIcon.h"
00031 #include "LauncherController.h"
00032 #include "GeisAdapter.h"
00033 #include "DevicesSettings.h"
00034 #include "PluginAdapter.h"
00035 #include "QuicklistManager.h"
00036 #include "StartupNotifyService.h"
00037 #include "Timer.h"
00038 #include "KeyboardUtil.h"
00039 #include "unityshell.h"
00040 #include "BackgroundEffectHelper.h"
00041 
00042 #include <dbus/dbus.h>
00043 #include <dbus/dbus-glib.h>
00044 #include <glib/gi18n-lib.h>
00045 #include <gtk/gtk.h>
00046 #include <gdk/gdk.h>
00047 #include <gdk/gdkx.h>
00048 #include <libnotify/notify.h>
00049 
00050 #include <sstream>
00051 #include <memory>
00052 
00053 #include <core/atoms.h>
00054 
00055 #include "unitya11y.h"
00056 
00057 #include "UBusMessages.h"
00058 #include "UScreen.h"
00059 
00060 #include "config.h"
00061 
00062 /* FIXME: once we get a better method to add the toplevel windows to
00063    the accessible root object, this include would not be required */
00064 #include "unity-util-accessible.h"
00065 
00066 /* Set up vtable symbols */
00067 COMPIZ_PLUGIN_20090315(unityshell, unity::UnityPluginVTable);
00068 
00069 namespace unity
00070 {
00071 using namespace launcher;
00072 using launcher::AbstractLauncherIcon;
00073 using launcher::Launcher;
00074 using ui::KeyboardUtil;
00075 using ui::LayoutWindow;
00076 using ui::LayoutWindowList;
00077 using util::Timer;
00078 
00079 namespace
00080 {
00081 
00082 nux::logging::Logger logger("unity.shell");
00083 
00084 UnityScreen* uScreen = 0;
00085 
00086 void reset_glib_logging();
00087 void configure_logging();
00088 void capture_g_log_calls(const gchar* log_domain,
00089                          GLogLevelFlags log_level,
00090                          const gchar* message,
00091                          gpointer user_data);
00092 gboolean is_extension_supported(const gchar* extensions, const gchar* extension);
00093 gfloat get_opengl_version_f32(const gchar* version_string);
00094 
00095 namespace local
00096 {
00097 // Tap duration in milliseconds.
00098 const int ALT_TAP_DURATION = 250;
00099 const unsigned int SCROLL_DOWN_BUTTON = 6;
00100 const unsigned int SCROLL_UP_BUTTON = 7;
00101 
00102 const std::string RELAYOUT_TIMEOUT = "relayout-timeout";
00103 } // namespace local
00104 } // anon namespace
00105 
00106 UnityScreen::UnityScreen(CompScreen* screen)
00107   : BaseSwitchScreen (screen)
00108   , PluginClassHandler <UnityScreen, CompScreen> (screen)
00109   , screen(screen)
00110   , cScreen(CompositeScreen::get(screen))
00111   , gScreen(GLScreen::get(screen))
00112   , debugger_(this)
00113   , enable_shortcut_overlay_(true)
00114   , gesture_engine_(screen)
00115   , needsRelayout(false)
00116   , _in_paint(false)
00117   , super_keypressed_(false)
00118   , newFocusedWindow(nullptr)
00119   , doShellRepaint(false)
00120   , didShellRepaint(false)
00121   , allowWindowPaint(false)
00122   , _key_nav_mode_requested(false)
00123   , _last_output(nullptr)
00124 #ifndef USE_MODERN_COMPIZ_GL
00125   , _active_fbo (0)
00126 #endif
00127   , grab_index_ (0)
00128   , painting_tray_ (false)
00129   , last_scroll_event_(0)
00130   , hud_keypress_time_(0)
00131   , panel_texture_has_changed_(true)
00132   , paint_panel_(false)
00133   , scale_just_activated_(false)
00134 {
00135   Timer timer;
00136   gfloat version;
00137   gchar* extensions;
00138   bool  failed = false;
00139   configure_logging();
00140   LOG_DEBUG(logger) << __PRETTY_FUNCTION__;
00141   int (*old_handler)(Display*, XErrorEvent*);
00142   old_handler = XSetErrorHandler(NULL);
00143 
00144 #ifndef USE_GLES
00145   /* Ensure OpenGL version is 1.4+. */
00146   version = get_opengl_version_f32((const gchar*) glGetString(GL_VERSION));
00147   if (version < 1.4f)
00148   {
00149     compLogMessage("unityshell", CompLogLevelError,
00150                    "OpenGL 1.4+ not supported\n");
00151     setFailed ();
00152     failed = true;
00153   }
00154 
00155   /* Ensure OpenGL extensions required by the Unity plugin are available. */
00156   extensions = (gchar*) glGetString(GL_EXTENSIONS);
00157   if (!is_extension_supported(extensions, "GL_ARB_vertex_program"))
00158   {
00159     compLogMessage("unityshell", CompLogLevelError,
00160                    "GL_ARB_vertex_program not supported\n");
00161     setFailed ();
00162     failed = true;
00163   }
00164   if (!is_extension_supported(extensions, "GL_ARB_fragment_program"))
00165   {
00166     compLogMessage("unityshell", CompLogLevelError,
00167                    "GL_ARB_fragment_program not supported\n");
00168     setFailed ();
00169     failed = true;
00170   }
00171   if (!is_extension_supported(extensions, "GL_ARB_vertex_buffer_object"))
00172   {
00173     compLogMessage("unityshell", CompLogLevelError,
00174                    "GL_ARB_vertex_buffer_object not supported\n");
00175     setFailed ();
00176     failed = true;
00177   }
00178   if (!is_extension_supported(extensions, "GL_ARB_framebuffer_object"))
00179   {
00180     if (!is_extension_supported(extensions, "GL_EXT_framebuffer_object"))
00181     {
00182       compLogMessage("unityshell", CompLogLevelError,
00183                      "GL_ARB_framebuffer_object or GL_EXT_framebuffer_object "
00184                      "not supported\n");
00185       setFailed();
00186       failed = true;
00187     }
00188   }
00189   if (!is_extension_supported(extensions, "GL_ARB_texture_non_power_of_two"))
00190   {
00191     if (!is_extension_supported(extensions, "GL_ARB_texture_rectangle"))
00192     {
00193       compLogMessage("unityshell", CompLogLevelError,
00194                      "GL_ARB_texture_non_power_of_two or "
00195                      "GL_ARB_texture_rectangle not supported\n");
00196       setFailed ();
00197       failed = true;
00198     }
00199   }
00200 #endif
00201 
00202   if (!failed)
00203   {
00204      notify_init("unityshell");
00205 
00206      dbus_g_thread_init();
00207 
00208      unity_a11y_preset_environment();
00209 
00210      XSetErrorHandler(old_handler);
00211 
00212      /* Wrap compiz interfaces */
00213      ScreenInterface::setHandler(screen);
00214      CompositeScreenInterface::setHandler(cScreen);
00215      GLScreenInterface::setHandler(gScreen);
00216 
00217 #ifdef USE_MODERN_COMPIZ_GL
00218      gScreen->glPaintCompositedOutputSetEnabled (this, true);
00219 #endif
00220 
00221      PluginAdapter::Initialize(screen);
00222      WindowManager::SetDefault(PluginAdapter::Default());
00223      AddChild(PluginAdapter::Default());
00224 
00225      StartupNotifyService::Default()->SetSnDisplay(screen->snDisplay(), screen->screenNum());
00226 
00227      nux::NuxInitialize(0);
00228 #ifndef USE_GLES
00229      wt.reset(nux::CreateFromForeignWindow(cScreen->output(),
00230                                            glXGetCurrentContext(),
00231                                            &UnityScreen::initUnity,
00232                                            this));
00233 #else
00234      wt.reset(nux::CreateFromForeignWindow(cScreen->output(),
00235                                            eglGetCurrentContext(),
00236                                            &UnityScreen::initUnity,
00237                                            this));
00238 #endif
00239 
00240      wt->RedrawRequested.connect(sigc::mem_fun(this, &UnityScreen::onRedrawRequested));
00241 
00242      unity_a11y_init(wt.get());
00243 
00244      /* i18n init */
00245      bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
00246      bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
00247 
00248      wt->Run(NULL);
00249      uScreen = this;
00250      _in_paint = false;
00251 
00252 #ifndef USE_MODERN_COMPIZ_GL
00253     void *dlhand = dlopen ("libunityshell.so", RTLD_LAZY);
00254 
00255     if (dlhand)
00256     {
00257       dlerror ();
00258       glXGetProcAddressP = (ScreenEffectFramebufferObject::GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddress");
00259       if (dlerror () != NULL)
00260         glXGetProcAddressP = NULL;
00261     }
00262 
00263      if (GL::fbo)
00264      {
00265        nux::Geometry geometry (0, 0, screen->width (), screen->height ());
00266        uScreen->_fbo = ScreenEffectFramebufferObject::Ptr (new ScreenEffectFramebufferObject (glXGetProcAddressP, geometry));
00267        uScreen->_fbo->onScreenSizeChanged (geometry);
00268      }
00269 #endif
00270 
00271      optionSetShowHudInitiate(boost::bind(&UnityScreen::ShowHudInitiate, this, _1, _2, _3));
00272      optionSetShowHudTerminate(boost::bind(&UnityScreen::ShowHudTerminate, this, _1, _2, _3));
00273      optionSetBackgroundColorNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00274      optionSetLauncherHideModeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00275      optionSetBacklightModeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00276      optionSetRevealTriggerNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00277      optionSetLaunchAnimationNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00278      optionSetUrgentAnimationNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00279      optionSetPanelOpacityNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00280      optionSetPanelOpacityMaximizedToggleNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00281      optionSetMenusFadeinNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00282      optionSetMenusFadeoutNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00283      optionSetMenusDiscoveryDurationNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00284      optionSetMenusDiscoveryFadeinNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00285      optionSetMenusDiscoveryFadeoutNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00286      optionSetLauncherOpacityNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00287      optionSetIconSizeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00288      optionSetAutohideAnimationNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00289      optionSetDashBlurExperimentalNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00290      optionSetDevicesOptionNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00291      optionSetShortcutOverlayNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00292      optionSetShowDesktopIconNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00293      optionSetShowLauncherInitiate(boost::bind(&UnityScreen::showLauncherKeyInitiate, this, _1, _2, _3));
00294      optionSetShowLauncherTerminate(boost::bind(&UnityScreen::showLauncherKeyTerminate, this, _1, _2, _3));
00295      optionSetKeyboardFocusInitiate(boost::bind(&UnityScreen::setKeyboardFocusKeyInitiate, this, _1, _2, _3));
00296      //optionSetKeyboardFocusTerminate (boost::bind (&UnityScreen::setKeyboardFocusKeyTerminate, this, _1, _2, _3));
00297      optionSetExecuteCommandInitiate(boost::bind(&UnityScreen::executeCommand, this, _1, _2, _3));
00298      optionSetPanelFirstMenuInitiate(boost::bind(&UnityScreen::showPanelFirstMenuKeyInitiate, this, _1, _2, _3));
00299      optionSetPanelFirstMenuTerminate(boost::bind(&UnityScreen::showPanelFirstMenuKeyTerminate, this, _1, _2, _3));
00300      optionSetAutomaximizeValueNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00301      optionSetAltTabTimeoutNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00302      optionSetAltTabBiasViewportNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00303 
00304      optionSetAltTabForwardAllInitiate(boost::bind(&UnityScreen::altTabForwardAllInitiate, this, _1, _2, _3));
00305      optionSetAltTabForwardInitiate(boost::bind(&UnityScreen::altTabForwardInitiate, this, _1, _2, _3));
00306      optionSetAltTabForwardTerminate(boost::bind(&UnityScreen::altTabTerminateCommon, this, _1, _2, _3));
00307      optionSetAltTabForwardAllTerminate(boost::bind(&UnityScreen::altTabTerminateCommon, this, _1, _2, _3));
00308      optionSetAltTabPrevAllInitiate(boost::bind(&UnityScreen::altTabPrevAllInitiate, this, _1, _2, _3));
00309      optionSetAltTabPrevInitiate(boost::bind(&UnityScreen::altTabPrevInitiate, this, _1, _2, _3));
00310 
00311      optionSetAltTabDetailStartInitiate(boost::bind(&UnityScreen::altTabDetailStartInitiate, this, _1, _2, _3));
00312      optionSetAltTabDetailStopInitiate(boost::bind(&UnityScreen::altTabDetailStopInitiate, this, _1, _2, _3));
00313 
00314      optionSetAltTabNextWindowInitiate(boost::bind(&UnityScreen::altTabNextWindowInitiate, this, _1, _2, _3));
00315      optionSetAltTabNextWindowTerminate(boost::bind(&UnityScreen::altTabTerminateCommon, this, _1, _2, _3));
00316 
00317      optionSetAltTabPrevWindowInitiate(boost::bind(&UnityScreen::altTabPrevWindowInitiate, this, _1, _2, _3));
00318 
00319      optionSetAltTabLeftInitiate(boost::bind (&UnityScreen::altTabPrevInitiate, this, _1, _2, _3));
00320      optionSetAltTabRightInitiate([&](CompAction* action, CompAction::State state, CompOption::Vector& options) -> bool
00321      {
00322       if (switcher_controller_->Visible())
00323       {
00324         switcher_controller_->Next();
00325         return true;
00326       }
00327       return false;
00328      });
00329 
00330      optionSetLauncherSwitcherForwardInitiate(boost::bind(&UnityScreen::launcherSwitcherForwardInitiate, this, _1, _2, _3));
00331      optionSetLauncherSwitcherPrevInitiate(boost::bind(&UnityScreen::launcherSwitcherPrevInitiate, this, _1, _2, _3));
00332      optionSetLauncherSwitcherForwardTerminate(boost::bind(&UnityScreen::launcherSwitcherTerminate, this, _1, _2, _3));
00333 
00334      optionSetStopVelocityNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00335      optionSetRevealPressureNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00336      optionSetEdgeResponsivenessNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00337      optionSetOvercomePressureNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00338      optionSetDecayRateNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00339      optionSetShowMinimizedWindowsNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00340 
00341      optionSetNumLaunchersNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00342      optionSetLauncherCaptureMouseNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
00343 
00344      ubus_manager_.RegisterInterest(UBUS_LAUNCHER_START_KEY_NAV,
00345                    sigc::mem_fun(this, &UnityScreen::OnLauncherStartKeyNav));
00346 
00347      ubus_manager_.RegisterInterest(UBUS_LAUNCHER_START_KEY_SWTICHER,
00348                    sigc::mem_fun(this, &UnityScreen::OnLauncherStartKeyNav));
00349 
00350      ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_NAV,
00351                    sigc::mem_fun(this, &UnityScreen::OnLauncherEndKeyNav));
00352 
00353      ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_SWTICHER,
00354                    sigc::mem_fun(this, &UnityScreen::OnLauncherEndKeyNav));
00355 
00356      ubus_manager_.RegisterInterest(UBUS_SWITCHER_START,
00357                    sigc::mem_fun(this, &UnityScreen::OnSwitcherStart));
00358 
00359      ubus_manager_.RegisterInterest(UBUS_SWITCHER_END,
00360                    sigc::mem_fun(this, &UnityScreen::OnSwitcherEnd));
00361 
00362      auto init_plugins_cb = sigc::mem_fun(this, &UnityScreen::initPluginActions);
00363      sources_.Add(std::make_shared<glib::Idle>(init_plugins_cb, glib::Source::Priority::DEFAULT));
00364 
00365      geis_adapter_.Run();
00366 
00367      CompString name(PKGDATADIR"/panel-shadow.png");
00368      CompString pname("unityshell");
00369      CompSize size(1, 20);
00370      _shadow_texture = GLTexture::readImageToTexture(name, pname, size);
00371 
00372      BackgroundEffectHelper::updates_enabled = true;
00373 
00374      ubus_manager_.RegisterInterest(UBUS_OVERLAY_SHOWN, [&](GVariant * data)
00375      {
00376        unity::glib::String overlay_identity;
00377        gboolean can_maximise = FALSE;
00378        gint32 overlay_monitor = 0;
00379        g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING,
00380                     &overlay_identity, &can_maximise, &overlay_monitor);
00381 
00382        dash_monitor_ = overlay_monitor;
00383 
00384        RaiseInputWindows();
00385      });
00386 
00387     Display* display = gdk_x11_display_get_xdisplay(gdk_display_get_default());;
00388     XSelectInput(display, GDK_ROOT_WINDOW(), PropertyChangeMask);
00389     LOG_INFO(logger) << "UnityScreen constructed: " << timer.ElapsedSeconds() << "s";
00390   }
00391 
00392   panel::Style::Instance().changed.connect(sigc::mem_fun(this, &UnityScreen::OnPanelStyleChanged));
00393 }
00394 
00395 UnityScreen::~UnityScreen()
00396 {
00397   notify_uninit();
00398 
00399   unity_a11y_finalize();
00400   ::unity::ui::IconRenderer::DestroyTextures();
00401   QuicklistManager::Destroy();
00402 
00403   reset_glib_logging();
00404 }
00405 
00406 void UnityScreen::initAltTabNextWindow()
00407 {
00408   KeyboardUtil key_util(screen->dpy());
00409   guint above_tab_keycode = key_util.GetKeycodeAboveKeySymbol (XStringToKeysym("Tab"));
00410   KeySym above_tab_keysym = XkbKeycodeToKeysym (screen->dpy(), above_tab_keycode, 0, 0);
00411 
00412   if (above_tab_keysym != NoSymbol)
00413   {
00414     {
00415       std::ostringstream sout;
00416       sout << "<Alt>" << XKeysymToString(above_tab_keysym);
00417 
00418       screen->removeAction(&optionGetAltTabNextWindow());
00419 
00420       CompAction action = CompAction();
00421       action.keyFromString(sout.str());
00422       action.setState (CompAction::StateInitKey | CompAction::StateAutoGrab);
00423       mOptions[UnityshellOptions::AltTabNextWindow].value().set (action);
00424       screen->addAction (&mOptions[UnityshellOptions::AltTabNextWindow].value ().action ());
00425 
00426       optionSetAltTabNextWindowInitiate(boost::bind(&UnityScreen::altTabNextWindowInitiate, this, _1, _2, _3));
00427       optionSetAltTabNextWindowTerminate(boost::bind(&UnityScreen::altTabTerminateCommon, this, _1, _2, _3));
00428     }
00429     {
00430       std::ostringstream sout;
00431       sout << "<Alt><Shift>" << XKeysymToString(above_tab_keysym);
00432 
00433       screen->removeAction(&optionGetAltTabPrevWindow());
00434 
00435       CompAction action = CompAction();
00436       action.keyFromString(sout.str());
00437       action.setState (CompAction::StateInitKey | CompAction::StateAutoGrab);
00438       mOptions[UnityshellOptions::AltTabPrevWindow].value().set (action);
00439       screen->addAction (&mOptions[UnityshellOptions::AltTabPrevWindow].value ().action ());
00440 
00441       optionSetAltTabPrevWindowInitiate(boost::bind(&UnityScreen::altTabPrevWindowInitiate, this, _1, _2, _3));
00442     }
00443   }
00444   else
00445   {
00446     printf ("Could not find key above tab!\n");
00447   }
00448 
00449 }
00450 
00451 void UnityScreen::EnsureSuperKeybindings()
00452 {
00453   for (auto action : _shortcut_actions)
00454     screen->removeAction(action.get());
00455 
00456   _shortcut_actions.clear ();
00457 
00458   for (auto shortcut : launcher_controller_->GetAllShortcuts())
00459   {
00460     CreateSuperNewAction(shortcut, impl::ActionModifiers::NONE);
00461     CreateSuperNewAction(shortcut, impl::ActionModifiers::USE_NUMPAD);
00462     CreateSuperNewAction(shortcut, impl::ActionModifiers::USE_SHIFT);
00463   }
00464 
00465   for (auto shortcut : dash_controller_->GetAllShortcuts())
00466     CreateSuperNewAction(shortcut, impl::ActionModifiers::NONE);
00467 }
00468 
00469 void UnityScreen::CreateSuperNewAction(char shortcut, impl::ActionModifiers flag)
00470 {
00471     CompActionPtr action(new CompAction());
00472     const std::string key(optionGetShowLauncher().keyToString());
00473 
00474     CompAction::KeyBinding binding;
00475     binding.fromString(impl::CreateActionString(key, shortcut, flag));
00476 
00477     action->setKey(binding);
00478 
00479     screen->addAction(action.get());
00480     _shortcut_actions.push_back(action);
00481 }
00482 
00483 void UnityScreen::nuxPrologue()
00484 {
00485 #ifndef USE_MODERN_COMPIZ_GL
00486   /* Vertex lighting isn't used in Unity, we disable that state as it could have
00487    * been leaked by another plugin. That should theoretically be switched off
00488    * right after PushAttrib since ENABLE_BIT is meant to restore the LIGHTING
00489    * bit, but we do that here in order to workaround a bug (?) in the NVIDIA
00490    * drivers (lp:703140). */
00491   glDisable(GL_LIGHTING);
00492 
00493   /* reset matrices */
00494   glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT |
00495                GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT | GL_SCISSOR_BIT);
00496 
00497   glMatrixMode(GL_PROJECTION);
00498   glPushMatrix();
00499 
00500   glMatrixMode(GL_MODELVIEW);
00501   glPushMatrix();
00502 #endif
00503 
00504   glGetError();
00505 }
00506 
00507 void UnityScreen::nuxEpilogue()
00508 {
00509 #ifndef USE_MODERN_COMPIZ_GL
00510   (*GL::bindFramebuffer)(GL_FRAMEBUFFER_EXT, _active_fbo);
00511 
00512   glMatrixMode(GL_PROJECTION);
00513   glLoadIdentity();
00514   glMatrixMode(GL_MODELVIEW);
00515   glLoadIdentity();
00516   glDepthRange(0, 1);
00517   glViewport(-1, -1, 2, 2);
00518   glRasterPos2f(0, 0);
00519 
00520   gScreen->resetRasterPos();
00521 
00522   glMatrixMode(GL_PROJECTION);
00523   glPopMatrix();
00524   glMatrixMode(GL_MODELVIEW);
00525   glPopMatrix();
00526 
00527   glDrawBuffer(GL_BACK);
00528   glReadBuffer(GL_BACK);
00529 
00530   glPopAttrib();
00531 #else
00532 #ifdef USE_GLES
00533   glDepthRangef(0, 1);
00534 #else
00535   glDepthRange(0, 1);
00536 #endif
00537   //glViewport(-1, -1, 2, 2);
00538   gScreen->resetRasterPos();
00539 #endif
00540 
00541   glDisable(GL_SCISSOR_TEST);
00542 }
00543 
00544 void UnityScreen::setPanelShadowMatrix(const GLMatrix& matrix)
00545 {
00546   panel_shadow_matrix_ = matrix;
00547 }
00548 
00549 void UnityScreen::paintPanelShadow(const GLMatrix& matrix)
00550 {
00551 #ifndef USE_MODERN_COMPIZ_GL
00552   if (sources_.GetSource(local::RELAYOUT_TIMEOUT))
00553     return;
00554 
00555   if (PluginAdapter::Default()->IsExpoActive())
00556     return;
00557 
00558   CompOutput* output = _last_output;
00559   float vc[4];
00560   float h = 20.0f;
00561   float w = 1.0f;
00562   float panel_h = panel_style_.panel_height;
00563 
00564   float x1 = output->x();
00565   float y1 = output->y() + panel_h;
00566   float x2 = x1 + output->width();
00567   float y2 = y1 + h;
00568 
00569   glPushMatrix ();
00570   glLoadMatrixf (panel_shadow_matrix_.getMatrix ());
00571 
00572   vc[0] = x1;
00573   vc[1] = x2;
00574   vc[2] = y1;
00575   vc[3] = y2;
00576 
00577   // compiz doesn't use the same method of tracking monitors as our toolkit
00578   // we need to make sure we properly associate with the right monitor
00579   int current_monitor = -1;
00580   auto monitors = UScreen::GetDefault()->GetMonitors();
00581   int i = 0;
00582   for (auto monitor : monitors)
00583   {
00584     if (monitor.x == output->x() && monitor.y == output->y())
00585     {
00586       current_monitor = i;
00587       break;
00588     }
00589     i++;
00590   }
00591 
00592   if (!(launcher_controller_->IsOverlayOpen() && current_monitor == dash_monitor_)
00593       && panel_controller_->opacity() > 0.0f)
00594   {
00595     foreach(GLTexture * tex, _shadow_texture)
00596     {
00597       glEnable(GL_BLEND);
00598       glColor4f(1.0f, 1.0f, 1.0f, panel_controller_->opacity());
00599       glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00600 
00601       GL::activeTexture(GL_TEXTURE0_ARB);
00602       tex->enable(GLTexture::Fast);
00603 
00604       glTexParameteri(tex->target(), GL_TEXTURE_WRAP_S, GL_REPEAT);
00605 
00606       glBegin(GL_QUADS);
00607       {
00608         glTexCoord2f(COMP_TEX_COORD_X(tex->matrix(), 0), COMP_TEX_COORD_Y(tex->matrix(), 0));
00609         glVertex2f(vc[0], vc[2]);
00610 
00611         glTexCoord2f(COMP_TEX_COORD_X(tex->matrix(), 0), COMP_TEX_COORD_Y(tex->matrix(), h));
00612         glVertex2f(vc[0], vc[3]);
00613 
00614         glTexCoord2f(COMP_TEX_COORD_X(tex->matrix(), w), COMP_TEX_COORD_Y(tex->matrix(), h));
00615         glVertex2f(vc[1], vc[3]);
00616 
00617         glTexCoord2f(COMP_TEX_COORD_X(tex->matrix(), w), COMP_TEX_COORD_Y(tex->matrix(), 0));
00618         glVertex2f(vc[1], vc[2]);
00619       }
00620       glEnd();
00621 
00622       tex->disable();
00623       glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00624       glDisable(GL_BLEND);
00625     }
00626   }
00627   glPopMatrix();
00628 #else
00629   return;
00630 
00631   if (sources_.GetSource(local::RELAYOUT_TIMEOUT))
00632     return;
00633 
00634   if (PluginAdapter::Default()->IsExpoActive())
00635     return;
00636 
00637   nuxPrologue();
00638 
00639   CompOutput* output = _last_output;
00640   float vc[4];
00641   float h = 20.0f;
00642   float w = 1.0f;
00643   float panel_h = static_cast<float>(panel_style_.panel_height);
00644 
00645   float x1 = output->x();
00646   float y1 = output->y() + panel_h;
00647   float x2 = x1 + output->width();
00648   float y2 = y1 + h;
00649 
00650   vc[0] = x1;
00651   vc[1] = x2;
00652   vc[2] = y1;
00653   vc[3] = y2;
00654 
00655   // compiz doesn't use the same method of tracking monitors as our toolkit
00656   // we need to make sure we properly associate with the right monitor
00657   int current_monitor = -1;
00658   auto monitors = UScreen::GetDefault()->GetMonitors();
00659   int i = 0;
00660   for (auto monitor : monitors)
00661   {
00662     if (monitor.x == output->x() && monitor.y == output->y())
00663     {
00664       current_monitor = i;
00665       break;
00666     }
00667     i++;
00668   }
00669 
00670   if (!(launcher_controller_->IsOverlayOpen() && current_monitor == dash_monitor_)
00671       && panel_controller_->opacity() > 0.0f)
00672   {
00673     foreach(GLTexture * tex, _shadow_texture)
00674     {
00675       std::vector<GLfloat>  vertexData;
00676       std::vector<GLfloat>  textureData;
00677       std::vector<GLushort> colorData;
00678       GLVertexBuffer       *streamingBuffer = GLVertexBuffer::streamingBuffer();
00679       bool                  wasBlend = glIsEnabled(GL_BLEND);
00680 
00681       if (!wasBlend)
00682         glEnable(GL_BLEND);
00683 
00684       GL::activeTexture(GL_TEXTURE0);
00685       tex->enable(GLTexture::Fast);
00686 
00687       glTexParameteri(tex->target(), GL_TEXTURE_WRAP_S, GL_REPEAT);
00688 
00689       colorData = { 0xFFFF, 0xFFFF, 0xFFFF,
00690                     (GLushort)(panel_controller_->opacity() * 0xFFFF)
00691                   };
00692 
00693       vertexData = {
00694         vc[0], vc[2], 0,
00695         vc[0], vc[3], 0,
00696         vc[1], vc[2], 0,
00697         vc[1], vc[3], 0,
00698       };
00699 
00700       textureData = {
00701         COMP_TEX_COORD_X(tex->matrix(), 0), COMP_TEX_COORD_Y(tex->matrix(), 0),
00702         COMP_TEX_COORD_X(tex->matrix(), 0), COMP_TEX_COORD_Y(tex->matrix(), h),
00703         COMP_TEX_COORD_X(tex->matrix(), w), COMP_TEX_COORD_Y(tex->matrix(), 0),
00704         COMP_TEX_COORD_X(tex->matrix(), w), COMP_TEX_COORD_Y(tex->matrix(), h),
00705       };
00706 
00707       streamingBuffer->begin(GL_TRIANGLE_STRIP);
00708 
00709       streamingBuffer->addColors(1, &colorData[0]);
00710       streamingBuffer->addVertices(4, &vertexData[0]);
00711       streamingBuffer->addTexCoords(0, 4, &textureData[0]);
00712 
00713       streamingBuffer->end();
00714       streamingBuffer->render(matrix);
00715 
00716       tex->disable();
00717       if (!wasBlend)
00718         glDisable(GL_BLEND);
00719     }
00720   }
00721   nuxEpilogue();
00722 #endif
00723 }
00724 
00725 void
00726 UnityWindow::updateIconPos (int   &wx,
00727                             int   &wy,
00728                             int   x,
00729                             int   y,
00730                             float width,
00731                             float height)
00732 {
00733   wx = x + (last_bound.width - width) / 2;
00734   wy = y + (last_bound.height - height) / 2;
00735 }
00736 
00737 void
00738 UnityScreen::OnPanelStyleChanged()
00739 {
00740   panel_texture_has_changed_ = true;
00741 }
00742 
00743 #ifdef USE_MODERN_COMPIZ_GL
00744 void UnityScreen::paintDisplay()
00745 #else
00746 void UnityScreen::paintDisplay(const CompRegion& region, const GLMatrix& transform, unsigned int mask)
00747 #endif
00748 {
00749   CompOutput *output = _last_output;
00750 
00751 #ifndef USE_MODERN_COMPIZ_GL
00752   bool was_bound = _fbo->bound ();
00753 
00754   if (nux::GetGraphicsDisplay()->GetGraphicsEngine()->UsingGLSLCodePath())
00755   {
00756     if (was_bound && launcher_controller_->IsOverlayOpen() && paint_panel_)
00757     {
00758       if (panel_texture_has_changed_ || !panel_texture_.IsValid())
00759       {
00760         panel_texture_.Release();
00761 
00762         nux::NBitmapData* bitmap = panel::Style::Instance().GetBackground(screen->width (), screen->height(), 1.0f);
00763         nux::BaseTexture* texture2D = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture();
00764         if (bitmap && texture2D)
00765         {
00766           texture2D->Update(bitmap);
00767           panel_texture_ = texture2D->GetDeviceTexture();
00768           texture2D->UnReference();
00769           delete bitmap;
00770         }
00771         panel_texture_has_changed_ = false;
00772       }
00773 
00774       if (panel_texture_.IsValid())
00775       {
00776         nux::GetGraphicsDisplay()->GetGraphicsEngine()->ResetModelViewMatrixStack();
00777         nux::GetGraphicsDisplay()->GetGraphicsEngine()->Push2DTranslationModelViewMatrix(0.0f, 0.0f, 0.0f);
00778         nux::GetGraphicsDisplay()->GetGraphicsEngine()->ResetProjectionMatrix();
00779         nux::GetGraphicsDisplay()->GetGraphicsEngine()->SetOrthographicProjectionMatrix(screen->width (), screen->height());
00780 
00781         nux::TexCoordXForm texxform;
00782         int panel_height = panel_style_.panel_height;
00783         nux::GetGraphicsDisplay()->GetGraphicsEngine()->QRP_GLSL_1Tex(0, 0, screen->width (), panel_height, panel_texture_, texxform, nux::color::White);
00784       }
00785     }
00786   }
00787 
00788   _fbo->unbind ();
00789 
00790   /* Draw the bit of the relevant framebuffer for each output */
00791 
00792   if (was_bound)
00793   {
00794     GLMatrix sTransform;
00795     sTransform.toScreenSpace (&screen->fullscreenOutput (), -DEFAULT_Z_CAMERA);
00796     glPushMatrix ();
00797     glLoadMatrixf (sTransform.getMatrix ());
00798     _fbo->paint (nux::Geometry (output->x (), output->y (), output->width (), output->height ()));
00799     glPopMatrix ();
00800   }
00801 
00802   nux::ObjectPtr<nux::IOpenGLBaseTexture> device_texture =
00803       nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture2DFromID(_fbo->texture(),
00804                                                                        screen->width (), screen->height(), 1, nux::BITFMT_R8G8B8A8);
00805 #else
00806   nux::ObjectPtr<nux::IOpenGLTexture2D> device_texture =
00807     nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture2DFromID(gScreen->fbo ()->tex ()->name (),
00808       output->width(), output->height(), 1, nux::BITFMT_R8G8B8A8);
00809 #endif
00810 
00811   nux::GetGraphicsDisplay()->GetGpuDevice()->backup_texture0_ = device_texture;
00812 
00813   nux::Geometry geo = nux::Geometry (0, 0, screen->width (), screen->height ());
00814   nux::Geometry oGeo = nux::Geometry (output->x (), output->y (), output->width (), output->height ());
00815   BackgroundEffectHelper::monitor_rect_ = geo;
00816 
00817 #ifdef USE_MODERN_COMPIZ_GL
00818   GLint fboID;
00819   // Nux renders to the referenceFramebuffer when it's embedded.
00820   glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fboID);
00821   wt->GetWindowCompositor().SetReferenceFramebuffer(fboID, geo);
00822 #endif
00823 
00824   nuxPrologue();
00825   _in_paint = true;
00826   wt->RenderInterfaceFromForeignCmd (&oGeo);
00827   _in_paint = false;
00828   nuxEpilogue();
00829 
00830   for (Window tray_xid : panel_controller_->GetTrayXids())
00831   {
00832     if (tray_xid && !allowWindowPaint)
00833     {
00834       CompWindow *tray = screen->findWindow (tray_xid);
00835 
00836       if (tray)
00837       {
00838         GLMatrix oTransform;
00839         UnityWindow  *uTrayWindow = UnityWindow::get (tray);
00840 #ifndef USE_MODERN_COMPIZ_GL
00841         GLFragment::Attrib attrib (uTrayWindow->gWindow->lastPaintAttrib());
00842 #else
00843         GLWindowPaintAttrib attrib (uTrayWindow->gWindow->lastPaintAttrib());
00844 #endif
00845         unsigned int oldGlAddGeometryIndex = uTrayWindow->gWindow->glAddGeometryGetCurrentIndex ();
00846         unsigned int oldGlDrawIndex = uTrayWindow->gWindow->glDrawGetCurrentIndex ();
00847 #ifndef USE_MODERN_COMPIZ_GL
00848         unsigned int oldGlDrawGeometryIndex = uTrayWindow->gWindow->glDrawGeometryGetCurrentIndex ();
00849 #endif
00850 
00851 #ifndef USE_MODERN_COMPIZ_GL
00852         attrib.setOpacity (OPAQUE);
00853         attrib.setBrightness (BRIGHT);
00854         attrib.setSaturation (COLOR);
00855 #else
00856         attrib.opacity = OPAQUE;
00857         attrib.brightness = BRIGHT;
00858         attrib.saturation = COLOR;
00859 #endif
00860 
00861         oTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
00862 
00863 #ifndef USE_MODERN_COMPIZ_GL
00864         glPushMatrix ();
00865         glLoadMatrixf (oTransform.getMatrix ());
00866 #endif
00867 
00868         painting_tray_ = true;
00869 
00870         /* force the use of the core functions */
00871         uTrayWindow->gWindow->glDrawSetCurrentIndex (MAXSHORT);
00872         uTrayWindow->gWindow->glAddGeometrySetCurrentIndex ( MAXSHORT);
00873 #ifndef USE_MODERN_COMPIZ_GL
00874         uTrayWindow->gWindow->glDrawGeometrySetCurrentIndex (MAXSHORT);
00875 #endif
00876         uTrayWindow->gWindow->glDraw (oTransform, attrib, infiniteRegion,
00877                PAINT_WINDOW_TRANSFORMED_MASK |
00878                PAINT_WINDOW_BLEND_MASK |
00879                PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);
00880 #ifndef USE_MODERN_COMPIZ_GL
00881         uTrayWindow->gWindow->glDrawGeometrySetCurrentIndex (oldGlDrawGeometryIndex);
00882 #endif
00883         uTrayWindow->gWindow->glAddGeometrySetCurrentIndex (oldGlAddGeometryIndex);
00884         uTrayWindow->gWindow->glDrawSetCurrentIndex (oldGlDrawIndex);
00885         painting_tray_ = false;
00886 
00887 #ifndef USE_MODERN_COMPIZ_GL
00888         glPopMatrix ();
00889 #endif
00890       }
00891     }
00892   }
00893 
00894  if (switcher_controller_->Visible ())
00895   {
00896     LayoutWindowList targets = switcher_controller_->ExternalRenderTargets ();
00897 
00898     for (LayoutWindow::Ptr target : targets)
00899     {
00900       CompWindow* window = screen->findWindow(target->xid);
00901       if (window)
00902       {
00903         UnityWindow *unity_window = UnityWindow::get (window);
00904 
00905         unity_window->paintThumbnail (target->result, target->alpha);
00906       }
00907     }
00908   }
00909 
00910   doShellRepaint = false;
00911   didShellRepaint = true;
00912 }
00913 
00914 bool UnityScreen::forcePaintOnTop ()
00915 {
00916     return !allowWindowPaint ||
00917       ((switcher_controller_->Visible() ||
00918         PluginAdapter::Default()->IsExpoActive())
00919        && !fullscreen_windows_.empty () && (!(screen->grabbed () && !screen->otherGrabExist (NULL))));
00920 }
00921 
00922 void UnityWindow::paintThumbnail (nux::Geometry const& bounding, float alpha)
00923 {
00924   GLMatrix matrix;
00925   matrix.toScreenSpace (UnityScreen::get (screen)->_last_output, -DEFAULT_Z_CAMERA);
00926 
00927   nux::Geometry geo = bounding;
00928   last_bound = geo;
00929 
00930   GLWindowPaintAttrib attrib = gWindow->lastPaintAttrib ();
00931   attrib.opacity = (GLushort) (alpha * G_MAXUSHORT);
00932 
00933   paintThumb (attrib,
00934               matrix,
00935               0,
00936               geo.x,
00937               geo.y,
00938               geo.width,
00939               geo.height,
00940               geo.width,
00941               geo.height);
00942 }
00943 
00944 void UnityScreen::EnableCancelAction(CancelActionTarget target, bool enabled, int modifiers)
00945 {
00946   if (enabled)
00947   {
00948     /* Create a new keybinding for the Escape key and the current modifiers,
00949      * compiz will take of the ref-counting of the repeated actions */
00950     KeyCode escape = XKeysymToKeycode(screen->dpy(), XStringToKeysym("Escape"));
00951     CompAction::KeyBinding binding(escape, modifiers);
00952 
00953     CompActionPtr &escape_action = _escape_actions[target];
00954     escape_action = CompActionPtr(new CompAction());
00955     escape_action->setKey(binding);
00956 
00957     screen->addAction(escape_action.get());
00958   }
00959   else if (!enabled && _escape_actions[target].get())
00960   {
00961     screen->removeAction(_escape_actions[target].get());
00962     _escape_actions.erase(target);
00963   }
00964 }
00965 
00966 void UnityScreen::enterShowDesktopMode ()
00967 {
00968   for (CompWindow *w : screen->windows ())
00969   {
00970     UnityWindow *uw = UnityWindow::get (w);
00971 
00972     if (ShowdesktopHandler::ShouldHide (static_cast <ShowdesktopHandlerWindowInterface *> (uw)))
00973     {
00974       UnityWindow::get (w)->enterShowDesktop ();
00975       // the animation plugin does strange things here ...
00976       // if this notification is sent
00977       // w->windowNotify (CompWindowNotifyEnterShowDesktopMode);
00978     }
00979     if (w->type() & CompWindowTypeDesktopMask)
00980       w->moveInputFocusTo();
00981   }
00982 
00983   PluginAdapter::Default()->OnShowDesktop();
00984 
00985   /* Disable the focus handler as we will report that
00986    * minimized windows can be focused which will
00987    * allow them to enter showdesktop mode. That's
00988    * no good */
00989   for (CompWindow *w : screen->windows ())
00990   {
00991     UnityWindow *uw = UnityWindow::get (w);
00992     w->focusSetEnabled (uw, false);
00993   }
00994 
00995   screen->enterShowDesktopMode ();
00996 
00997   for (CompWindow *w : screen->windows ())
00998   {
00999     UnityWindow *uw = UnityWindow::get (w);
01000     w->focusSetEnabled (uw, true);
01001   }
01002 }
01003 
01004 void UnityScreen::leaveShowDesktopMode (CompWindow *w)
01005 {
01006   /* Where a window is inhibiting, only allow the window
01007    * that is inhibiting the leave show desktop to actually
01008    * fade in again - all other windows should remain faded out */
01009   if (!ShowdesktopHandler::InhibitingXid ())
01010   {
01011     for (CompWindow *cw : screen->windows ())
01012     {
01013       if (cw->inShowDesktopMode ())
01014       {
01015         UnityWindow::get (cw)->leaveShowDesktop ();
01016         // the animation plugin does strange things here ...
01017         // if this notification is sent
01018         //cw->windowNotify (CompWindowNotifyLeaveShowDesktopMode);
01019       }
01020     }
01021 
01022     PluginAdapter::Default()->OnLeaveDesktop();
01023 
01024     screen->leaveShowDesktopMode (w);
01025   }
01026   else
01027   {
01028     CompWindow *cw = screen->findWindow (ShowdesktopHandler::InhibitingXid ());
01029     if (cw)
01030     {
01031       if (cw->inShowDesktopMode ())
01032       {
01033         UnityWindow::get (cw)->leaveShowDesktop ();
01034       }
01035     }
01036   }
01037 }
01038 
01039 void UnityWindow::enterShowDesktop ()
01040 {
01041   if (!mShowdesktopHandler)
01042     mShowdesktopHandler = new ShowdesktopHandler (static_cast <ShowdesktopHandlerWindowInterface *> (this),
01043                                                   static_cast <compiz::WindowInputRemoverLockAcquireInterface *> (this));
01044 
01045   window->setShowDesktopMode (true);
01046   mShowdesktopHandler->FadeOut ();
01047 }
01048 
01049 void UnityWindow::leaveShowDesktop ()
01050 {
01051   if (mShowdesktopHandler)
01052   {
01053     mShowdesktopHandler->FadeIn ();
01054     window->setShowDesktopMode (false);
01055   }
01056 }
01057 
01058 void UnityWindow::activate ()
01059 {
01060   ShowdesktopHandler::InhibitLeaveShowdesktopMode (window->id ());
01061   window->activate ();
01062   ShowdesktopHandler::AllowLeaveShowdesktopMode (window->id ());
01063 }
01064 
01065 void UnityWindow::DoEnableFocus ()
01066 {
01067   window->focusSetEnabled (this, true);
01068 }
01069 
01070 void UnityWindow::DoDisableFocus ()
01071 {
01072   window->focusSetEnabled (this, false);
01073 }
01074 
01075 bool UnityWindow::IsOverrideRedirect ()
01076 {
01077   return window->overrideRedirect ();
01078 }
01079 
01080 bool UnityWindow::IsManaged ()
01081 {
01082   return window->managed ();
01083 }
01084 
01085 bool UnityWindow::IsGrabbed ()
01086 {
01087   return window->grabbed ();
01088 }
01089 
01090 bool UnityWindow::IsDesktopOrDock ()
01091 {
01092   return (window->type () & (CompWindowTypeDesktopMask | CompWindowTypeDockMask));
01093 }
01094 
01095 bool UnityWindow::IsSkipTaskbarOrPager ()
01096 {
01097   return (window->state () & (CompWindowStateSkipTaskbarMask | CompWindowStateSkipPagerMask));
01098 }
01099 
01100 bool UnityWindow::IsInShowdesktopMode ()
01101 {
01102   return window->inShowDesktopMode ();
01103 }
01104 
01105 bool UnityWindow::IsHidden ()
01106 {
01107   return window->state () & CompWindowStateHiddenMask;
01108 }
01109 
01110 bool UnityWindow::IsShaded ()
01111 {
01112   return window->shaded ();
01113 }
01114 
01115 bool UnityWindow::IsMinimized ()
01116 {
01117   return window->minimized ();
01118 }
01119 
01120 void UnityWindow::DoOverrideFrameRegion (CompRegion &region)
01121 {
01122   unsigned int oldUpdateFrameRegionIndex = window->updateFrameRegionGetCurrentIndex ();
01123 
01124   window->updateFrameRegionSetCurrentIndex (MAXSHORT);
01125   window->updateFrameRegion (region);
01126   window->updateFrameRegionSetCurrentIndex (oldUpdateFrameRegionIndex);
01127 }
01128 
01129 void UnityWindow::DoHide ()
01130 {
01131   window->changeState (window->state () | CompWindowStateHiddenMask);
01132 }
01133 
01134 void UnityWindow::DoNotifyHidden ()
01135 {
01136   window->windowNotify (CompWindowNotifyHide);
01137 }
01138 
01139 void UnityWindow::DoShow ()
01140 {
01141   window->changeState (window->state () & ~(CompWindowStateHiddenMask));
01142 }
01143 
01144 void UnityWindow::DoNotifyShown ()
01145 {
01146   window->windowNotify (CompWindowNotifyShow);
01147 }
01148 
01149 void UnityWindow::DoMoveFocusAway ()
01150 {
01151   window->moveInputFocusToOtherWindow ();
01152 }
01153 
01154 ShowdesktopHandlerWindowInterface::PostPaintAction UnityWindow::DoHandleAnimations (unsigned int ms)
01155 {
01156   ShowdesktopHandlerWindowInterface::PostPaintAction action = ShowdesktopHandlerWindowInterface::PostPaintAction::Wait;
01157 
01158   if (mShowdesktopHandler)
01159     action = mShowdesktopHandler->Animate (ms);
01160 
01161   return action;
01162 }
01163 
01164 void UnityWindow::DoAddDamage ()
01165 {
01166   cWindow->addDamage ();
01167 }
01168 
01169 void UnityWindow::DoDeleteHandler ()
01170 {
01171   delete mShowdesktopHandler;
01172   mShowdesktopHandler = NULL;
01173 
01174   window->updateFrameRegion ();
01175 }
01176 
01177 compiz::WindowInputRemoverLock::Ptr
01178 UnityWindow::GetInputRemover ()
01179 {
01180   if (!input_remover_.expired ())
01181     return input_remover_.lock ();
01182 
01183   compiz::WindowInputRemoverLock::Ptr ret (new compiz::WindowInputRemoverLock (new compiz::WindowInputRemover (screen->dpy (), window->id ())));
01184   input_remover_ = ret;
01185   return ret;
01186 }
01187 
01188 unsigned int
01189 UnityWindow::GetNoCoreInstanceMask ()
01190 {
01191   return PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
01192 }
01193 
01194 void UnityWindow::handleEvent (XEvent *event)
01195 {
01196   if (screen->XShape () &&
01197       event->type == screen->shapeEvent () + ShapeNotify &&
01198       !event->xany.send_event)
01199   {
01200     if (mShowdesktopHandler)
01201       mShowdesktopHandler->HandleShapeEvent ();
01202   }
01203 }
01204 
01205 /* called whenever we need to repaint parts of the screen */
01206 bool UnityScreen::glPaintOutput(const GLScreenPaintAttrib& attrib,
01207                                 const GLMatrix& transform,
01208                                 const CompRegion& region,
01209                                 CompOutput* output,
01210                                 unsigned int mask)
01211 {
01212   bool ret;
01213 
01214   /*
01215    * Very important!
01216    * Don't waste GPU and CPU rendering the shell on every frame if you don't
01217    * need to. Doing so on every frame causes Nux to hog the GPU and slow down
01218    * ALL rendering. (LP: #988079)
01219    */
01220   bool force = forcePaintOnTop() || PluginAdapter::Default()->IsExpoActive();
01221   doShellRepaint = force || !(region.isEmpty() || wt->GetDrawList().empty());
01222 
01223   allowWindowPaint = true;
01224   _last_output = output;
01225   paint_panel_ = false;
01226 
01227 #ifndef USE_MODERN_COMPIZ_GL
01228   /* bind the framebuffer here
01229    * - it will be unbound and flushed
01230    *   to the backbuffer when some
01231    *   plugin requests to draw a
01232    *   a transformed screen or when
01233    *   we have finished this draw cycle.
01234    *   once an fbo is bound any further
01235    *   attempts to bind it will only increment
01236    *   its bind reference so make sure that
01237    *   you always unbind as much as you bind */
01238   if (doShellRepaint)
01239     _fbo->bind (nux::Geometry (output->x (), output->y (), output->width (), output->height ()));
01240 #endif
01241 
01242   // CompRegion has no clear() method. So this is the fastest alternative.
01243   fullscreenRegion = CompRegion();
01244   nuxRegion = CompRegion();
01245 
01246   /* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */
01247   ret = gScreen->glPaintOutput(attrib, transform, region, output, mask);
01248 
01249 #ifndef USE_MODERN_COMPIZ_GL
01250   if (doShellRepaint && !force && fullscreenRegion.contains(*output))
01251     doShellRepaint = false;
01252 
01253   if (doShellRepaint)
01254     paintDisplay(region, transform, mask);
01255 #endif
01256 
01257   return ret;
01258 }
01259 
01260 #ifdef USE_MODERN_COMPIZ_GL
01261 void UnityScreen::glPaintCompositedOutput (const CompRegion &region,
01262                                            ::GLFramebufferObject *fbo,
01263                                            unsigned int        mask)
01264 {
01265   bool useFbo = false;
01266 
01267   if (doShellRepaint)
01268   {
01269     oldFbo = fbo->bind ();
01270     useFbo = fbo->checkStatus () && fbo->tex ();
01271     if (!useFbo) {
01272        printf ("bailing from UnityScreen::glPaintCompositedOutput");
01273        ::GLFramebufferObject::rebind (oldFbo);
01274        return;
01275     }
01276     paintDisplay();
01277     ::GLFramebufferObject::rebind (oldFbo);
01278   }
01279 
01280   gScreen->glPaintCompositedOutput(region, fbo, mask);
01281 }
01282 #endif
01283 
01284 /* called whenever a plugin needs to paint the entire scene
01285  * transformed */
01286 
01287 void UnityScreen::glPaintTransformedOutput(const GLScreenPaintAttrib& attrib,
01288                                            const GLMatrix& transform,
01289                                            const CompRegion& region,
01290                                            CompOutput* output,
01291                                            unsigned int mask)
01292 {
01293   allowWindowPaint = false;
01294   gScreen->glPaintTransformedOutput(attrib, transform, region, output, mask);
01295 
01296 }
01297 
01298 void UnityScreen::preparePaint(int ms)
01299 {
01300   cScreen->preparePaint(ms);
01301 
01302   for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows)
01303     wi->HandleAnimations (ms);
01304 
01305   compizDamageNux(cScreen->currentDamage());
01306 
01307   didShellRepaint = false;
01308   firstWindowAboveShell = NULL;
01309 }
01310 
01311 void UnityScreen::donePaint()
01312 {
01313   /*
01314    * It's only safe to clear the draw list if drawing actually occurred
01315    * (i.e. the shell was not obscured behind a fullscreen window).
01316    * If you clear the draw list and drawing has not occured then you'd be
01317    * left with all your views thinking they're queued for drawing still and
01318    * would refuse to redraw when you return from fullscreen.
01319    * I think this is a Nux bug. ClearDrawList should ideally also mark all
01320    * the queued views as draw_cmd_queued_=false.
01321    */
01322   if (didShellRepaint)
01323     wt->ClearDrawList();
01324 
01325   std::list <ShowdesktopHandlerWindowInterface *> remove_windows;
01326 
01327   for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows)
01328   {
01329     ShowdesktopHandlerWindowInterface::PostPaintAction action = wi->HandleAnimations (0);
01330     if (action == ShowdesktopHandlerWindowInterface::PostPaintAction::Remove)
01331       remove_windows.push_back(wi);
01332     else if (action == ShowdesktopHandlerWindowInterface::PostPaintAction::Damage)
01333       wi->AddDamage ();
01334   }
01335 
01336   for (ShowdesktopHandlerWindowInterface *wi : remove_windows)
01337   {
01338     wi->DeleteHandler ();
01339     ShowdesktopHandler::animating_windows.remove (wi);
01340   }
01341 
01342   cScreen->donePaint ();
01343 }
01344 
01345 void UnityScreen::compizDamageNux(CompRegion const& damage)
01346 {
01347   if (!launcher_controller_)
01348     return;
01349 
01350   /*
01351    * Prioritise user interaction over active blur updates. So the general
01352    * slowness of the active blur doesn't affect the UI interaction performance.
01353    *
01354    * Also, BackgroundEffectHelper::ProcessDamage() is causing a feedback loop
01355    * while the dash is open. Calling it results in the NEXT frame (and the
01356    * current one?) to get some damage. This GetDrawList().empty() check avoids
01357    * that feedback loop and allows us to idle correctly.
01358    */
01359   if (wt->GetDrawList().empty())
01360   {
01361     CompRect::vector const& rects(damage.rects());
01362     for (CompRect const& r : rects)
01363     {
01364       nux::Geometry geo(r.x(), r.y(), r.width(), r.height());
01365       BackgroundEffectHelper::ProcessDamage(geo);
01366     }
01367   }
01368 
01369   auto launchers = launcher_controller_->launchers();
01370   for (auto launcher : launchers)
01371   {
01372     if (!launcher->Hidden())
01373     {
01374       nux::Geometry geo = launcher->GetAbsoluteGeometry();
01375       CompRegion launcher_region(geo.x, geo.y, geo.width, geo.height);
01376       if (damage.intersects(launcher_region))
01377         launcher->QueueDraw();
01378       nux::ObjectPtr<nux::View> tooltip = launcher->GetActiveTooltip();
01379       if (!tooltip.IsNull())
01380       {
01381         nux::Geometry tip = tooltip->GetAbsoluteGeometry();
01382         CompRegion tip_region(tip.x, tip.y, tip.width, tip.height);
01383         if (damage.intersects(tip_region))
01384           tooltip->QueueDraw();
01385       }
01386     }
01387   }
01388 
01389   std::vector<nux::View*> const& panels(panel_controller_->GetPanelViews());
01390   for (nux::View* view : panels)
01391   {
01392     nux::Geometry geo = view->GetAbsoluteGeometry();
01393     CompRegion panel_region(geo.x, geo.y, geo.width, geo.height);
01394     if (damage.intersects(panel_region))
01395       view->QueueDraw();
01396   }
01397 
01398   QuicklistManager* qm = QuicklistManager::Default();
01399   if (qm)
01400   {
01401     QuicklistView* view = qm->Current();
01402     if (view)
01403     {
01404       nux::Geometry geo = view->GetAbsoluteGeometry();
01405       CompRegion quicklist_region(geo.x, geo.y, geo.width, geo.height);
01406       if (damage.intersects(quicklist_region))
01407         view->QueueDraw();
01408     }
01409   }
01410 }
01411 
01412 /* Grab changed nux regions and add damage rects for them */
01413 void UnityScreen::nuxDamageCompiz()
01414 {
01415   /*
01416    * WARNING: Nux bug LP: #1014610 (unbounded DrawList growth) will cause
01417    *          this code to be called far too often in some cases and
01418    *          Unity will appear to freeze for a while. Please ensure you
01419    *          have Nux 3.0+ with the fix for LP: #1014610.
01420    */
01421 
01422   if (!launcher_controller_ || !dash_controller_)
01423     return;
01424 
01425   CompRegion nux_damage;
01426 
01427   std::vector<nux::Geometry> const& dirty = wt->GetDrawList();
01428   for (auto geo : dirty)
01429     nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height);
01430 
01431   if (launcher_controller_->IsOverlayOpen())
01432   {
01433     nux::BaseWindow* dash_window = dash_controller_->window();
01434     nux::Geometry const& geo = dash_window->GetAbsoluteGeometry();
01435     nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height);
01436   }
01437 
01438   auto launchers = launcher_controller_->launchers();
01439   for (auto launcher : launchers)
01440   {
01441     if (!launcher->Hidden())
01442     {
01443       nux::ObjectPtr<nux::View> tooltip = launcher->GetActiveTooltip();
01444       if (!tooltip.IsNull())
01445       {
01446         nux::Geometry const& g = tooltip->GetAbsoluteGeometry();
01447         nux_damage += CompRegion(g.x, g.y, g.width, g.height);
01448       }
01449     }
01450   }
01451 
01452   cScreen->damageRegionSetEnabled(this, false);
01453   cScreen->damageRegion(nux_damage);
01454   cScreen->damageRegionSetEnabled(this, true);
01455 }
01456 
01457 /* handle X Events */
01458 void UnityScreen::handleEvent(XEvent* event)
01459 {
01460   bool skip_other_plugins = false;
01461   switch (event->type)
01462   {
01463     case FocusIn:
01464     case FocusOut:
01465       if (event->xfocus.mode == NotifyGrab)
01466         PluginAdapter::Default()->OnScreenGrabbed();
01467       else if (event->xfocus.mode == NotifyUngrab)
01468         PluginAdapter::Default()->OnScreenUngrabbed();
01469 #ifndef USE_MODERN_COMPIZ_GL
01470       cScreen->damageScreen();  // evil hack
01471 #endif
01472       if (_key_nav_mode_requested)
01473       {
01474         // Close any overlay that is open.
01475         if (launcher_controller_->IsOverlayOpen())
01476         {
01477           dash_controller_->HideDash();
01478           hud_controller_->HideHud();
01479         }
01480         launcher_controller_->KeyNavGrab();
01481       }
01482       _key_nav_mode_requested = false;
01483       break;
01484     case ButtonPress:
01485       if (super_keypressed_)
01486       {
01487         launcher_controller_->KeyNavTerminate(false);
01488         EnableCancelAction(CancelActionTarget::LAUNCHER_SWITCHER, false);
01489       }
01490       break;
01491     case ButtonRelease:
01492       if (switcher_controller_ && switcher_controller_->Visible())
01493       {
01494         XButtonEvent *bev = reinterpret_cast<XButtonEvent*>(event);
01495         if (bev->time - last_scroll_event_ > 150)
01496         {
01497           if (bev->button == Button4 || bev->button == local::SCROLL_UP_BUTTON)
01498           {
01499             switcher_controller_->Prev();
01500             last_scroll_event_ = bev->time;
01501           }
01502           else if (bev->button == Button5 || bev->button == local::SCROLL_DOWN_BUTTON)
01503           {
01504             switcher_controller_->Next();
01505             last_scroll_event_ = bev->time;
01506           }
01507         }
01508       }
01509       break;
01510     case KeyPress:
01511     {
01512       if (super_keypressed_)
01513       {
01514         /* We need an idle to postpone this action, after the current event
01515          * has been processed */
01516         sources_.Add(std::make_shared<glib::Idle>([&]() {
01517           shortcut_controller_->SetEnabled(false);
01518           shortcut_controller_->Hide();
01519           EnableCancelAction(CancelActionTarget::SHORTCUT_HINT, false);
01520 
01521           return false;
01522         }));
01523       }
01524 
01525       KeySym key_sym;
01526       char key_string[2];
01527       int result = XLookupString(&(event->xkey), key_string, 2, &key_sym, 0);
01528 
01529       if (launcher_controller_->KeyNavIsActive())
01530       {
01531         if (key_sym == XK_Up)
01532         {
01533           launcher_controller_->KeyNavPrevious();
01534           break;
01535         }
01536         else if (key_sym == XK_Down)
01537         {
01538           launcher_controller_->KeyNavNext();
01539           break;
01540         }
01541       }
01542 
01543       if (result > 0)
01544       {
01545         // NOTE: does this have the potential to do an invalid write?  Perhaps
01546         // we should just say "key_string[1] = 0" because that is the only
01547         // thing that could possibly make sense here.
01548         key_string[result] = 0;
01549 
01550         if (super_keypressed_)
01551         {
01552           skip_other_plugins = launcher_controller_->HandleLauncherKeyEvent(screen->dpy(), key_sym, event->xkey.keycode, event->xkey.state, key_string);
01553           if (!skip_other_plugins)
01554             skip_other_plugins = dash_controller_->CheckShortcutActivation(key_string);
01555 
01556           if (skip_other_plugins && launcher_controller_->KeyNavIsActive())
01557           {
01558             launcher_controller_->KeyNavTerminate(false);
01559             EnableCancelAction(CancelActionTarget::LAUNCHER_SWITCHER, false);
01560           }
01561         }
01562       }
01563       break;
01564     }
01565     case MapRequest:
01566       ShowdesktopHandler::InhibitLeaveShowdesktopMode (event->xmaprequest.window);
01567       break;
01568     case PropertyNotify:
01569       if (event->xproperty.window == GDK_ROOT_WINDOW() &&
01570           event->xproperty.atom == gdk_x11_get_xatom_by_name("_GNOME_BACKGROUND_REPRESENTATIVE_COLORS"))
01571       {
01572         _bghash.RefreshColor();
01573       }
01574       break;
01575     default:
01576         if (screen->shapeEvent () + ShapeNotify == event->type)
01577         {
01578           Window xid = event->xany.window;
01579           CompWindow *w = screen->findWindow(xid);
01580 
01581           if (w)
01582           {
01583             UnityWindow *uw = UnityWindow::get (w);
01584 
01585             uw->handleEvent(event);
01586           }
01587         }
01588       break;
01589   }
01590 
01591   compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::handleEvent (event);
01592 
01593   // avoid further propagation (key conflict for instance)
01594   if (!skip_other_plugins)
01595     screen->handleEvent(event);
01596 
01597   switch (event->type)
01598   {
01599     case PropertyNotify:
01600       if (event->xproperty.atom == Atoms::mwmHints)
01601       {
01602         PluginAdapter::Default ()->NotifyNewDecorationState(event->xproperty.window);
01603       }
01604       break;
01605     case MapRequest:
01606       ShowdesktopHandler::AllowLeaveShowdesktopMode (event->xmaprequest.window);
01607       break;
01608   }
01609 
01610   if (!skip_other_plugins &&
01611       screen->otherGrabExist("deco", "move", "switcher", "resize", NULL) &&
01612       !switcher_controller_->Visible())
01613   {
01614     wt->ProcessForeignEvent(event, NULL);
01615   }
01616 }
01617 
01618 void UnityScreen::damageRegion(const CompRegion &region)
01619 {
01620   compizDamageNux(region);
01621   cScreen->damageRegion(region);
01622 }
01623 
01624 void UnityScreen::handleCompizEvent(const char* plugin,
01625                                     const char* event,
01626                                     CompOption::Vector& option)
01627 {
01628   PluginAdapter::Default()->NotifyCompizEvent(plugin, event, option);
01629   compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::handleCompizEvent (plugin, event, option);
01630 
01631   if (launcher_controller_->IsOverlayOpen() && g_strcmp0(event, "start_viewport_switch") == 0)
01632   {
01633     ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
01634   }
01635 
01636   if (PluginAdapter::Default()->IsScaleActive() && g_strcmp0(plugin, "scale") == 0)
01637   {
01638     scale_just_activated_ = true;
01639   }
01640 
01641   screen->handleCompizEvent(plugin, event, option);
01642 }
01643 
01644 bool UnityScreen::showLauncherKeyInitiate(CompAction* action,
01645                                           CompAction::State state,
01646                                           CompOption::Vector& options)
01647 {
01648   // to receive the Terminate event
01649   if (state & CompAction::StateInitKey)
01650     action->setState(action->state() | CompAction::StateTermKey);
01651 
01652   super_keypressed_ = true;
01653   int when = options[7].value().i();  // XEvent time in millisec
01654   launcher_controller_->HandleLauncherKeyPress(when);
01655   EnsureSuperKeybindings ();
01656 
01657   if (!shortcut_controller_->Visible() && shortcut_controller_->IsEnabled())
01658   {
01659     int launcher_width = optionGetIconSize() + 18;
01660     int panel_height = panel_style_.panel_height;
01661 
01662     if (shortcut_controller_->Show())
01663     {
01664       shortcut_controller_->SetAdjustment(launcher_width, panel_height);
01665       EnableCancelAction(CancelActionTarget::SHORTCUT_HINT, true, action->key().modifiers());
01666     }
01667   }
01668 
01669   return true;
01670 }
01671 
01672 bool UnityScreen::showLauncherKeyTerminate(CompAction* action,
01673                                            CompAction::State state,
01674                                            CompOption::Vector& options)
01675 {
01676   // Remember StateCancel and StateCommit will be broadcast to all actions
01677   // so we need to verify that we are actually being toggled...
01678   if (!(state & CompAction::StateTermKey))
01679     return false;
01680 
01681   if (state & CompAction::StateCancel)
01682     return false;
01683 
01684   bool was_tap = state & CompAction::StateTermTapped;
01685   LOG_DEBUG(logger) << "Super released: " << (was_tap ? "tapped" : "released");
01686   int when = options[7].value().i();  // XEvent time in millisec
01687 
01688   // hack...if the scale just wasn't activated AND the 'when' time is within time to start the
01689   // dash then assume was_tap is also true, since the ScalePlugin doesn't accept that state...
01690   if (PluginAdapter::Default()->IsScaleActive() && !scale_just_activated_ && launcher_controller_->AboutToShowDash(true, when))
01691   {
01692     PluginAdapter::Default()->TerminateScale();
01693     was_tap = true;
01694   }
01695   else if (scale_just_activated_)
01696   {
01697     scale_just_activated_ = false;
01698   }
01699 
01700   if (hud_controller_->IsVisible() && launcher_controller_->AboutToShowDash(was_tap, when))
01701     hud_controller_->HideHud();
01702 
01703   super_keypressed_ = false;
01704   launcher_controller_->KeyNavTerminate(true);
01705   launcher_controller_->HandleLauncherKeyRelease(was_tap, when);
01706   EnableCancelAction(CancelActionTarget::LAUNCHER_SWITCHER, false);
01707 
01708   shortcut_controller_->SetEnabled(enable_shortcut_overlay_);
01709   shortcut_controller_->Hide();
01710   EnableCancelAction(CancelActionTarget::SHORTCUT_HINT, false);
01711 
01712   action->setState (action->state() & (unsigned)~(CompAction::StateTermKey));
01713   return true;
01714 }
01715 
01716 bool UnityScreen::showPanelFirstMenuKeyInitiate(CompAction* action,
01717                                                 CompAction::State state,
01718                                                 CompOption::Vector& options)
01719 {
01720   /* In order to avoid too many events when keeping the keybinding pressed,
01721    * that would make the unity-panel-service to go crazy (see bug #948522)
01722    * we need to filter them, just considering an event every 750 ms */
01723   int event_time = options[7].value().i();  // XEvent time in millisec
01724 
01725   if (event_time - first_menu_keypress_time_ < 750)
01726   {
01727     first_menu_keypress_time_ = event_time;
01728     return false;
01729   }
01730 
01731   first_menu_keypress_time_ = event_time;
01732 
01733   /* Even if we do nothing on key terminate, we must enable it, not to to hide
01734    * the menus entries after that a menu has been shown and hidden via the
01735    * keyboard and the Alt key is still pressed */
01736   action->setState(action->state() | CompAction::StateTermKey);
01737   panel_controller_->FirstMenuShow();
01738 
01739   return true;
01740 }
01741 
01742 bool UnityScreen::showPanelFirstMenuKeyTerminate(CompAction* action,
01743                                                  CompAction::State state,
01744                                                  CompOption::Vector& options)
01745 {
01746   action->setState (action->state() & (unsigned)~(CompAction::StateTermKey));
01747   return true;
01748 }
01749 
01750 void UnityScreen::SendExecuteCommand()
01751 {
01752   if (hud_controller_->IsVisible())
01753   {
01754     hud_controller_->HideHud();
01755   }
01756 
01757   if (PluginAdapter::Default()->IsScaleActive())
01758   {
01759     PluginAdapter::Default()->TerminateScale();
01760   }
01761 
01762   ubus_manager_.SendMessage(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST,
01763                             g_variant_new("(sus)", "commands.lens", 0, ""));
01764 }
01765 
01766 bool UnityScreen::executeCommand(CompAction* action,
01767                                  CompAction::State state,
01768                                  CompOption::Vector& options)
01769 {
01770   SendExecuteCommand();
01771   return true;
01772 }
01773 
01774 
01775 bool UnityScreen::setKeyboardFocusKeyInitiate(CompAction* action,
01776                                               CompAction::State state,
01777                                               CompOption::Vector& options)
01778 {
01779   _key_nav_mode_requested = true;
01780   return true;
01781 }
01782 
01783 bool UnityScreen::altTabInitiateCommon(CompAction* action, switcher::ShowMode show_mode)
01784 {
01785   if (!grab_index_)
01786     grab_index_ = screen->pushGrab (screen->invisibleCursor(), "unity-switcher");
01787   if (!grab_index_)
01788     return false;
01789 
01790   screen->addAction(&optionGetAltTabRight());
01791   screen->addAction(&optionGetAltTabDetailStart());
01792   screen->addAction(&optionGetAltTabDetailStop());
01793   screen->addAction(&optionGetAltTabLeft());
01794 
01795   /* Create a new keybinding for scroll buttons and current modifiers */
01796   CompAction scroll_up;
01797   CompAction scroll_down;
01798   scroll_up.setButton(CompAction::ButtonBinding(local::SCROLL_UP_BUTTON, action->key().modifiers()));
01799   scroll_down.setButton(CompAction::ButtonBinding(local::SCROLL_DOWN_BUTTON, action->key().modifiers()));
01800   screen->addAction(&scroll_up);
01801   screen->addAction(&scroll_down);
01802 
01803   // maybe check launcher position/hide state?
01804 
01805   WindowManager *wm = WindowManager::Default();
01806   int monitor = wm->GetWindowMonitor(wm->GetActiveWindow());
01807   nux::Geometry monitor_geo = UScreen::GetDefault()->GetMonitorGeometry(monitor);
01808   monitor_geo.x += 100;
01809   monitor_geo.y += 100;
01810   monitor_geo.width -= 200;
01811   monitor_geo.height -= 200;
01812   switcher_controller_->SetWorkspace(monitor_geo, monitor);
01813 
01814   if (!optionGetAltTabBiasViewport())
01815   {
01816     if (show_mode == switcher::ShowMode::CURRENT_VIEWPORT)
01817       show_mode = switcher::ShowMode::ALL;
01818     else
01819       show_mode = switcher::ShowMode::CURRENT_VIEWPORT;
01820   }
01821 
01822   RaiseInputWindows();
01823 
01824   auto results = launcher_controller_->GetAltTabIcons(show_mode == switcher::ShowMode::CURRENT_VIEWPORT);
01825 
01826   if (!(results.size() == 1 && results[0]->GetIconType() == AbstractLauncherIcon::IconType::TYPE_DESKTOP))
01827     switcher_controller_->Show(show_mode, switcher::SortMode::FOCUS_ORDER, false, results);
01828 
01829   return true;
01830 }
01831 
01832 bool UnityScreen::altTabTerminateCommon(CompAction* action,
01833                                        CompAction::State state,
01834                                        CompOption::Vector& options)
01835 {
01836   if (grab_index_)
01837   {
01838     // remove grab before calling hide so workspace switcher doesn't fail
01839     screen->removeGrab(grab_index_, NULL);
01840     grab_index_ = 0;
01841 
01842     screen->removeAction(&optionGetAltTabRight ());
01843     screen->removeAction(&optionGetAltTabDetailStart ());
01844     screen->removeAction(&optionGetAltTabDetailStop ());
01845     screen->removeAction(&optionGetAltTabLeft ());
01846 
01847     /* Removing the scroll actions */
01848     CompAction scroll_up;
01849     CompAction scroll_down;
01850     scroll_up.setButton(CompAction::ButtonBinding(local::SCROLL_UP_BUTTON, action->key().modifiers()));
01851     scroll_down.setButton(CompAction::ButtonBinding(local::SCROLL_DOWN_BUTTON, action->key().modifiers()));
01852     screen->removeAction(&scroll_up);
01853     screen->removeAction(&scroll_down);
01854 
01855     bool accept_state = (state & CompAction::StateCancel) == 0;
01856     switcher_controller_->Hide(accept_state);
01857   }
01858 
01859   action->setState (action->state() & (unsigned)~(CompAction::StateTermKey));
01860   return true;
01861 }
01862 
01863 bool UnityScreen::altTabForwardInitiate(CompAction* action,
01864                                         CompAction::State state,
01865                                         CompOption::Vector& options)
01866 {
01867   if (switcher_controller_->Visible())
01868     switcher_controller_->Next();
01869   else
01870     altTabInitiateCommon(action, switcher::ShowMode::CURRENT_VIEWPORT);
01871 
01872   action->setState(action->state() | CompAction::StateTermKey);
01873   return true;
01874 }
01875 
01876 bool UnityScreen::altTabForwardAllInitiate(CompAction* action,
01877                                         CompAction::State state,
01878                                         CompOption::Vector& options)
01879 {
01880   if (switcher_controller_->Visible())
01881     switcher_controller_->Next();
01882   else
01883     altTabInitiateCommon(action, switcher::ShowMode::ALL);
01884 
01885   action->setState(action->state() | CompAction::StateTermKey);
01886   return true;
01887 }
01888 
01889 bool UnityScreen::altTabPrevAllInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
01890 {
01891   if (switcher_controller_->Visible())
01892   {
01893     switcher_controller_->Prev();
01894     return true;
01895   }
01896 
01897   return false;
01898 }
01899 
01900 bool UnityScreen::altTabPrevInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
01901 {
01902   if (switcher_controller_->Visible())
01903   {
01904     switcher_controller_->Prev();
01905     return true;
01906   }
01907 
01908   return false;
01909 }
01910 
01911 bool UnityScreen::altTabDetailStartInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
01912 {
01913   if (switcher_controller_->Visible())
01914   {
01915     switcher_controller_->SetDetail(true);
01916     return true;
01917   }
01918 
01919   return false;
01920 }
01921 
01922 bool UnityScreen::altTabDetailStopInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
01923 {
01924   if (switcher_controller_->Visible())
01925   {
01926     switcher_controller_->SetDetail(false);
01927     return true;
01928   }
01929 
01930   return false;
01931 }
01932 
01933 bool UnityScreen::altTabNextWindowInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
01934 {
01935   if (!switcher_controller_->Visible())
01936   {
01937     altTabInitiateCommon(action, switcher::ShowMode::CURRENT_VIEWPORT);
01938     switcher_controller_->Select(1); // always select the current application
01939   }
01940 
01941   switcher_controller_->NextDetail();
01942 
01943   action->setState(action->state() | CompAction::StateTermKey);
01944   return true;
01945 }
01946 
01947 bool UnityScreen::altTabPrevWindowInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
01948 {
01949   if (switcher_controller_->Visible())
01950   {
01951     switcher_controller_->PrevDetail();
01952     return true;
01953   }
01954 
01955   return false;
01956 }
01957 
01958 bool UnityScreen::launcherSwitcherForwardInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
01959 {
01960   if (!launcher_controller_->KeyNavIsActive())
01961   {
01962     int modifiers = action->key().modifiers();
01963 
01964     launcher_controller_->KeyNavActivate();
01965 
01966     EnableCancelAction(CancelActionTarget::LAUNCHER_SWITCHER, true, modifiers);
01967 
01968     KeyCode down_key = XKeysymToKeycode(screen->dpy(), XStringToKeysym("Down"));
01969     KeyCode up_key = XKeysymToKeycode(screen->dpy(), XStringToKeysym("Up"));
01970 
01971     CompAction down_action;
01972     down_action.setKey(CompAction::KeyBinding(down_key, modifiers));
01973     screen->addAction(&down_action);
01974 
01975     CompAction up_action;
01976     up_action.setKey(CompAction::KeyBinding(up_key, modifiers));
01977     screen->addAction(&up_action);
01978   }
01979   else
01980   {
01981     launcher_controller_->KeyNavNext();
01982   }
01983 
01984   action->setState(action->state() | CompAction::StateTermKey);
01985   return true;
01986 }
01987 bool UnityScreen::launcherSwitcherPrevInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
01988 {
01989   launcher_controller_->KeyNavPrevious();
01990 
01991   return true;
01992 }
01993 bool UnityScreen::launcherSwitcherTerminate(CompAction* action, CompAction::State state, CompOption::Vector& options)
01994 {
01995   bool accept_state = (state & CompAction::StateCancel) == 0;
01996   launcher_controller_->KeyNavTerminate(accept_state);
01997 
01998   EnableCancelAction(CancelActionTarget::LAUNCHER_SWITCHER, false);
01999 
02000   KeyCode down_key = XKeysymToKeycode(screen->dpy(), XStringToKeysym("Down"));
02001   KeyCode up_key = XKeysymToKeycode(screen->dpy(), XStringToKeysym("Up"));
02002 
02003   CompAction down_action;
02004   down_action.setKey(CompAction::KeyBinding(down_key, action->key().modifiers()));
02005   screen->removeAction(&down_action);
02006 
02007   CompAction up_action;
02008   up_action.setKey(CompAction::KeyBinding(up_key, action->key().modifiers()));
02009   screen->removeAction(&up_action);
02010 
02011   action->setState (action->state() & (unsigned)~(CompAction::StateTermKey));
02012   return true;
02013 }
02014 
02015 void UnityScreen::OnLauncherStartKeyNav(GVariant* data)
02016 {
02017   // Put the launcher BaseWindow at the top of the BaseWindow stack. The
02018   // input focus coming from the XinputWindow will be processed by the
02019   // launcher BaseWindow only. Then the Launcher BaseWindow will decide
02020   // which View will get the input focus.
02021   if (SaveInputThenFocus(launcher_controller_->KeyNavLauncherInputWindowId()))
02022     launcher_controller_->PushToFront();
02023 }
02024 
02025 void UnityScreen::OnLauncherEndKeyNav(GVariant* data)
02026 {
02027   RestoreWindow(data);
02028 }
02029 
02030 void UnityScreen::OnSwitcherStart(GVariant* data)
02031 {
02032   SaveInputThenFocus(switcher_controller_->GetSwitcherInputWindowId());
02033 }
02034 
02035 void UnityScreen::OnSwitcherEnd(GVariant* data)
02036 {
02037   RestoreWindow(data);
02038 }
02039 
02040 void UnityScreen::RestoreWindow(GVariant* data)
02041 {
02042   bool preserve_focus = false;
02043 
02044   if (data)
02045   {
02046     preserve_focus = g_variant_get_boolean(data);
02047   }
02048 
02049   // Return input-focus to previously focused window (before key-nav-mode was
02050   // entered)
02051   if (preserve_focus)
02052     PluginAdapter::Default ()->restoreInputFocus ();
02053 }
02054 
02055 bool UnityScreen::SaveInputThenFocus(const guint xid)
02056 {
02057   // get CompWindow*
02058   newFocusedWindow = screen->findWindow(xid);
02059 
02060   // check if currently focused window isn't it self
02061   if (xid != screen->activeWindow())
02062     PluginAdapter::Default()->saveInputFocus();
02063 
02064   // set input-focus on window
02065   if (newFocusedWindow)
02066   {
02067     newFocusedWindow->moveInputFocusTo();
02068     return true;
02069   }
02070   return false;
02071 }
02072 
02073 bool UnityScreen::ShowHud()
02074 {
02075   if (switcher_controller_->Visible())
02076   {
02077     LOG_ERROR(logger) << "this should never happen";
02078     return false; // early exit if the switcher is open
02079   }
02080 
02081   if (hud_controller_->IsVisible())
02082   {
02083     ubus_manager_.SendMessage(UBUS_HUD_CLOSE_REQUEST);
02084   }
02085   else
02086   {
02087     // Handles closing KeyNav (Alt+F1) if the hud is about to show
02088     if (launcher_controller_->KeyNavIsActive())
02089       launcher_controller_->KeyNavTerminate(false);
02090 
02091     // If an overlay is open, it must be the dash! Close it!
02092     if (launcher_controller_->IsOverlayOpen())
02093       dash_controller_->HideDash();
02094 
02095     hud_controller_->ShowHud();
02096   }
02097 
02098   // Consume the event.
02099   return true;
02100 }
02101 
02102 bool UnityScreen::ShowHudInitiate(CompAction* action,
02103                                   CompAction::State state,
02104                                   CompOption::Vector& options)
02105 {
02106   // Look to see if there is a keycode.  If there is, then this isn't a
02107   // modifier only keybinding.
02108   int key_code = 0;
02109   if (options[6].type() != CompOption::TypeUnset)
02110   {
02111     key_code = options[6].value().i();
02112     LOG_DEBUG(logger) << "HUD initiate key code: " << key_code;
02113     // show it now, no timings or terminate needed.
02114     return ShowHud();
02115   }
02116   else
02117   {
02118     LOG_DEBUG(logger) << "HUD initiate key code option not set, modifier only keypress.";
02119   }
02120 
02121 
02122   // to receive the Terminate event
02123   if (state & CompAction::StateInitKey)
02124     action->setState(action->state() | CompAction::StateTermKey);
02125   hud_keypress_time_ = options[7].value().i();  // XEvent time in millisec
02126 
02127   // pass key through
02128   return false;
02129 }
02130 
02131 bool UnityScreen::ShowHudTerminate(CompAction* action,
02132                                    CompAction::State state,
02133                                    CompOption::Vector& options)
02134 {
02135   // Remember StateCancel and StateCommit will be broadcast to all actions
02136   // so we need to verify that we are actually being toggled...
02137   if (!(state & CompAction::StateTermKey))
02138     return false;
02139 
02140   action->setState(action->state() & ~CompAction::StateTermKey);
02141 
02142   // If we have a modifier only keypress, check for tap and timing.
02143   if (!(state & CompAction::StateTermTapped))
02144     return false;
02145 
02146   int release_time = options[7].value().i();  // XEvent time in millisec
02147   int tap_duration = release_time - hud_keypress_time_;
02148   if (tap_duration > local::ALT_TAP_DURATION)
02149   {
02150     LOG_DEBUG(logger) << "Tap too long";
02151     return false;
02152   }
02153 
02154   return ShowHud();
02155 }
02156 
02157 bool UnityScreen::initPluginActions()
02158 {
02159   CompPlugin* p = CompPlugin::find("expo");
02160 
02161   if (p)
02162   {
02163     MultiActionList expoActions(0);
02164 
02165     foreach(CompOption & option, p->vTable->getOptions())
02166     {
02167       if (option.name() == "expo_key" ||
02168           option.name() == "expo_button" ||
02169           option.name() == "expo_edge")
02170       {
02171         CompAction* action = &option.value().action();
02172         expoActions.AddNewAction(action, false);
02173         break;
02174       }
02175     }
02176 
02177     PluginAdapter::Default()->SetExpoAction(expoActions);
02178   }
02179 
02180   p = CompPlugin::find("scale");
02181 
02182   if (p)
02183   {
02184     MultiActionList scaleActions(0);
02185 
02186     foreach(CompOption & option, p->vTable->getOptions())
02187     {
02188       if (option.name() == "initiate_all_key" ||
02189           option.name() == "initiate_all_edge" ||
02190           option.name() == "initiate_key" ||
02191           option.name() == "initiate_button" ||
02192           option.name() == "initiate_edge" ||
02193           option.name() == "initiate_group_key" ||
02194           option.name() == "initiate_group_button" ||
02195           option.name() == "initiate_group_edge" ||
02196           option.name() == "initiate_output_key" ||
02197           option.name() == "initiate_output_button" ||
02198           option.name() == "initiate_output_edge")
02199       {
02200         CompAction* action = &option.value().action();
02201         scaleActions.AddNewAction(action, false);
02202       }
02203       else if (option.name() == "initiate_all_button")
02204       {
02205         CompAction* action = &option.value().action();
02206         scaleActions.AddNewAction(action, true);
02207       }
02208     }
02209 
02210     PluginAdapter::Default()->SetScaleAction(scaleActions);
02211   }
02212 
02213   p = CompPlugin::find("unitymtgrabhandles");
02214 
02215   if (p)
02216   {
02217     foreach(CompOption & option, p->vTable->getOptions())
02218     {
02219       if (option.name() == "show_handles_key")
02220         PluginAdapter::Default()->SetShowHandlesAction(&option.value().action());
02221       else if (option.name() == "hide_handles_key")
02222         PluginAdapter::Default()->SetHideHandlesAction(&option.value().action());
02223       else if (option.name() == "toggle_handles_key")
02224         PluginAdapter::Default()->SetToggleHandlesAction(&option.value().action());
02225     }
02226   }
02227 
02228   return false;
02229 }
02230 
02231 /* Set up expo and scale actions on the launcher */
02232 bool UnityScreen::initPluginForScreen(CompPlugin* p)
02233 {
02234   if (p->vTable->name() == "expo" ||
02235       p->vTable->name() == "scale")
02236   {
02237     initPluginActions();
02238   }
02239 
02240   bool result = screen->initPluginForScreen(p);
02241   if (p->vTable->name() == "unityshell")
02242     initAltTabNextWindow();
02243 
02244   return result;
02245 }
02246 
02247 void UnityScreen::AddProperties(GVariantBuilder* builder)
02248 {
02249 }
02250 
02251 std::string UnityScreen::GetName() const
02252 {
02253   return "Unity";
02254 }
02255 
02256 bool isNuxWindow (CompWindow* value)
02257 {
02258   std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList();
02259   auto id = value->id();
02260 
02261   // iterate loop by hand rather than use std::find as this is considerably faster
02262   // we care about performance here becuase of the high frequency in which this function is
02263   // called (nearly every frame)
02264   unsigned int size = xwns.size();
02265   for (unsigned int i = 0; i < size; ++i)
02266   {
02267     if (xwns[i] == id)
02268       return true;
02269   }
02270   return false;
02271 }
02272 
02273 void UnityScreen::RaiseInputWindows()
02274 {
02275   std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList();
02276 
02277   for (auto window : xwns)
02278   {
02279     CompWindow* cwin = screen->findWindow(window);
02280     if (cwin)
02281       cwin->raise();
02282   }
02283 }
02284 
02285 /* detect occlusions
02286  *
02287  * core passes down the PAINT_WINDOW_OCCLUSION_DETECTION
02288  * mask when it is doing occlusion detection, so use that
02289  * order to fill our occlusion buffer which we'll flip
02290  * to nux later
02291  */
02292 bool UnityWindow::glPaint(const GLWindowPaintAttrib& attrib,
02293                           const GLMatrix& matrix,
02294                           const CompRegion& region,
02295                           unsigned int mask)
02296 {
02297   /*
02298    * The occlusion pass tests windows from TOP to BOTTOM. That's opposite to
02299    * the actual painting loop.
02300    *
02301    * Detect uScreen->fullscreenRegion here. That represents the region which
02302    * fully covers the shell on its output. It does not include regular windows
02303    * stacked above the shell like DnD icons or Onboard etc.
02304    */
02305   if (isNuxWindow(window))
02306   {
02307     if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
02308     {
02309       uScreen->nuxRegion += window->geometry();
02310       uScreen->nuxRegion -= uScreen->fullscreenRegion;
02311     }
02312     return false;  // Ensure nux windows are never painted by compiz
02313   }
02314   else if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
02315   {
02316     static const unsigned int nonOcclusionBits =
02317                               PAINT_WINDOW_TRANSLUCENT_MASK |
02318                               PAINT_WINDOW_TRANSFORMED_MASK |
02319                               PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
02320     if (!(mask & nonOcclusionBits) &&
02321         (window->state() & CompWindowStateFullscreenMask))
02322         // And I've been advised to test other things, but they don't work:
02323         // && (attrib.opacity == OPAQUE)) <-- Doesn't work; Only set in glDraw
02324         // && !window->alpha() <-- Doesn't work; Opaque windows often have alpha
02325     {
02326       uScreen->fullscreenRegion += window->geometry();
02327       uScreen->fullscreenRegion -= uScreen->nuxRegion;
02328     }
02329     if (uScreen->nuxRegion.isEmpty())
02330       uScreen->firstWindowAboveShell = window;
02331   }
02332 
02333   GLWindowPaintAttrib wAttrib = attrib;
02334 
02335   if (mMinimizeHandler)
02336   {
02337     mask |= mMinimizeHandler->getPaintMask ();
02338   }
02339   else if (mShowdesktopHandler)
02340   {
02341     mShowdesktopHandler->PaintOpacity (wAttrib.opacity);
02342     mask |= mShowdesktopHandler->GetPaintMask ();
02343   }
02344 
02345   std::vector<Window> const& tray_xids = uScreen->panel_controller_->GetTrayXids();
02346   if (std::find(tray_xids.begin(), tray_xids.end(), window->id()) != tray_xids.end() &&
02347       !uScreen->allowWindowPaint)
02348   {
02349     if (!uScreen->painting_tray_)
02350     {
02351       uScreen->tray_paint_mask_ = mask;
02352       mask |= PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
02353     }
02354   }
02355 
02356   return gWindow->glPaint(wAttrib, matrix, region, mask);
02357 }
02358 
02359 /* handle window painting in an opengl context
02360  *
02361  * we want to paint underneath other windows here,
02362  * so we need to find if this window is actually
02363  * stacked on top of one of the nux input windows
02364  * and if so paint nux and stop us from painting
02365  * other windows or on top of the whole screen */
02366 bool UnityWindow::glDraw(const GLMatrix& matrix,
02367 #ifndef USE_MODERN_COMPIZ_GL
02368                          GLFragment::Attrib& attrib,
02369 #else
02370                          const GLWindowPaintAttrib& attrib,
02371 #endif
02372                          const CompRegion& region,
02373                          unsigned int mask)
02374 {
02375   if (uScreen->doShellRepaint && !uScreen->paint_panel_ && window->type() == CompWindowTypeNormalMask)
02376   {
02377     guint32 id = window->id();
02378     bool maximized = WindowManager::Default()->IsWindowMaximized(id);
02379     bool on_current = window->onCurrentDesktop();
02380     bool override_redirect = window->overrideRedirect();
02381     bool managed = window->managed();
02382     CompPoint viewport = window->defaultViewport();
02383     int output = window->outputDevice();
02384 
02385     if (maximized && on_current && !override_redirect && managed && viewport == uScreen->screen->vp() && output == (int)uScreen->screen->currentOutputDev().id())
02386     {
02387       uScreen->paint_panel_ = true;
02388     }
02389   }
02390 
02391   if (uScreen->doShellRepaint &&
02392       !uScreen->forcePaintOnTop () &&
02393       window == uScreen->firstWindowAboveShell &&
02394       !uScreen->fullscreenRegion.contains(window->geometry())
02395      )
02396   {
02397 #ifdef USE_MODERN_COMPIZ_GL
02398     uScreen->paintDisplay();
02399 #else
02400     uScreen->paintDisplay(region, matrix, mask);
02401 #endif
02402   }
02403 
02404   if (window->type() == CompWindowTypeDesktopMask)
02405     uScreen->setPanelShadowMatrix(matrix);
02406 
02407   Window active_window = screen->activeWindow();
02408   if (window->id() == active_window && window->type() != CompWindowTypeDesktopMask)
02409   {
02410     uScreen->paintPanelShadow(matrix);
02411   }
02412 
02413   bool ret = gWindow->glDraw(matrix, attrib, region, mask);
02414 
02415   if ((active_window == 0 || active_window == window->id()) &&
02416       (window->type() == CompWindowTypeDesktopMask))
02417   {
02418     uScreen->paintPanelShadow(matrix);
02419   }
02420 
02421 
02422   return ret;
02423 }
02424 
02425 void
02426 UnityWindow::minimize ()
02427 {
02428   if (!window->managed ())
02429     return;
02430 
02431   if (!mMinimizeHandler)
02432   {
02433     mMinimizeHandler.reset (new UnityMinimizedHandler (window, this));
02434     mMinimizeHandler->minimize ();
02435   }
02436 }
02437 
02438 void
02439 UnityWindow::unminimize ()
02440 {
02441   if (mMinimizeHandler)
02442   {
02443     mMinimizeHandler->unminimize ();
02444     mMinimizeHandler.reset ();
02445   }
02446 }
02447 
02448 bool
02449 UnityWindow::focus ()
02450 {
02451   if (!mMinimizeHandler)
02452     return window->focus ();
02453 
02454   if (window->overrideRedirect ())
02455     return false;
02456 
02457   if (!window->managed ())
02458     return false;
02459 
02460   if (!window->onCurrentDesktop ())
02461     return false;
02462 
02463   /* Only withdrawn windows
02464    * which are marked hidden
02465    * are excluded */
02466   if (!window->shaded () &&
02467       !window->minimized () &&
02468       (window->state () & CompWindowStateHiddenMask))
02469     return false;
02470 
02471   if (window->geometry ().x () + window->geometry ().width ()  <= 0 ||
02472       window->geometry ().y () + window->geometry ().height () <= 0 ||
02473       window->geometry ().x () >= (int) screen->width ()||
02474       window->geometry ().y () >= (int) screen->height ())
02475     return false;
02476 
02477   return true;
02478 }
02479 
02480 bool
02481 UnityWindow::minimized ()
02482 {
02483   return mMinimizeHandler.get () != nullptr;
02484 }
02485 
02486 /* Called whenever a window is mapped, unmapped, minimized etc */
02487 void UnityWindow::windowNotify(CompWindowNotify n)
02488 {
02489   PluginAdapter::Default()->Notify(window, n);
02490 
02491   switch (n)
02492   {
02493     case CompWindowNotifyMap:
02494       if (window->type() == CompWindowTypeDesktopMask) {
02495         if (!focus_desktop_timeout_)
02496         {
02497           focus_desktop_timeout_.reset(new glib::Timeout(1000, [&] {
02498             for (CompWindow *w : screen->clientList())
02499             {
02500               if (!(w->type() & NO_FOCUS_MASK) && w->focus ())
02501               {
02502                 focus_desktop_timeout_ = nullptr;
02503                 return false;
02504               }
02505             }
02506 
02507             window->moveInputFocusTo();
02508 
02509             focus_desktop_timeout_ = nullptr;
02510             return false;
02511           }));
02512         }
02513       }
02514     /* Fall through an re-evaluate wraps on map and unmap too */
02515     case CompWindowNotifyUnmap:
02516       if (UnityScreen::get (screen)->optionGetShowMinimizedWindows () &&
02517           window->mapNum ())
02518       {
02519         bool wasMinimized = window->minimized ();
02520         if (wasMinimized)
02521           window->unminimize ();
02522         window->focusSetEnabled (this, true);
02523         window->minimizeSetEnabled (this, true);
02524         window->unminimizeSetEnabled (this, true);
02525         window->minimizedSetEnabled (this, true);
02526 
02527         if (wasMinimized)
02528           window->minimize ();
02529       }
02530       else
02531       {
02532         window->focusSetEnabled (this, false);
02533         window->minimizeSetEnabled (this, false);
02534         window->unminimizeSetEnabled (this, false);
02535         window->minimizedSetEnabled (this, false);
02536       }
02537         break;
02538       default:
02539         break;
02540   }
02541 
02542 
02543   window->windowNotify(n);
02544 
02545   if (mMinimizeHandler)
02546   {
02547     /* The minimize handler will short circuit the frame
02548      * region update func and ensure that the frame
02549      * does not have a region */
02550     mMinimizeHandler->windowNotify (n);
02551   }
02552   else if (mShowdesktopHandler)
02553   {
02554     if (n == CompWindowNotifyFocusChange)
02555       mShowdesktopHandler->WindowFocusChangeNotify ();
02556   }
02557 
02558   // We do this after the notify to ensure input focus has actually been moved.
02559   if (n == CompWindowNotifyFocusChange)
02560   {
02561     UnityScreen* us = UnityScreen::get(screen);
02562     CompWindow *lw;
02563 
02564     if (us->launcher_controller_->IsOverlayOpen())
02565     {
02566       lw = screen->findWindow(us->launcher_controller_->LauncherWindowId(0));
02567       lw->moveInputFocusTo();
02568     }
02569   }
02570 }
02571 
02572 void UnityWindow::stateChangeNotify(unsigned int lastState)
02573 {
02574   if (window->state () & CompWindowStateFullscreenMask &&
02575       !(lastState & CompWindowStateFullscreenMask))
02576     UnityScreen::get (screen)->fullscreen_windows_.push_back(window);
02577   else if (lastState & CompWindowStateFullscreenMask &&
02578      !(window->state () & CompWindowStateFullscreenMask))
02579     UnityScreen::get (screen)->fullscreen_windows_.remove(window);
02580 
02581   PluginAdapter::Default()->NotifyStateChange(window, window->state(), lastState);
02582   window->stateChangeNotify(lastState);
02583 }
02584 
02585 void UnityWindow::updateFrameRegion(CompRegion &region)
02586 {
02587   /* The minimize handler will short circuit the frame
02588    * region update func and ensure that the frame
02589    * does not have a region */
02590 
02591   if (mMinimizeHandler)
02592     mMinimizeHandler->updateFrameRegion (region);
02593   else if (mShowdesktopHandler)
02594     mShowdesktopHandler->UpdateFrameRegion (region);
02595   else
02596     window->updateFrameRegion (region);
02597 }
02598 
02599 void UnityWindow::moveNotify(int x, int y, bool immediate)
02600 {
02601   PluginAdapter::Default()->NotifyMoved(window, x, y);
02602   window->moveNotify(x, y, immediate);
02603 }
02604 
02605 void UnityWindow::resizeNotify(int x, int y, int w, int h)
02606 {
02607   PluginAdapter::Default()->NotifyResized(window, x, y, w, h);
02608   window->resizeNotify(x, y, w, h);
02609 }
02610 
02611 CompPoint UnityWindow::tryNotIntersectUI(CompPoint& pos)
02612 {
02613   UnityScreen* us = UnityScreen::get(screen);
02614   auto window_geo = window->borderRect ();
02615   nux::Geometry target_monitor;
02616   nux::Point result(pos.x(), pos.y());
02617 
02618   // seriously why does compiz not track monitors XRandR style???
02619   auto monitors = UScreen::GetDefault()->GetMonitors();
02620   for (auto monitor : monitors)
02621   {
02622     if (monitor.IsInside(result))
02623     {
02624       target_monitor = monitor;
02625       break;
02626     }
02627   }
02628 
02629   auto launchers = us->launcher_controller_->launchers();
02630   for (auto launcher : launchers)
02631   {
02632     nux::Geometry geo = launcher->GetAbsoluteGeometry();
02633 
02634     if (launcher->Hidden() || launcher->options()->hide_mode == LAUNCHER_HIDE_NEVER || launcher->options()->hide_mode == LAUNCHER_HIDE_AUTOHIDE)
02635       continue;
02636 
02637     if (geo.IsInside(result))
02638     {
02639       if (geo.x + geo.width + 1 + window_geo.width() < target_monitor.x + target_monitor.width)
02640       {
02641         result.x = geo.x + geo.width + 1;
02642       }
02643     }
02644   }
02645 
02646   for (nux::Geometry &geo : us->panel_controller_->GetGeometries ())
02647   {
02648     if (geo.IsInside(result))
02649     {
02650       if (geo.y + geo.height + window_geo.height() < target_monitor.y + target_monitor.height)
02651       {
02652         result.y = geo.y + geo.height;
02653       }
02654     }
02655   }
02656 
02657   pos.setX(result.x);
02658   pos.setY(result.y);
02659   return pos;
02660 }
02661 
02662 bool UnityWindow::place(CompPoint& pos)
02663 {
02664   bool was_maximized = PluginAdapter::Default ()->MaximizeIfBigEnough(window);
02665 
02666   if (!was_maximized)
02667   {
02668     bool result = window->place(pos);
02669 
02670     if (window->type() & NO_FOCUS_MASK)
02671       return result;
02672 
02673     pos = tryNotIntersectUI(pos);
02674     return result;
02675   }
02676 
02677   return true;
02678 }
02679 
02680 
02681 /* Start up nux after OpenGL is initialized */
02682 void UnityScreen::initUnity(nux::NThread* thread, void* InitData)
02683 {
02684   Timer timer;
02685   UnityScreen* self = reinterpret_cast<UnityScreen*>(InitData);
02686   self->initLauncher();
02687 
02688   nux::ColorLayer background(nux::color::Transparent);
02689   static_cast<nux::WindowThread*>(thread)->SetWindowBackgroundPaintLayer(&background);
02690   LOG_INFO(logger) << "UnityScreen::initUnity: " << timer.ElapsedSeconds() << "s";
02691 }
02692 
02693 void UnityScreen::onRedrawRequested()
02694 {
02695   nuxDamageCompiz();
02696 }
02697 
02698 /* Handle option changes and plug that into nux windows */
02699 void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num)
02700 {
02701   // Note: perhaps we should put the options here into the controller.
02702   unity::launcher::Options::Ptr launcher_options = launcher_controller_->options();
02703   switch (num)
02704   {
02705     case UnityshellOptions::NumLaunchers:
02706       launcher_controller_->multiple_launchers = optionGetNumLaunchers() == 0;
02707       dash_controller_->use_primary = !launcher_controller_->multiple_launchers();
02708       hud_controller_->multiple_launchers = launcher_controller_->multiple_launchers();
02709       break;
02710     case UnityshellOptions::LauncherCaptureMouse:
02711       launcher_options->edge_resist = optionGetLauncherCaptureMouse();
02712       break;
02713     case UnityshellOptions::BackgroundColor:
02714     {
02715       nux::Color override_color (optionGetBackgroundColorRed() / 65535.0f,
02716                                  optionGetBackgroundColorGreen() / 65535.0f,
02717                                  optionGetBackgroundColorBlue() / 65535.0f,
02718                                  optionGetBackgroundColorAlpha() / 65535.0f);
02719 
02720       override_color.red = override_color.red / override_color.alpha;
02721       override_color.green = override_color.green / override_color.alpha;
02722       override_color.blue = override_color.blue / override_color.alpha;
02723       _bghash.OverrideColor(override_color);
02724       break;
02725     }
02726     case UnityshellOptions::LauncherHideMode:
02727     {
02728       launcher_options->hide_mode = (unity::launcher::LauncherHideMode) optionGetLauncherHideMode();
02729       hud_controller_->launcher_locked_out = (launcher_options->hide_mode == unity::launcher::LauncherHideMode::LAUNCHER_HIDE_NEVER);
02730       break;
02731     }
02732     case UnityshellOptions::BacklightMode:
02733       launcher_options->backlight_mode = (unity::launcher::BacklightMode) optionGetBacklightMode();
02734       break;
02735     case UnityshellOptions::RevealTrigger:
02736       launcher_options->reveal_trigger = (unity::launcher::RevealTrigger) optionGetRevealTrigger();
02737       break;
02738     case UnityshellOptions::LaunchAnimation:
02739       launcher_options->launch_animation = (unity::launcher::LaunchAnimation) optionGetLaunchAnimation();
02740       break;
02741     case UnityshellOptions::UrgentAnimation:
02742       launcher_options->urgent_animation = (unity::launcher::UrgentAnimation) optionGetUrgentAnimation();
02743       break;
02744     case UnityshellOptions::PanelOpacity:
02745       panel_controller_->SetOpacity(optionGetPanelOpacity());
02746       break;
02747     case UnityshellOptions::PanelOpacityMaximizedToggle:
02748       panel_controller_->SetOpacityMaximizedToggle(optionGetPanelOpacityMaximizedToggle());
02749       break;
02750     case UnityshellOptions::MenusFadein:
02751     case UnityshellOptions::MenusFadeout:
02752     case UnityshellOptions::MenusDiscoveryFadein:
02753     case UnityshellOptions::MenusDiscoveryFadeout:
02754     case UnityshellOptions::MenusDiscoveryDuration:
02755       panel_controller_->SetMenuShowTimings(optionGetMenusFadein(),
02756                                             optionGetMenusFadeout(),
02757                                             optionGetMenusDiscoveryDuration(),
02758                                             optionGetMenusDiscoveryFadein(),
02759                                             optionGetMenusDiscoveryFadeout());
02760       break;
02761     case UnityshellOptions::LauncherOpacity:
02762       launcher_options->background_alpha = optionGetLauncherOpacity();
02763       break;
02764     case UnityshellOptions::IconSize:
02765     {
02766       CompPlugin         *p = CompPlugin::find ("expo");
02767 
02768       launcher_options->icon_size = optionGetIconSize();
02769       launcher_options->tile_size = optionGetIconSize() + 6;
02770 
02771       hud_controller_->icon_size = launcher_options->icon_size();
02772       hud_controller_->tile_size = launcher_options->tile_size();
02773 
02774       /* The launcher geometry includes 1px used to draw the right margin
02775        * that must not be considered when drawing an overlay */
02776       hud_controller_->launcher_width = launcher_controller_->launcher().GetAbsoluteWidth() - 1;
02777       dash_controller_->launcher_width = launcher_controller_->launcher().GetAbsoluteWidth() - 1;
02778 
02779       if (p)
02780       {
02781         CompOption::Vector &opts = p->vTable->getOptions ();
02782 
02783         for (CompOption &o : opts)
02784         {
02785           if (o.name () == std::string ("x_offset"))
02786           {
02787             CompOption::Value v;
02788             v.set (static_cast <int> (optionGetIconSize() + 18));
02789 
02790             screen->setOptionForPlugin (p->vTable->name ().c_str (), o.name ().c_str (), v);
02791             break;
02792           }
02793         }
02794       }
02795       break;
02796     }
02797     case UnityshellOptions::AutohideAnimation:
02798       launcher_options->auto_hide_animation = (unity::launcher::AutoHideAnimation) optionGetAutohideAnimation();
02799       break;
02800     case UnityshellOptions::DashBlurExperimental:
02801       BackgroundEffectHelper::blur_type = (unity::BlurType)optionGetDashBlurExperimental();
02802       break;
02803     case UnityshellOptions::AutomaximizeValue:
02804       PluginAdapter::Default()->SetCoverageAreaBeforeAutomaximize(optionGetAutomaximizeValue() / 100.0f);
02805       break;
02806     case UnityshellOptions::DevicesOption:
02807       unity::DevicesSettings::GetDefault().SetDevicesOption((unity::DevicesSettings::DevicesOption) optionGetDevicesOption());
02808       break;
02809     case UnityshellOptions::AltTabTimeout:
02810       switcher_controller_->detail_on_timeout = optionGetAltTabTimeout();
02811     case UnityshellOptions::AltTabBiasViewport:
02812       PluginAdapter::Default()->bias_active_to_viewport = optionGetAltTabBiasViewport();
02813       break;
02814     case UnityshellOptions::ShowMinimizedWindows:
02815       compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::setFunctions (optionGetShowMinimizedWindows ());
02816       screen->enterShowDesktopModeSetEnabled (this, optionGetShowMinimizedWindows ());
02817       screen->leaveShowDesktopModeSetEnabled (this, optionGetShowMinimizedWindows ());
02818       break;
02819     case UnityshellOptions::ShortcutOverlay:
02820       enable_shortcut_overlay_ = optionGetShortcutOverlay();
02821       shortcut_controller_->SetEnabled(enable_shortcut_overlay_);
02822       break;
02823     case UnityshellOptions::ShowDesktopIcon:
02824       launcher_controller_->SetShowDesktopIcon(optionGetShowDesktopIcon());
02825       break;
02826     case UnityshellOptions::DecayRate:
02827       launcher_options->edge_decay_rate = optionGetDecayRate() * 100;
02828       break;
02829     case UnityshellOptions::OvercomePressure:
02830       launcher_options->edge_overcome_pressure = optionGetOvercomePressure() * 100;
02831       break;
02832     case UnityshellOptions::StopVelocity:
02833       launcher_options->edge_stop_velocity = optionGetStopVelocity() * 100;
02834       break;
02835     case UnityshellOptions::RevealPressure:
02836       launcher_options->edge_reveal_pressure = optionGetRevealPressure() * 100;
02837     case UnityshellOptions::EdgeResponsiveness:
02838       launcher_options->edge_responsiveness = optionGetEdgeResponsiveness();
02839       break;
02840     default:
02841       break;
02842   }
02843 }
02844 
02845 void UnityScreen::NeedsRelayout()
02846 {
02847   needsRelayout = true;
02848 }
02849 
02850 void UnityScreen::ScheduleRelayout(guint timeout)
02851 {
02852   if (!sources_.GetSource(local::RELAYOUT_TIMEOUT))
02853   {
02854     auto relayout_timeout(std::make_shared<glib::Timeout>(timeout));
02855     sources_.Add(relayout_timeout, local::RELAYOUT_TIMEOUT);
02856 
02857     relayout_timeout->Run([&]() {
02858       NeedsRelayout();
02859       Relayout();
02860 
02861       cScreen->damageScreen();
02862 
02863       return false;
02864     });
02865   }
02866 }
02867 
02868 void UnityScreen::Relayout()
02869 {
02870   nux::Geometry geometry (0, 0, screen->width (), screen->height ());
02871 
02872   if (!needsRelayout)
02873     return;
02874 
02875 #ifndef USE_MODERN_COMPIZ_GL
02876   if (GL::fbo)
02877   {
02878     uScreen->_fbo = ScreenEffectFramebufferObject::Ptr (new ScreenEffectFramebufferObject (glXGetProcAddressP, geometry));
02879     uScreen->_fbo->onScreenSizeChanged (geometry);
02880   }
02881 #endif
02882 
02883   UScreen *uscreen = UScreen::GetDefault();
02884   int primary_monitor = uscreen->GetPrimaryMonitor();
02885   auto geo = uscreen->GetMonitorGeometry(primary_monitor);
02886 
02887   primary_monitor_ = nux::Geometry(geo.x, geo.y, geo.width, geo.height);
02888   wt->SetWindowSize(geo.width, geo.height);
02889 
02890   LOG_DEBUG(logger) << "Setting to primary screen rect:"
02891                     << " x=" << primary_monitor_().x
02892                     << " y=" << primary_monitor_().y
02893                     << " w=" << primary_monitor_().width
02894                     << " h=" << primary_monitor_().height;
02895 
02896   needsRelayout = false;
02897 }
02898 
02899 /* Handle changes in the number of workspaces by showing the switcher
02900  * or not showing the switcher */
02901 bool UnityScreen::setOptionForPlugin(const char* plugin, const char* name,
02902                                      CompOption::Value& v)
02903 {
02904   bool status = screen->setOptionForPlugin(plugin, name, v);
02905   if (status)
02906   {
02907     if (strcmp(plugin, "core") == 0 && strcmp(name, "hsize") == 0)
02908     {
02909       launcher_controller_->UpdateNumWorkspaces(screen->vpSize().width() * screen->vpSize().height());
02910     }
02911   }
02912   return status;
02913 }
02914 
02915 void UnityScreen::outputChangeNotify()
02916 {
02917   screen->outputChangeNotify ();
02918 
02919   ScheduleRelayout(500);
02920 }
02921 
02922 void UnityScreen::OnDashRealized ()
02923 {
02924   /* stack any windows named "onboard" above us */
02925   for (CompWindow *w : screen->windows ())
02926   {
02927     if (w->resName() == "onboard")
02928     {
02929       Window xid = dash_controller_->window()->GetInputWindowId();
02930       XSetTransientForHint (screen->dpy(), w->id(), xid);
02931       w->raise ();
02932     }
02933   }
02934 }
02935 
02936 /* Start up the launcher */
02937 void UnityScreen::initLauncher()
02938 {
02939   Timer timer;
02940   launcher_controller_ = std::make_shared<launcher::Controller>(screen->dpy());
02941   AddChild(launcher_controller_.get());
02942 
02943   switcher_controller_ = std::make_shared<switcher::Controller>();
02944   AddChild(switcher_controller_.get());
02945 
02946   LOG_INFO(logger) << "initLauncher-Launcher " << timer.ElapsedSeconds() << "s";
02947 
02948   /* Setup panel */
02949   timer.Reset();
02950   panel_controller_ = std::make_shared<panel::Controller>();
02951   AddChild(panel_controller_.get());
02952   panel_controller_->SetMenuShowTimings(optionGetMenusFadein(),
02953                                         optionGetMenusFadeout(),
02954                                         optionGetMenusDiscoveryDuration(),
02955                                         optionGetMenusDiscoveryFadein(),
02956                                         optionGetMenusDiscoveryFadeout());
02957   LOG_INFO(logger) << "initLauncher-Panel " << timer.ElapsedSeconds() << "s";
02958 
02959   /* Setup Places */
02960   dash_controller_ = std::make_shared<dash::Controller>();
02961   dash_controller_->on_realize.connect(sigc::mem_fun(this, &UnityScreen::OnDashRealized));
02962 
02963   /* Setup Hud */
02964   hud_controller_ = std::make_shared<hud::Controller>();
02965   auto hide_mode = (unity::launcher::LauncherHideMode) optionGetLauncherHideMode();
02966   hud_controller_->launcher_locked_out = (hide_mode == unity::launcher::LauncherHideMode::LAUNCHER_HIDE_NEVER);
02967   hud_controller_->multiple_launchers = (optionGetNumLaunchers() == 0);
02968   hud_controller_->icon_size = launcher_controller_->options()->icon_size();
02969   hud_controller_->tile_size = launcher_controller_->options()->tile_size();
02970   AddChild(hud_controller_.get());
02971   LOG_INFO(logger) << "initLauncher-hud " << timer.ElapsedSeconds() << "s";
02972 
02973   // Setup Shortcut Hint
02974   InitHints();
02975   shortcut_controller_ = std::make_shared<shortcut::Controller>(hints_);
02976   AddChild(shortcut_controller_.get());
02977 
02978   AddChild(dash_controller_.get());
02979 
02980   ScheduleRelayout(0);
02981 }
02982 
02983 void UnityScreen::InitHints()
02984 {
02985   // TODO move category text into a vector...
02986 
02987   // Launcher...
02988   std::string const launcher(_("Launcher"));
02989 
02990   hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", _(" (Press)"), _("Open Launcher, displays shortcuts."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher" ));
02991   hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", "", _("Open Launcher keyboard navigation mode."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "keyboard_focus"));
02992   hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", "", _("Switch applications via Launcher."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "launcher_switcher_forward"));
02993   hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", _(" + 1 to 9"), _("Same as clicking on a Launcher icon."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
02994   hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", _(" + Shift + 1 to 9"), _("Open new window of the app."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
02995   hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", " + T", _("Open the Trash."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
02996 
02997   // Dash...
02998   std::string const dash( _("Dash"));
02999 
03000   hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", _(" (Tap)"), _("Open the Dash Home."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
03001   hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + A", _("Open the Dash App Lens."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
03002   hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + F", _("Open the Dash Files Lens."), shortcut::COMPIZ_KEY_OPTION,"unityshell", "show_launcher"));
03003   hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + M", _("Open the Dash Music Lens."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher"));
03004   hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", "", _("Switches between Lenses."), shortcut::HARDCODED_OPTION, _("Ctrl + Tab")));
03005   hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", "", _("Moves the focus."), shortcut::HARDCODED_OPTION, _("Cursor Keys")));
03006   hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", "", _("Open currently focused item."), shortcut::HARDCODED_OPTION, _("Enter & Return")));
03007 
03008   // Menu Bar
03009   std::string const menubar(_("HUD & Menu Bar"));
03010 
03011   hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", _(" (Tap)"), _("Open the HUD."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_hud"));
03012   hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", _(" (Press)"), _("Reveals application menu."), shortcut::HARDCODED_OPTION, "Alt"));
03013   hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", "", _("Opens the indicator menu."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "panel_first_menu"));
03014   hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", "", _("Moves focus between indicators."), shortcut::HARDCODED_OPTION, _("Cursor Left or Right")));
03015 
03016   // Switching
03017   std::string const switching(_("Switching"));
03018 
03019   hints_.push_back(std::make_shared<shortcut::Hint>(switching, "", "", _("Switch between applications."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "alt_tab_forward"));
03020   hints_.push_back(std::make_shared<shortcut::Hint>(switching, "", "", _("Switch windows of current application."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "alt_tab_next_window"));
03021   hints_.push_back(std::make_shared<shortcut::Hint>(switching, "", "", _("Moves the focus."), shortcut::HARDCODED_OPTION, _("Cursor Left or Right")));
03022 
03023   // Workspaces
03024   std::string const workspaces(_("Workspaces"));
03025 
03026   hints_.push_back(std::make_shared<shortcut::Hint>(workspaces, "", "", _("Spread workspaces."), shortcut::COMPIZ_KEY_OPTION, "expo", "expo_key"));
03027   hints_.push_back(std::make_shared<shortcut::Hint>(workspaces, "",  _(" + Cursor Keys"), _("Switch workspaces."), shortcut::COMPIZ_METAKEY_OPTION, "wall", "left_key"));
03028   hints_.push_back(std::make_shared<shortcut::Hint>(workspaces, "",  _(" + Cursor Keys"), _("Move focused window to different workspace."), shortcut::COMPIZ_METAKEY_OPTION, "wall", "left_window_key"));
03029 
03030   // Windows
03031   std::string const windows(_("Windows"));
03032   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Spreads all windows in the current workspace."), shortcut::COMPIZ_KEY_OPTION, "scale", "initiate_all_key"));
03033   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Minimises all windows."), shortcut::COMPIZ_KEY_OPTION, "core", "show_desktop_key"));
03034   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Maximises the current window."), shortcut::COMPIZ_KEY_OPTION, "core", "maximize_window_key"));
03035   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Restores or minimises current window."), shortcut::COMPIZ_KEY_OPTION, "core", "unmaximize_window_key"));
03036   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" or Right"), _("Semi-maximises current window."), shortcut::COMPIZ_KEY_OPTION, "grid", "put_left_key"));
03037   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Closes current window."), shortcut::COMPIZ_KEY_OPTION, "core", "close_window_key"));
03038   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Opens window accessibility menu."), shortcut::HARDCODED_OPTION, _("Alt + Space")));
03039   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Places window in corresponding positions."), shortcut::HARDCODED_OPTION, _("Ctrl + Alt + Num")));
03040   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" Drag"), _("Move window."), shortcut::COMPIZ_MOUSE_OPTION, "move", "initiate_button"));
03041   hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" Drag"), _("Resize window."), shortcut::COMPIZ_MOUSE_OPTION, "resize", "initiate_button"));
03042 }
03043 
03044 /* Window init */
03045 UnityWindow::UnityWindow(CompWindow* window)
03046   : BaseSwitchWindow (dynamic_cast<BaseSwitchScreen *> (UnityScreen::get (screen)), window)
03047   , PluginClassHandler<UnityWindow, CompWindow>(window)
03048   , window(window)
03049   , gWindow(GLWindow::get(window))
03050   , mMinimizeHandler()
03051   , mShowdesktopHandler(nullptr)
03052 {
03053   WindowInterface::setHandler(window);
03054   GLWindowInterface::setHandler(gWindow);
03055 
03056   if (UnityScreen::get (screen)->optionGetShowMinimizedWindows () &&
03057       window->mapNum ())
03058   {
03059     bool wasMinimized = window->minimized ();
03060     if (wasMinimized)
03061       window->unminimize ();
03062     window->minimizeSetEnabled (this, true);
03063     window->unminimizeSetEnabled (this, true);
03064     window->minimizedSetEnabled (this, true);
03065 
03066     if (wasMinimized)
03067       window->minimize ();
03068   }
03069   else
03070   {
03071     window->minimizeSetEnabled (this, false);
03072     window->unminimizeSetEnabled (this, false);
03073     window->minimizedSetEnabled (this, false);
03074   }
03075 
03076   if (window->state () & CompWindowStateFullscreenMask)
03077     UnityScreen::get (screen)->fullscreen_windows_.push_back(window);
03078 
03079   /* We might be starting up so make sure that
03080    * we don't deref the dashcontroller that doesnt
03081    * exist */
03082   dash::Controller::Ptr dp = UnityScreen::get(screen)->dash_controller_;
03083 
03084   if (dp)
03085   {
03086     nux::BaseWindow* w = dp->window ();
03087 
03088     if (w)
03089     {
03090       if (window->resName() == "onboard")
03091       {
03092         Window xid = dp->window()->GetInputWindowId();
03093         XSetTransientForHint (screen->dpy(), window->id(), xid);
03094       }
03095     }
03096   }
03097 }
03098 
03099 UnityWindow::~UnityWindow()
03100 {
03101   UnityScreen* us = UnityScreen::get(screen);
03102   if (us->newFocusedWindow && (UnityWindow::get(us->newFocusedWindow) == this))
03103     us->newFocusedWindow = NULL;
03104 
03105   if (!window->destroyed ())
03106   {
03107     bool wasMinimized = window->minimized ();
03108     if (wasMinimized)
03109       window->unminimize ();
03110     window->focusSetEnabled (this, false);
03111     window->minimizeSetEnabled (this, false);
03112     window->unminimizeSetEnabled (this, false);
03113     if (wasMinimized)
03114       window->minimize ();
03115   }
03116 
03117   ShowdesktopHandler::animating_windows.remove (static_cast <ShowdesktopHandlerWindowInterface *> (this));
03118 
03119   if (mShowdesktopHandler)
03120     delete mShowdesktopHandler;
03121 
03122   if (window->state () & CompWindowStateFullscreenMask)
03123     UnityScreen::get (screen)->fullscreen_windows_.remove(window);
03124 
03125   PluginAdapter::Default ()->OnWindowClosed (window);
03126 }
03127 
03128 /* vtable init */
03129 bool UnityPluginVTable::init()
03130 {
03131   if (!CompPlugin::checkPluginABI("core", CORE_ABIVERSION))
03132     return false;
03133   if (!CompPlugin::checkPluginABI("composite", COMPIZ_COMPOSITE_ABI))
03134     return false;
03135   if (!CompPlugin::checkPluginABI("opengl", COMPIZ_OPENGL_ABI))
03136     return false;
03137 
03138   /*
03139    * GTK needs to be initialized or else unity's gdk/gtk calls will crash.
03140    * This is already done in compiz' main() if using ubuntu packages, but not
03141    * if you're using the regular (upstream) compiz.
03142    * Admittedly this is the same as what the "gtkloader" plugin does. But it
03143    * is faster, more efficient (one less plugin in memory), and more reliable
03144    * to do the init here where its needed. And yes, init'ing multiple times is
03145    * safe, and does nothing after the first init.
03146    */
03147   if (!gtk_init_check(&programArgc, &programArgv))
03148   {
03149     compLogMessage("unityshell", CompLogLevelError, "GTK init failed\n");
03150     return false;
03151   }
03152 
03153   return true;
03154 }
03155 
03156 
03157 namespace
03158 {
03159 
03160 void reset_glib_logging()
03161 {
03162   // Reinstate the default glib logger.
03163   g_log_set_default_handler(g_log_default_handler, NULL);
03164 }
03165 
03166 void configure_logging()
03167 {
03168   // The default behaviour of the logging infrastructure is to send all output
03169   // to std::cout for warning or above.
03170 
03171   // TODO: write a file output handler that keeps track of backups.
03172   nux::logging::configure_logging(::getenv("UNITY_LOG_SEVERITY"));
03173   g_log_set_default_handler(capture_g_log_calls, NULL);
03174 }
03175 
03176 /* Checks whether an extension is supported by the GLX or OpenGL implementation
03177  * given the extension name and the list of supported extensions. */
03178 gboolean is_extension_supported(const gchar* extensions, const gchar* extension)
03179 {
03180   if (extensions != NULL && extension != NULL)
03181   {
03182     const gsize len = strlen(extension);
03183     gchar* p = (gchar*) extensions;
03184     gchar* end = p + strlen(p);
03185 
03186     while (p < end)
03187     {
03188       const gsize size = strcspn(p, " ");
03189       if (len == size && strncmp(extension, p, size) == 0)
03190         return TRUE;
03191       p += size + 1;
03192     }
03193   }
03194 
03195   return FALSE;
03196 }
03197 
03198 /* Gets the OpenGL version as a floating-point number given the string. */
03199 gfloat get_opengl_version_f32(const gchar* version_string)
03200 {
03201   gfloat version = 0.0f;
03202   gint32 i;
03203 
03204   for (i = 0; isdigit(version_string[i]); i++)
03205     version = version * 10.0f + (version_string[i] - 48);
03206 
03207   if ((version_string[i] == '.' || version_string[i] == ',') &&
03208       isdigit(version_string[i + 1]))
03209   {
03210     version = version * 10.0f + (version_string[i + 1] - 48);
03211     return (version + 0.1f) * 0.1f;
03212   }
03213   else
03214     return 0.0f;
03215 }
03216 
03217 nux::logging::Level glog_level_to_nux(GLogLevelFlags log_level)
03218 {
03219   // For some weird reason, ERROR is more critical than CRITICAL in gnome.
03220   if (log_level & G_LOG_LEVEL_ERROR)
03221     return nux::logging::Critical;
03222   if (log_level & G_LOG_LEVEL_CRITICAL)
03223     return nux::logging::Error;
03224   if (log_level & G_LOG_LEVEL_WARNING)
03225     return nux::logging::Warning;
03226   if (log_level & G_LOG_LEVEL_MESSAGE ||
03227       log_level & G_LOG_LEVEL_INFO)
03228     return nux::logging::Info;
03229   // default to debug.
03230   return nux::logging::Debug;
03231 }
03232 
03233 void capture_g_log_calls(const gchar* log_domain,
03234                          GLogLevelFlags log_level,
03235                          const gchar* message,
03236                          gpointer user_data)
03237 {
03238   // If nothing else, all log messages from unity should be identified as such
03239   std::string module("unity");
03240   if (log_domain)
03241   {
03242     module += std::string(".") + log_domain;
03243   }
03244   nux::logging::Logger logger(module);
03245   nux::logging::Level level = glog_level_to_nux(log_level);
03246   if (level >= logger.GetEffectiveLogLevel())
03247   {
03248     nux::logging::LogStream(level, logger.module(), "<unknown>", 0).stream()
03249         << message;
03250     if (level >= nux::logging::Error)
03251     {
03252       nux::logging::Backtrace();
03253     }
03254   }
03255 }
03256 
03257 } // anonymous namespace
03258 } // namespace unity