Back to index

unity  6.0.0
PluginAdapterCompiz.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2010 Canonical Ltd
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Authored by: Jason Smith <jason.smith@canonical.com>
00018  */
00019 
00020 #include <glib.h>
00021 #include <sstream>
00022 #include "PluginAdapter.h"
00023 #include "UScreen.h"
00024 
00025 #include <NuxCore/Logger.h>
00026 #include <UnityCore/Variant.h>
00027 
00028 namespace
00029 {
00030 
00031 nux::logging::Logger logger("unity.plugin");
00032 
00033 const int THRESHOLD_HEIGHT = 600;
00034 const int THRESHOLD_WIDTH = 1024;
00035 
00036 }
00037 
00038 PluginAdapter* PluginAdapter::_default = 0;
00039 
00040 #define MAXIMIZABLE (CompWindowActionMaximizeHorzMask & CompWindowActionMaximizeVertMask & CompWindowActionResizeMask)
00041 
00042 #define MWM_HINTS_FUNCTIONS     (1L << 0)
00043 #define MWM_HINTS_DECORATIONS   (1L << 1)
00044 #define MWM_HINTS_UNDECORATED_UNITY 0x80
00045 #define _XA_MOTIF_WM_HINTS    "_MOTIF_WM_HINTS"
00046 
00047 /* static */
00048 PluginAdapter*
00049 PluginAdapter::Default()
00050 {
00051   if (!_default)
00052     return 0;
00053   return _default;
00054 }
00055 
00056 /* static */
00057 void
00058 PluginAdapter::Initialize(CompScreen* screen)
00059 {
00060   _default = new PluginAdapter(screen);
00061 }
00062 
00063 PluginAdapter::PluginAdapter(CompScreen* screen) :
00064   m_Screen(screen),
00065   m_ExpoActionList(0),
00066   m_ScaleActionList(0),
00067   _in_show_desktop (false),
00068   _last_focused_window(nullptr)
00069 {
00070   _spread_state = false;
00071   _spread_windows_state = false;
00072   _expo_state = false;
00073   _vp_switch_started = false;
00074 
00075   _grab_show_action = 0;
00076   _grab_hide_action = 0;
00077   _grab_toggle_action = 0;
00078   _coverage_area_before_automaximize = 0.75;
00079   bias_active_to_viewport = false;
00080 }
00081 
00082 PluginAdapter::~PluginAdapter()
00083 {
00084 }
00085 
00086 /* A No-op for now, but could be useful later */
00087 void
00088 PluginAdapter::OnScreenGrabbed()
00089 {
00090   compiz_screen_grabbed.emit();
00091 
00092   if (!_spread_state && screen->grabExist("scale"))
00093   {
00094     _spread_state = true;
00095     initiate_spread.emit();
00096   }
00097 
00098   if (!_expo_state && screen->grabExist("expo"))
00099   {
00100     _expo_state = true;
00101     initiate_expo.emit();
00102   }
00103 }
00104 
00105 void
00106 PluginAdapter::OnScreenUngrabbed()
00107 {
00108   if (_spread_state && !screen->grabExist("scale"))
00109   {
00110     _spread_state = false;
00111     _spread_windows_state = false;
00112     terminate_spread.emit();
00113   }
00114 
00115   if (_expo_state && !screen->grabExist("expo"))
00116   {
00117     _expo_state = false;
00118     terminate_expo.emit();
00119   }
00120 
00121   compiz_screen_ungrabbed.emit();
00122 }
00123 
00124 void
00125 PluginAdapter::NotifyResized(CompWindow* window, int x, int y, int w, int h)
00126 {
00127   window_resized.emit(window->id());
00128 }
00129 
00130 void
00131 PluginAdapter::NotifyMoved(CompWindow* window, int x, int y)
00132 {
00133   window_moved.emit(window->id());
00134 }
00135 
00136 void
00137 PluginAdapter::NotifyStateChange(CompWindow* window, unsigned int state, unsigned int last_state)
00138 {
00139   if (!((last_state & MAXIMIZE_STATE) == MAXIMIZE_STATE)
00140       && ((state & MAXIMIZE_STATE) == MAXIMIZE_STATE))
00141   {
00142     WindowManager::window_maximized.emit(window->id());
00143   }
00144   else if (((last_state & MAXIMIZE_STATE) == MAXIMIZE_STATE)
00145            && !((state & MAXIMIZE_STATE) == MAXIMIZE_STATE))
00146   {
00147     WindowManager::window_restored.emit(window->id());
00148   }
00149 }
00150 
00151 void
00152 PluginAdapter::NotifyNewDecorationState(guint32 xid)
00153 {
00154   bool wasTracked = (_window_decoration_state.find (xid) != _window_decoration_state.end ());
00155   bool wasDecorated = false;
00156 
00157   if (wasTracked)
00158     wasDecorated = _window_decoration_state[xid];
00159 
00160   bool decorated = IsWindowDecorated (xid);
00161 
00162   if (decorated == wasDecorated)
00163     return;
00164 
00165   if (decorated && (!wasDecorated || !wasTracked))
00166     WindowManager::window_decorated.emit(xid);
00167   else if (wasDecorated || !wasTracked)
00168     WindowManager::window_undecorated.emit(xid);
00169 }
00170 
00171 void
00172 PluginAdapter::Notify(CompWindow* window, CompWindowNotify notify)
00173 {
00174   switch (notify)
00175   {
00176     case CompWindowNotifyMinimize:
00177       window_minimized.emit(window->id());
00178       break;
00179     case CompWindowNotifyUnminimize:
00180       window_unminimized.emit(window->id());
00181       break;
00182     case CompWindowNotifyShade:
00183       window_shaded.emit(window->id());
00184       break;
00185     case CompWindowNotifyUnshade:
00186       window_unshaded.emit(window->id());
00187       break;
00188     case CompWindowNotifyHide:
00189       window_hidden.emit(window->id());
00190       break;
00191     case CompWindowNotifyShow:
00192       window_shown.emit(window->id());
00193       break;
00194     case CompWindowNotifyMap:
00195       WindowManager::window_mapped.emit(window->id());
00196       break;
00197     case CompWindowNotifyUnmap:
00198       WindowManager::window_unmapped.emit(window->id());
00199       break;
00200     case CompWindowNotifyFocusChange:
00201       WindowManager::window_focus_changed.emit(window->id());
00202       break;
00203     default:
00204       break;
00205   }
00206 }
00207 
00208 void
00209 PluginAdapter::NotifyCompizEvent(const char* plugin, const char* event, CompOption::Vector& option)
00210 {
00211   if (g_strcmp0(event, "start_viewport_switch") == 0)
00212   {
00213     _vp_switch_started = true;
00214     compiz_screen_viewport_switch_started.emit();
00215   }
00216   else if (g_strcmp0(event, "end_viewport_switch") == 0)
00217   {
00218     _vp_switch_started = false;
00219     compiz_screen_viewport_switch_ended.emit();
00220   }
00221 
00222   compiz_event.emit(plugin, event, option);
00223 }
00224 
00225 void
00226 MultiActionList::AddNewAction(CompAction* a, bool primary)
00227 {
00228   if (std::find(m_ActionList.begin(), m_ActionList.end(), a)  == m_ActionList.end())
00229     m_ActionList.push_back(a);
00230 
00231   if (primary)
00232     _primary_action = a;
00233 }
00234 
00235 void
00236 MultiActionList::RemoveAction(CompAction* a)
00237 {
00238   m_ActionList.remove(a);
00239 }
00240 
00241 void
00242 MultiActionList::InitiateAll(CompOption::Vector& extraArgs, int state)
00243 {
00244   CompOption::Vector argument;
00245   if (!m_ActionList.size())
00246     return;
00247 
00248   argument.resize(1);
00249   argument[0].setName("root", CompOption::TypeInt);
00250   argument[0].value().set((int) screen->root());
00251   foreach(CompOption & arg, extraArgs)
00252   {
00253     argument.push_back(arg);
00254   }
00255 
00256   CompAction* a;
00257 
00258   if (_primary_action)
00259     a = _primary_action;
00260   else
00261     a = m_ActionList.front();
00262 
00263   /* Initiate the first available action with the arguments */
00264   a->initiate()(a, state, argument);
00265 }
00266 
00267 void
00268 MultiActionList::TerminateAll(CompOption::Vector& extraArgs)
00269 {
00270   CompOption::Vector argument;
00271   CompOption::Value  value;
00272   if (!m_ActionList.size())
00273     return;
00274 
00275   argument.resize(1);
00276   argument[0].setName("root", CompOption::TypeInt);
00277   argument[0].value().set((int) screen->root());
00278 
00279   foreach(CompOption & a, extraArgs)
00280   argument.push_back(a);
00281 
00282   if (_primary_action)
00283   {
00284     _primary_action->terminate()(_primary_action, 0, argument);
00285     return;
00286   }
00287 
00288   foreach(CompAction * action, m_ActionList)
00289   {
00290     if (action->state() & (CompAction::StateTermKey |
00291                            CompAction::StateTermButton |
00292                            CompAction::StateTermEdge |
00293                            CompAction::StateTermEdgeDnd))
00294     {
00295       action->terminate()(action, 0, argument);
00296     }
00297   }
00298 }
00299 
00300 unsigned long long
00301 PluginAdapter::GetWindowActiveNumber (guint32 xid)
00302 {
00303   Window win = xid;
00304   CompWindow* window;
00305 
00306   window = m_Screen->findWindow(win);
00307 
00308   if (window)
00309   {
00310     // result is actually an unsigned int (32 bits)
00311     unsigned long long result = window->activeNum ();
00312     if (bias_active_to_viewport() && window->defaultViewport() == m_Screen->vp())
00313       result = result << 32;
00314 
00315     return result;
00316   }
00317 
00318   return 0;
00319 }
00320 
00321 void
00322 PluginAdapter::SetExpoAction(MultiActionList& expo)
00323 {
00324   m_ExpoActionList = expo;
00325 }
00326 
00327 void
00328 PluginAdapter::SetScaleAction(MultiActionList& scale)
00329 {
00330   m_ScaleActionList = scale;
00331 }
00332 
00333 std::string
00334 PluginAdapter::MatchStringForXids(std::vector<Window> *windows)
00335 {
00336   std::ostringstream sout;
00337 
00338   sout << "any & (";
00339 
00340   std::vector<Window>::iterator it;
00341   for (it = windows->begin(); it != windows->end(); ++it)
00342   {
00343     sout << "| xid=" << static_cast<int>(*it) << " ";
00344   }
00345   sout << ")";
00346 
00347   return sout.str();
00348 }
00349 
00350 void
00351 PluginAdapter::InitiateScale(std::string const& match, int state)
00352 {
00353   CompOption::Vector argument;
00354   CompMatch      m(match);
00355 
00356   argument.resize(1);
00357   argument[0].setName("match", CompOption::TypeMatch);
00358   argument[0].value().set(m);
00359 
00360   m_ScaleActionList.InitiateAll(argument, state);
00361 }
00362 
00363 void
00364 PluginAdapter::TerminateScale()
00365 {
00366   CompOption::Vector argument(0);
00367   m_ScaleActionList.TerminateAll(argument);
00368 }
00369 
00370 bool
00371 PluginAdapter::IsScaleActive()
00372 {
00373   return m_Screen->grabExist("scale");
00374 }
00375 
00376 bool
00377 PluginAdapter::IsScaleActiveForGroup()
00378 {
00379   return _spread_windows_state && m_Screen->grabExist("scale");
00380 }
00381 
00382 bool
00383 PluginAdapter::IsExpoActive()
00384 {
00385   return m_Screen->grabExist("expo");
00386 }
00387 
00388 void
00389 PluginAdapter::InitiateExpo()
00390 {
00391   CompOption::Vector argument(0);
00392 
00393   m_ExpoActionList.InitiateAll(argument, 0);
00394 }
00395 
00396 // WindowManager implementation
00397 guint32
00398 PluginAdapter::GetActiveWindow()
00399 {
00400   return m_Screen->activeWindow();
00401 }
00402 
00403 bool
00404 PluginAdapter::IsWindowMaximized(guint xid)
00405 {
00406   Window win = xid;
00407   CompWindow* window;
00408 
00409   window = m_Screen->findWindow(win);
00410   if (window)
00411   {
00412     return ((window->state() & MAXIMIZE_STATE) == MAXIMIZE_STATE);
00413   }
00414 
00415   return false;
00416 }
00417 
00418 bool
00419 PluginAdapter::IsWindowDecorated(guint32 xid)
00420 {
00421   Display* display = m_Screen->dpy();
00422   Window win = xid;
00423   Atom hints_atom = None;
00424   MotifWmHints* hints = NULL;
00425   Atom type = None;
00426   gint format;
00427   gulong nitems;
00428   gulong bytes_after;
00429   bool ret = true;
00430 
00431   hints_atom = XInternAtom(display, _XA_MOTIF_WM_HINTS, false);
00432 
00433   if (XGetWindowProperty(display, win, hints_atom, 0,
00434                          sizeof(MotifWmHints) / sizeof(long), False,
00435                          hints_atom, &type, &format, &nitems, &bytes_after,
00436                          (guchar**)&hints) != Success)
00437     return false;
00438 
00439   if (!hints)
00440     return ret;
00441 
00442   /* Check for the presence of the high bit
00443    * if present, it means that we undecorated
00444    * this window, so don't mark it as undecorated */
00445   if (type == hints_atom && format != 0 &&
00446       hints->flags & MWM_HINTS_DECORATIONS)
00447   {
00448     /* Must have both bits set */
00449     _window_decoration_state[xid] = ret =
00450           (hints->decorations & (MwmDecorAll | MwmDecorTitle))  ||
00451           (hints->decorations & MWM_HINTS_UNDECORATED_UNITY);
00452   }
00453 
00454   XFree(hints);
00455   return ret;
00456 }
00457 
00458 bool
00459 PluginAdapter::IsWindowOnCurrentDesktop(guint32 xid)
00460 {
00461   Window win = xid;
00462   CompWindow* window;
00463 
00464   window = m_Screen->findWindow(win);
00465   if (window)
00466   {
00467     // we aren't checking window->onCurrentDesktop (), as the name implies, because that is broken
00468     return (window->defaultViewport() == m_Screen->vp());
00469   }
00470 
00471   return false;
00472 }
00473 
00474 bool
00475 PluginAdapter::IsWindowObscured(guint32 xid)
00476 {
00477   Window win = xid;
00478   CompWindow* window;
00479 
00480   window = m_Screen->findWindow(win);
00481 
00482   if (window)
00483   {
00484     if (window->inShowDesktopMode())
00485       return true;
00486 
00487     CompPoint window_vp = window->defaultViewport();
00488     nux::Geometry const& win_geo = GetWindowGeometry(window->id());
00489     // Check if any windows above this one are blocking it
00490     for (CompWindow* sibling = window->next; sibling != NULL; sibling = sibling->next)
00491     {
00492       if (sibling->defaultViewport() == window_vp
00493           && !sibling->minimized()
00494           && sibling->isMapped()
00495           && sibling->isViewable()
00496           && (sibling->state() & MAXIMIZE_STATE) == MAXIMIZE_STATE
00497           && !GetWindowGeometry(sibling->id()).Intersect(win_geo).IsNull())
00498       {
00499         return true;
00500       }
00501     }
00502   }
00503 
00504   return false;
00505 }
00506 
00507 bool
00508 PluginAdapter::IsWindowMapped(guint32 xid)
00509 {
00510   Window win = xid;
00511   CompWindow* window;
00512 
00513   window = m_Screen->findWindow(win);
00514   if (window)
00515     return window->mapNum () > 0;
00516   return true;
00517 }
00518 
00519 bool
00520 PluginAdapter::IsWindowVisible(guint32 xid)
00521 {
00522   Window win = xid;
00523   CompWindow* window;
00524 
00525   window = m_Screen->findWindow(win);
00526   if (window)
00527     return !(window->state() & CompWindowStateHiddenMask) && !window->inShowDesktopMode();
00528 
00529   return false;
00530 }
00531 
00532 bool
00533 PluginAdapter::IsWindowOnTop(guint32 xid)
00534 {
00535   Window win = xid;
00536   CompWindow* window = m_Screen->findWindow(win);
00537 
00538   if (window)
00539   {
00540     if (window->inShowDesktopMode() || !window->isMapped() || !window->isViewable() || window->minimized())
00541       return false;
00542 
00543     CompPoint window_vp = window->defaultViewport();
00544     nux::Geometry const& window_vp_geo = GetWorkAreaGeometry(window->id());
00545     std::vector<Window> const& our_xids = nux::XInputWindow::NativeHandleList();
00546 
00547     for (CompWindow* sibling = window->next; sibling; sibling = sibling->next)
00548     {
00549       if (sibling->defaultViewport() == window_vp && !sibling->minimized() &&
00550           sibling->isMapped() && sibling->isViewable() && !sibling->inShowDesktopMode() &&
00551           !(sibling->state() & CompWindowStateAboveMask) &&
00552           !(sibling->type() & CompWindowTypeSplashMask) &&
00553           !(sibling->type() & CompWindowTypeDockMask) &&
00554           /* FIXME: This should be included by the above defaultViewport() check,
00555            * but it doesn't seem to work correctly when there's only one workspace
00556            * enabled, so please drop the line above when bug #996604 is fixed in
00557            * Compiz. */
00558           !window_vp_geo.Intersect(GetWindowGeometry(sibling->id())).IsNull() &&
00559           std::find(our_xids.begin(), our_xids.end(), sibling->id()) == our_xids.end())
00560       {
00561         return false;
00562       }
00563     }
00564 
00565     return true;
00566   }
00567 
00568   return false;
00569 }
00570 
00571 bool
00572 PluginAdapter::IsWindowClosable(guint32 xid)
00573 {
00574   Window win = xid;
00575   CompWindow* window;
00576 
00577   window = m_Screen->findWindow(win);
00578   if (window)
00579     return (window->actions() & CompWindowActionCloseMask);
00580 
00581   return false;
00582 }
00583 
00584 bool
00585 PluginAdapter::IsWindowMinimizable(guint32 xid)
00586 {
00587   Window win = xid;
00588   CompWindow* window;
00589 
00590   window = m_Screen->findWindow(win);
00591   if (window)
00592     return (window->actions() & CompWindowActionMinimizeMask);
00593 
00594   return false;
00595 }
00596 
00597 bool
00598 PluginAdapter::IsWindowMaximizable(guint32 xid)
00599 {
00600   Window win = xid;
00601   CompWindow* window;
00602 
00603   window = m_Screen->findWindow(win);
00604   if (window)
00605     return (window->actions() & MAXIMIZABLE);
00606 
00607   return false;
00608 }
00609 
00610 void
00611 PluginAdapter::Restore(guint32 xid)
00612 {
00613   Window win = xid;
00614   CompWindow* window;
00615 
00616   window = m_Screen->findWindow(win);
00617   if (window)
00618     window->maximize(0);
00619 }
00620 
00621 void
00622 PluginAdapter::RestoreAt(guint32 xid, int x, int y)
00623 {
00624   Window win = xid;
00625   CompWindow* window;
00626 
00627   window = m_Screen->findWindow(win);
00628   if (window && (window->state() & MAXIMIZE_STATE))
00629   {
00630     nux::Geometry new_geo(GetWindowSavedGeometry(xid));
00631     new_geo.x = x;
00632     new_geo.y = y;
00633     window->maximize(0);
00634     MoveResizeWindow(xid, new_geo);
00635   }
00636 }
00637 
00638 void
00639 PluginAdapter::Minimize(guint32 xid)
00640 {
00641   Window win = xid;
00642   CompWindow* window;
00643 
00644   window = m_Screen->findWindow(win);
00645   if (window && (window->actions() & CompWindowActionMinimizeMask))
00646     window->minimize();
00647 }
00648 
00649 void
00650 PluginAdapter::Close(guint32 xid)
00651 {
00652   Window win = xid;
00653   CompWindow* window;
00654 
00655   window = m_Screen->findWindow(win);
00656   if (window)
00657     window->close(CurrentTime);
00658 }
00659 
00660 void
00661 PluginAdapter::Activate(guint32 xid)
00662 {
00663   Window win = xid;
00664   CompWindow* window;
00665 
00666   window = m_Screen->findWindow(win);
00667   if (window)
00668     window->activate();
00669 }
00670 
00671 void
00672 PluginAdapter::Raise(guint32 xid)
00673 {
00674   Window win = xid;
00675   CompWindow* window;
00676 
00677   window = m_Screen->findWindow(win);
00678   if (window)
00679     window->raise();
00680 }
00681 
00682 void
00683 PluginAdapter::Lower(guint32 xid)
00684 {
00685   Window win = xid;
00686   CompWindow* window;
00687 
00688   window = m_Screen->findWindow(win);
00689   if (window)
00690     window->lower();
00691 }
00692 
00693 void
00694 PluginAdapter::FocusWindowGroup(std::vector<Window> window_ids, FocusVisibility focus_visibility, int monitor, bool only_top_win)
00695 {
00696   CompPoint target_vp = m_Screen->vp();
00697   CompWindow* top_window = nullptr;
00698   CompWindow* top_monitor_win = nullptr;
00699 
00700   bool any_on_current = false;
00701   bool any_mapped = false;
00702   bool any_mapped_on_current = false;
00703   bool forced_unminimize = false;
00704 
00705   /* sort the list */
00706   CompWindowList windows;
00707   for (auto win : m_Screen->clientList())
00708   {
00709     Window id = win->id();
00710     if (std::find(window_ids.begin(), window_ids.end(), id) != window_ids.end())
00711       windows.push_back(win);
00712   }
00713 
00714   /* filter based on workspace */
00715   for (CompWindow* &win : windows)
00716   {
00717     if (win->defaultViewport() == m_Screen->vp())
00718     {
00719       any_on_current = true;
00720 
00721       if (!win->minimized())
00722       {
00723         any_mapped_on_current = true;
00724       }
00725     }
00726 
00727     if (!win->minimized())
00728     {
00729       any_mapped = true;
00730     }
00731 
00732     if (any_on_current && any_mapped)
00733       break;
00734   }
00735 
00736   if (!any_on_current)
00737   {
00738     for (auto it = windows.rbegin(); it != windows.rend(); ++it)
00739     {
00740       CompWindow* win = *it;
00741       if ((any_mapped && !win->minimized()) || !any_mapped)
00742       {
00743         target_vp = win->defaultViewport();
00744         break;
00745       }
00746     }
00747   }
00748 
00749   for (CompWindow* &win : windows)
00750   {
00751     if (win->defaultViewport() == target_vp)
00752     {
00753       int win_monitor = GetWindowMonitor(win->id());
00754 
00755       /* Any window which is actually unmapped is
00756       * not going to be accessible by either switcher
00757       * or scale, so unconditionally unminimize those
00758       * windows when the launcher icon is activated */
00759       if ((focus_visibility == WindowManager::FocusVisibility::ForceUnminimizeOnCurrentDesktop &&
00760           target_vp == m_Screen->vp()) ||
00761           (focus_visibility == WindowManager::FocusVisibility::ForceUnminimizeInvisible &&
00762            win->mapNum() == 0))
00763       {
00764         top_window = win;
00765         forced_unminimize = true;
00766 
00767         if (monitor >= 0 && win_monitor == monitor)
00768           top_monitor_win = win;
00769 
00770         if (!only_top_win)
00771         {
00772           bool is_mapped = (win->mapNum() != 0);
00773           win->unminimize();
00774 
00775            /* Initially minimized windows dont get raised */
00776           if (!is_mapped)
00777             win->raise();
00778         }
00779       }
00780       else if ((any_mapped_on_current && !win->minimized()) || !any_mapped_on_current)
00781       {
00782         if (!forced_unminimize || target_vp == m_Screen->vp())
00783         {
00784           top_window = win;
00785 
00786           if (monitor >= 0 && win_monitor == monitor)
00787             top_monitor_win = win;
00788 
00789           if (!only_top_win)
00790             win->raise();
00791         }
00792       }
00793     }
00794   }
00795 
00796   if (monitor >= 0 && top_monitor_win)
00797     top_window = top_monitor_win;
00798 
00799   if (top_window)
00800   {
00801     if (only_top_win)
00802     {
00803       if (forced_unminimize)
00804         {
00805           top_window->unminimize();
00806         }
00807 
00808       top_window->raise();
00809     }
00810 
00811     top_window->activate();
00812   }
00813 }
00814 
00815 bool
00816 PluginAdapter::ScaleWindowGroup(std::vector<Window> windows, int state, bool force)
00817 {
00818   if (windows.size() > 1 || (force && windows.size() > 0))
00819   {
00820     std::string match = MatchStringForXids(&windows);
00821     InitiateScale(match, state);
00822     _spread_windows_state = true;
00823     return true;
00824   }
00825   return false;
00826 }
00827 
00828 void
00829 PluginAdapter::SetWindowIconGeometry(Window window, nux::Geometry const& geo)
00830 {
00831   long data[4];
00832 
00833   data[0] = geo.x;
00834   data[1] = geo.y;
00835   data[2] = geo.width;
00836   data[3] = geo.height;
00837 
00838   XChangeProperty(m_Screen->dpy(), window, Atoms::wmIconGeometry,
00839                   XA_CARDINAL, 32, PropModeReplace,
00840                   (unsigned char*) data, 4);
00841 }
00842 
00843 void
00844 PluginAdapter::ShowDesktop()
00845 {
00846   if (_in_show_desktop)
00847   {
00848     LOG_INFO(logger) << "Leaving show-desktop mode.";
00849     m_Screen->leaveShowDesktopMode(NULL);
00850   }
00851   else
00852   {
00853     LOG_INFO(logger) << "Entering show-desktop mode.";
00854     m_Screen->enterShowDesktopMode();
00855   }
00856 }
00857 
00858 void
00859 PluginAdapter::OnShowDesktop()
00860 {
00861   LOG_DEBUG(logger) << "Now in show desktop mode.";
00862   _in_show_desktop = true;
00863 }
00864 
00865 void
00866 PluginAdapter::OnLeaveDesktop()
00867 {
00868   LOG_DEBUG(logger) << "No longer in show desktop mode.";
00869   _in_show_desktop = false;
00870 }
00871 
00872 int
00873 PluginAdapter::GetWindowMonitor(guint32 xid) const
00874 {
00875   // FIXME, we should use window->outputDevice() but this is not UScreen friendly
00876   nux::Geometry const& geo = GetWindowGeometry(xid);
00877 
00878   if (!geo.IsNull())
00879   {
00880     int x = geo.x + geo.width/2;
00881     int y = geo.y + geo.height/2;
00882 
00883     return unity::UScreen::GetDefault()->GetMonitorAtPosition(x, y);
00884   }
00885 
00886   return -1;
00887 }
00888 
00889 nux::Geometry
00890 PluginAdapter::GetWindowGeometry(guint32 xid) const
00891 {
00892   Window win = xid;
00893   CompWindow* window;
00894   nux::Geometry geo;
00895 
00896   window = m_Screen->findWindow(win);
00897   if (window)
00898   {
00899     geo.x = window->borderRect().x();
00900     geo.y = window->borderRect().y();
00901     geo.width = window->borderRect().width();
00902     geo.height = window->borderRect().height();
00903   }
00904   return geo;
00905 }
00906 
00907 nux::Geometry
00908 PluginAdapter::GetWindowSavedGeometry(guint32 xid) const
00909 {
00910   Window win = xid;
00911   nux::Geometry geo(0, 0, 1, 1);
00912   CompWindow* window;
00913 
00914   window = m_Screen->findWindow(win);
00915   if (window)
00916   {
00917     XWindowChanges &wc = window->saveWc();
00918     geo.x = wc.x;
00919     geo.y = wc.y;
00920     geo.width = wc.width;
00921     geo.height = wc.height;
00922   }
00923 
00924   return geo;
00925 }
00926 
00927 nux::Geometry
00928 PluginAdapter::GetScreenGeometry() const
00929 {
00930   nux::Geometry geo;
00931 
00932   geo.x = 0;
00933   geo.y = 0;
00934   geo.width = m_Screen->width();
00935   geo.height = m_Screen->height();
00936 
00937   return geo;
00938 }
00939 
00940 nux::Geometry
00941 PluginAdapter::GetWorkAreaGeometry(guint32 xid) const
00942 {
00943   CompWindow* window = nullptr;
00944   unsigned int output = 0;
00945 
00946   if (xid != 0)
00947   {
00948     Window win = xid;
00949 
00950     window = m_Screen->findWindow(win);
00951     if (window)
00952     {
00953       output = window->outputDevice();
00954     }
00955   }
00956 
00957   if (xid == 0 || !window)
00958   {
00959     output = m_Screen->currentOutputDev().id();
00960   }
00961 
00962   CompRect workarea = m_Screen->getWorkareaForOutput(output);
00963 
00964   return nux::Geometry(workarea.x(), workarea.y(), workarea.width(), workarea.height());
00965 }
00966 
00967 bool
00968 PluginAdapter::CheckWindowIntersection(nux::Geometry const& region, CompWindow* window)
00969 {
00970   int intersect_types = CompWindowTypeNormalMask | CompWindowTypeDialogMask |
00971                         CompWindowTypeModalDialogMask | CompWindowTypeUtilMask;
00972 
00973   if (!window ||
00974       !(window->type() & intersect_types) ||
00975       !window->isMapped() ||
00976       !window->isViewable() ||
00977       window->state() & CompWindowStateHiddenMask)
00978     return false;
00979 
00980   if (CompRegion(window->borderRect()).intersects(CompRect(region.x, region.y, region.width, region.height)))
00981     return true;
00982 
00983   return false;
00984 }
00985 
00986 void
00987 PluginAdapter::CheckWindowIntersections (nux::Geometry const& region, bool &active, bool &any)
00988 {
00989   // prime to false so we can assume values later one
00990   active = false;
00991   any = false;
00992 
00993   CompWindowList window_list = m_Screen->windows();
00994   CompWindowList::iterator it;
00995   CompWindow* window = NULL;
00996   CompWindow* parent = NULL;
00997   int type_dialogs = CompWindowTypeDialogMask | CompWindowTypeModalDialogMask
00998                      | CompWindowTypeUtilMask;
00999 
01000 
01001   window = m_Screen->findWindow(m_Screen->activeWindow());
01002 
01003   if (window && (window->type() & type_dialogs))
01004     parent = m_Screen->findWindow(window->transientFor());
01005 
01006   if (CheckWindowIntersection(region, window) || CheckWindowIntersection(region, parent))
01007   {
01008     any = true;
01009     active = true;
01010   }
01011   else
01012   {
01013     for (it = window_list.begin(); it != window_list.end(); it++)
01014     {
01015       if (CheckWindowIntersection(region, *it))
01016       {
01017         any = true;
01018         break;
01019       }
01020     }
01021   }
01022 }
01023 
01024 int
01025 PluginAdapter::WorkspaceCount()
01026 {
01027   return m_Screen->vpSize().width() * m_Screen->vpSize().height();
01028 }
01029 
01030 void
01031 PluginAdapter::SetMwmWindowHints(Window xid, MotifWmHints* new_hints)
01032 {
01033   Display* display = m_Screen->dpy();
01034   Atom hints_atom = None;
01035   MotifWmHints* data = NULL;
01036   MotifWmHints* hints = NULL;
01037   Atom type = None;
01038   gint format;
01039   gulong nitems;
01040   gulong bytes_after;
01041 
01042   hints_atom = XInternAtom(display, _XA_MOTIF_WM_HINTS, false);
01043 
01044   if (XGetWindowProperty(display,
01045                          xid,
01046                          hints_atom, 0, sizeof(MotifWmHints) / sizeof(long),
01047                          False, AnyPropertyType, &type, &format, &nitems,
01048                          &bytes_after, (guchar**)&data) != Success)
01049   {
01050     return;
01051   }
01052 
01053   if (type != hints_atom || !data)
01054   {
01055     hints = new_hints;
01056   }
01057   else
01058   {
01059     hints = data;
01060 
01061     if (new_hints->flags & MWM_HINTS_FUNCTIONS)
01062     {
01063       hints->flags |= MWM_HINTS_FUNCTIONS;
01064       hints->functions = new_hints->functions;
01065     }
01066     if (new_hints->flags & MWM_HINTS_DECORATIONS)
01067     {
01068       hints->flags |= MWM_HINTS_DECORATIONS;
01069       hints->decorations = new_hints->decorations;
01070     }
01071   }
01072 
01073   XChangeProperty(display,
01074                   xid,
01075                   hints_atom, hints_atom, 32, PropModeReplace,
01076                   (guchar*)hints, sizeof(MotifWmHints) / sizeof(long));
01077 
01078   if (data)
01079     XFree(data);
01080 }
01081 
01082 void
01083 PluginAdapter::Decorate(guint32 xid)
01084 {
01085   MotifWmHints hints = { 0 };
01086 
01087   hints.flags = MWM_HINTS_DECORATIONS;
01088   hints.decorations = GDK_DECOR_ALL & ~(MWM_HINTS_UNDECORATED_UNITY);
01089 
01090   SetMwmWindowHints(xid, &hints);
01091 }
01092 
01093 void
01094 PluginAdapter::Undecorate(guint32 xid)
01095 {
01096   MotifWmHints hints = { 0 };
01097 
01098   /* Set the high bit to indicate that we undecorated this
01099    * window, when an application attempts to "undecorate"
01100    * the window again, this bit will be cleared */
01101   hints.flags = MWM_HINTS_DECORATIONS;
01102   hints.decorations = MWM_HINTS_UNDECORATED_UNITY;
01103 
01104   SetMwmWindowHints(xid, &hints);
01105 }
01106 
01107 bool
01108 PluginAdapter::IsScreenGrabbed()
01109 {
01110   return m_Screen->grabbed();
01111 }
01112 
01113 bool
01114 PluginAdapter::IsViewPortSwitchStarted()
01115 {
01116   return _vp_switch_started;
01117 }
01118 
01119 /* Returns true if the window was maximized */
01120 bool PluginAdapter::MaximizeIfBigEnough(CompWindow* window)
01121 {
01122   XClassHint   classHint;
01123   Status       status;
01124   std::string  win_wmclass;
01125   int          num_monitor;
01126 
01127   int          screen_width;
01128   int          screen_height;
01129   float        covering_part;
01130 
01131   if (!window)
01132     return false;
01133 
01134   if ((window->state() & MAXIMIZE_STATE) == MAXIMIZE_STATE)
01135     return false;
01136 
01137   if (window->type() != CompWindowTypeNormalMask
01138       || (window->actions() & MAXIMIZABLE) != MAXIMIZABLE)
01139     return false;
01140 
01141   status = XGetClassHint(m_Screen->dpy(), window->id(), &classHint);
01142   if (status && classHint.res_class)
01143   {
01144     win_wmclass = classHint.res_class;
01145     XFree(classHint.res_class);
01146 
01147     if (classHint.res_name)
01148       XFree(classHint.res_name);
01149   }
01150   else
01151     return false;
01152 
01153   num_monitor = window->outputDevice();
01154   CompOutput &o = m_Screen->outputDevs().at(num_monitor);
01155 
01156   screen_height = o.workArea().height();
01157   screen_width = o.workArea().width();
01158 
01159   // See bug https://bugs.launchpad.net/unity/+bug/797808
01160   if (screen_height * screen_width > THRESHOLD_HEIGHT * THRESHOLD_WIDTH)
01161     return false;
01162 
01163   // use server<parameter> because the window won't show the real parameter as
01164   // not mapped yet
01165   const XSizeHints& hints = window->sizeHints();
01166   covering_part = (float)(window->serverWidth() * window->serverHeight()) / (float)(screen_width * screen_height);
01167   if ((covering_part < _coverage_area_before_automaximize) || (covering_part > 1.0) ||
01168       (hints.flags & PMaxSize && (screen_width > hints.max_width || screen_height > hints.max_height)))
01169   {
01170     LOG_DEBUG(logger) << win_wmclass << " window size doesn't fit";
01171     return false;
01172   }
01173 
01174   window->maximize(MAXIMIZE_STATE);
01175 
01176   return true;
01177 }
01178 
01179 void
01180 PluginAdapter::ShowGrabHandles(CompWindow* window, bool use_timer)
01181 {
01182   if (!_grab_show_action || !window)
01183     return;
01184 
01185   CompOption::Vector argument;
01186 
01187   argument.resize(3);
01188   argument[0].setName("root", CompOption::TypeInt);
01189   argument[0].value().set((int) screen->root());
01190   argument[1].setName("window", CompOption::TypeInt);
01191   argument[1].value().set((int) window->id());
01192   argument[2].setName("use-timer", CompOption::TypeBool);
01193   argument[2].value().set(use_timer);
01194 
01195   /* Initiate the first available action with the arguments */
01196   _grab_show_action->initiate()(_grab_show_action, 0, argument);
01197 }
01198 
01199 void
01200 PluginAdapter::HideGrabHandles(CompWindow* window)
01201 {
01202   if (!_grab_hide_action || !window)
01203     return;
01204 
01205   CompOption::Vector argument;
01206 
01207   argument.resize(2);
01208   argument[0].setName("root", CompOption::TypeInt);
01209   argument[0].value().set((int) screen->root());
01210   argument[1].setName("window", CompOption::TypeInt);
01211   argument[1].value().set((int) window->id());
01212 
01213   /* Initiate the first available action with the arguments */
01214   _grab_hide_action->initiate()(_grab_hide_action, 0, argument);
01215 }
01216 
01217 void
01218 PluginAdapter::ToggleGrabHandles(CompWindow* window)
01219 {
01220   if (!_grab_toggle_action || !window)
01221     return;
01222 
01223   CompOption::Vector argument;
01224 
01225   argument.resize(2);
01226   argument[0].setName("root", CompOption::TypeInt);
01227   argument[0].value().set((int) screen->root());
01228   argument[1].setName("window", CompOption::TypeInt);
01229   argument[1].value().set((int) window->id());
01230 
01231   /* Initiate the first available action with the arguments */
01232   _grab_toggle_action->initiate()(_grab_toggle_action, 0, argument);
01233 }
01234 
01235 void
01236 PluginAdapter::SetCoverageAreaBeforeAutomaximize(float area)
01237 {
01238   _coverage_area_before_automaximize = area;
01239 }
01240 
01241 bool
01242 PluginAdapter::saveInputFocus()
01243 {
01244   Window      active = m_Screen->activeWindow ();
01245   CompWindow* cw = m_Screen->findWindow (active);
01246 
01247   if (cw)
01248   {
01249     _last_focused_window = cw;
01250     return true;
01251   }
01252 
01253   return false;
01254 }
01255 
01256 bool
01257 PluginAdapter::restoreInputFocus()
01258 {
01259   if (_last_focused_window)
01260   {
01261     _last_focused_window->moveInputFocusTo ();
01262     _last_focused_window = NULL;
01263     return true;
01264   }
01265   else
01266   {
01267     m_Screen->focusDefaultWindow ();
01268     return false;
01269   }
01270 
01271   return false;
01272 }
01273 
01274 void
01275 PluginAdapter::MoveResizeWindow(guint32 xid, nux::Geometry geometry)
01276 {
01277   int w, h;
01278   CompWindow* window = m_Screen->findWindow(xid);
01279 
01280   if (!window)
01281     return;
01282 
01283   if (window->constrainNewWindowSize(geometry.width, geometry.height, &w, &h))
01284   {
01285     CompRect workarea = m_Screen->getWorkareaForOutput(window->outputDevice());
01286     int dx = geometry.x + w - workarea.right() + window->border().right;
01287     int dy = geometry.y + h - workarea.bottom() + window->border().bottom;
01288 
01289     if (dx > 0)
01290       geometry.x -= dx;
01291     if (dy > 0)
01292       geometry.y -= dy;
01293 
01294     geometry.SetWidth(w);
01295     geometry.SetHeight(h);
01296   }
01297 
01298   XWindowChanges xwc;
01299   xwc.x = geometry.x;
01300   xwc.y = geometry.y;
01301   xwc.width = geometry.width;
01302   xwc.height = geometry.height;
01303 
01304   if (window->mapNum())
01305     window->sendSyncRequest();
01306 
01307   window->configureXWindow(CWX | CWY | CWWidth | CWHeight, &xwc);
01308 }
01309 
01310 void
01311 PluginAdapter::OnWindowClosed(CompWindow *w)
01312 {
01313   if (_last_focused_window == w)
01314     _last_focused_window = NULL;
01315 }
01316 
01317 void
01318 PluginAdapter::AddProperties(GVariantBuilder* builder)
01319 {
01320   unity::variant::BuilderWrapper wrapper(builder);
01321   wrapper.add(GetScreenGeometry())
01322          .add("workspace_count", WorkspaceCount())
01323          .add("active_window", GetActiveWindow())
01324          .add("screen_grabbed", IsScreenGrabbed())
01325          .add("scale_active", IsScaleActive())
01326          .add("scale_active_for_group", IsScaleActiveForGroup())
01327          .add("expo_active", IsExpoActive())
01328          .add("viewport_switch_running", IsViewPortSwitchStarted())
01329          .add("showdesktop_active", _in_show_desktop);
01330 }