diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CMakeLists.txt | 62 | ||||
-rw-r--r-- | src/action.cpp | 644 | ||||
-rw-r--r-- | src/actions.cpp | 289 | ||||
-rw-r--r-- | src/atoms.cpp | 324 | ||||
-rw-r--r-- | src/event.cpp | 1759 | ||||
-rw-r--r-- | src/icon.cpp | 46 | ||||
-rw-r--r-- | src/main.cpp | 242 | ||||
-rw-r--r-- | src/match.cpp | 744 | ||||
-rw-r--r-- | src/modifierhandler.cpp | 204 | ||||
-rw-r--r-- | src/option.cpp | 964 | ||||
-rw-r--r-- | src/output.cpp | 90 | ||||
-rw-r--r-- | src/plugin.cpp | 700 | ||||
-rw-r--r-- | src/pluginclasses.cpp | 74 | ||||
-rw-r--r-- | src/point.cpp | 100 | ||||
-rw-r--r-- | src/privateaction.h | 53 | ||||
-rw-r--r-- | src/privatematch.h | 88 | ||||
-rw-r--r-- | src/privateoption.h | 95 | ||||
-rw-r--r-- | src/privateregion.h | 44 | ||||
-rw-r--r-- | src/privatescreen.h | 427 | ||||
-rw-r--r-- | src/privatewindow.h | 296 | ||||
-rw-r--r-- | src/propertywriter.cpp | 227 | ||||
-rw-r--r-- | src/rect.cpp | 285 | ||||
-rw-r--r-- | src/region.cpp | 449 | ||||
-rw-r--r-- | src/screen.cpp | 4636 | ||||
-rw-r--r-- | src/session.cpp | 427 | ||||
-rw-r--r-- | src/size.cpp | 50 | ||||
-rw-r--r-- | src/string.cpp | 88 | ||||
-rw-r--r-- | src/timer.cpp | 140 | ||||
-rw-r--r-- | src/window.cpp | 5615 | ||||
-rw-r--r-- | src/windowgeometry.cpp | 206 |
30 files changed, 19368 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..17cad68 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,62 @@ +include (CompizBcop) + +compiz_add_bcop_targets ( + core + ${compiz_BINARY_DIR}/generated/core.xml.in + _bcop_sources +) + +include_directories ( + ${compiz_SOURCE_DIR}/include + ${compiz_BINARY_DIR} + ${compiz_BINARY_DIR}/generated + ${CMAKE_CURRENT_SOURCE_DIR} + ${COMPIZ_INCLUDE_DIRS} +) + +add_definitions ( + -DHAVE_CONFIG_H + -DPLUGINDIR=\\\"${compiz_plugindir}\\\" + -DIMAGEDIR=\\\"${compiz_imagedir}\\\" + -DMETADATADIR=\\\"${compiz_metadatadir}\\\" +) + +link_directories ( + ${COMPIZ_LINK_DIRS} +) + +add_executable (compiz + region.cpp + atoms.cpp + timer.cpp + main.cpp + actions.cpp + screen.cpp + window.cpp + action.cpp + option.cpp + string.cpp + match.cpp + pluginclasses.cpp + event.cpp + plugin.cpp + session.cpp + output.cpp + rect.cpp + size.cpp + point.cpp + windowgeometry.cpp + icon.cpp + modifierhandler.cpp + propertywriter.cpp + ${_bcop_sources} +) + +target_link_libraries ( + compiz ${COMPIZ_LIBRARIES} m pthread dl +) + +install ( + TARGETS compiz + DESTINATION ${COMPIZ_DESTDIR}${exec_prefix} +) diff --git a/src/action.cpp b/src/action.cpp new file mode 100644 index 0000000..f487ec9 --- /dev/null +++ b/src/action.cpp @@ -0,0 +1,644 @@ +/* + * Copyright © 2005 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <davidr@novell.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <compiz.h> + +#include <core/option.h> +#include <core/action.h> +#include <core/screen.h> +#include "privateaction.h" +#include "privatescreen.h" + +struct _Modifier { + const char *name; + int modifier; +} modifiers[] = { + { "<Shift>", ShiftMask }, + { "<Control>", ControlMask }, + { "<Mod1>", Mod1Mask }, + { "<Mod2>", Mod2Mask }, + { "<Mod3>", Mod3Mask }, + { "<Mod4>", Mod4Mask }, + { "<Mod5>", Mod5Mask }, + { "<Alt>", CompAltMask }, + { "<Meta>", CompMetaMask }, + { "<Super>", CompSuperMask }, + { "<Hyper>", CompHyperMask }, + { "<ModeSwitch>", CompModeSwitchMask } +}; + +#define N_MODIFIERS (sizeof (modifiers) / sizeof (struct _Modifier)) + +struct _Edge { + const char *name; + const char *modifierName; +} edges[] = { + { "Left", "<LeftEdge>" }, + { "Right", "<RightEdge>" }, + { "Top", "<TopEdge>" }, + { "Bottom", "<BottomEdge>" }, + { "TopLeft", "<TopLeftEdge>" }, + { "TopRight", "<TopRightEdge>" }, + { "BottomLeft", "<BottomLeftEdge>" }, + { "BottomRight", "<BottomRightEdge>" } +}; + +static CompString +modifiersToString (unsigned int modMask) +{ + CompString binding; + + for (unsigned int i = 0; i < N_MODIFIERS; i++) + { + if (modMask & modifiers[i].modifier) + binding += modifiers[i].name; + } + + return binding; +} + +static unsigned int +stringToModifiers (CompString str) +{ + unsigned int mods = 0; + + for (unsigned int i = 0; i < N_MODIFIERS; i++) + { + if (str.find (modifiers[i].name) != std::string::npos) + mods |= modifiers[i].modifier; + } + + return mods; +} + +static unsigned int +bindingStringToEdgeMask (CompString str) +{ + unsigned int edgeMask = 0; + + for (int i = 0; i < SCREEN_EDGE_NUM; i++) + if (str.find (edges[i].modifierName) != std::string::npos) + edgeMask |= 1 << i; + + return edgeMask; +} + +static CompString +edgeMaskToBindingString (unsigned int edgeMask) +{ + CompString binding; + int i; + + for (i = 0; i < SCREEN_EDGE_NUM; i++) + if (edgeMask & (1 << i)) + binding += edges[i].modifierName; + + return binding; +} + +CompAction::KeyBinding::KeyBinding () : + mModifiers (0), + mKeycode (0) +{ +} + +CompAction::KeyBinding::KeyBinding (const KeyBinding& k) : + mModifiers (k.mModifiers), + mKeycode (k.mKeycode) +{ +} + +CompAction::KeyBinding::KeyBinding (int keycode, unsigned int modifiers) : + mModifiers (modifiers), + mKeycode (keycode) +{ +} + +unsigned int +CompAction::KeyBinding::modifiers () const +{ + return mModifiers; +} + +int +CompAction::KeyBinding::keycode () const +{ + return mKeycode; +} + +bool +CompAction::KeyBinding::fromString (const CompString &str) +{ + CompString sStr; + unsigned int mods; + size_t pos, start = 0; + KeySym keysym; + + if (!screen) + return false; + + mods = stringToModifiers (str); + + pos = str.rfind ('>'); + if (pos != std::string::npos) + start = pos + 1; + + while (start < str.size () && !isalnum (str[start])) + start++; + + if (start == str.size ()) + { + if (mods) + { + mKeycode = 0; + mModifiers = mods; + + return true; + } + + return false; + } + + sStr = str.substr (start); + keysym = XStringToKeysym (sStr.c_str ()); + + if (keysym != NoSymbol) + { + KeyCode keycode; + + keycode = XKeysymToKeycode (screen->dpy (), keysym); + if (keycode) + { + mKeycode = keycode; + mModifiers = mods; + + return true; + } + } + + if (sStr.compare (0, 2, "0x") == 0) + { + mKeycode = strtol (sStr.c_str (), NULL, 0); + mModifiers = mods; + + return true; + } + + return false; +} + +CompString +CompAction::KeyBinding::toString () const +{ + CompString binding; + + if (!screen) + return ""; + + binding = modifiersToString (mModifiers); + + if (mKeycode != 0) + { + KeySym keysym; + char *keyname; + + keysym = XKeycodeToKeysym (screen->dpy (), mKeycode, 0); + keyname = XKeysymToString (keysym); + + if (keyname) + binding += keyname; + else + binding += compPrintf ("0x%x", mKeycode); + } + + return binding; +} + +CompAction::ButtonBinding::ButtonBinding () : + mModifiers (0), + mButton (0) +{ +} + +CompAction::ButtonBinding::ButtonBinding (const ButtonBinding& b) : + mModifiers (b.mModifiers), + mButton (b.mButton) +{ +} + +CompAction::ButtonBinding::ButtonBinding (int button, unsigned int modifiers) : + mModifiers (modifiers), + mButton (button) +{ +} + +unsigned int +CompAction::ButtonBinding::modifiers () const +{ + return mModifiers; +} + +int +CompAction::ButtonBinding::button () const +{ + return mButton; +} + +bool +CompAction::ButtonBinding::fromString (const CompString &str) +{ + unsigned int mods; + size_t pos, start = 0; + + mods = stringToModifiers (str); + + pos = str.rfind ('>'); + if (pos != std::string::npos) + start = pos + 1; + + while (start < str.size () && !isalnum (str[start])) + start++; + + if (start != str.size () && str.compare (start, 6, "Button") == 0) + { + int buttonNum; + + if (sscanf (str.substr (start + 6).c_str (), "%d", &buttonNum) == 1) + { + mButton = buttonNum; + mModifiers = mods; + + return true; + } + } + + return false; +} + +CompString +CompAction::ButtonBinding::toString () const +{ + CompString binding; + + if (!mModifiers && !mButton) + return ""; + + binding = modifiersToString (mModifiers); + binding += compPrintf ("Button%d", mButton); + + return binding; +} + +CompAction::CompAction () : + priv (new PrivateAction ()) +{ +} + +CompAction::CompAction (const CompAction & a) : + priv (new PrivateAction (*a.priv)) +{ +} + +CompAction::~CompAction () +{ + delete priv; +} + +CompAction::CallBack +CompAction::initiate () +{ + return priv->initiate; +} + +CompAction::CallBack +CompAction::terminate () +{ + return priv->terminate; +} + +void +CompAction::setInitiate (const CompAction::CallBack &initiate) +{ + priv->initiate = initiate; +} + +void +CompAction::setTerminate (const CompAction::CallBack &terminate) +{ + priv->terminate = terminate; +} + +CompAction::State +CompAction::state () +{ + return priv->state; +} + +CompAction::BindingType +CompAction::type () +{ + return priv->type; +} + +CompAction::KeyBinding & +CompAction::key () +{ + return priv->key; +} + +void +CompAction::setKey (const CompAction::KeyBinding &key) +{ + priv->key = key; + + if (key.modifiers () || key.keycode ()) + priv->type = CompAction::BindingTypeKey; + else + priv->type = CompAction::BindingTypeNone; +} + +CompAction::ButtonBinding & +CompAction::button () +{ + return priv->button; +} + +void +CompAction::setButton (const CompAction::ButtonBinding &button) +{ + priv->button = button; + + if (button.modifiers () || button.button ()) + { + if (priv->edgeMask) + priv->type = CompAction::BindingTypeEdgeButton; + else + priv->type = CompAction::BindingTypeButton; + } + else + { + priv->type = CompAction::BindingTypeNone; + } +} + +unsigned int +CompAction::edgeMask () +{ + return priv->edgeMask; +} + +void +CompAction::setEdgeMask (unsigned int edge) +{ + priv->edgeMask = edge; + + if (priv->type == CompAction::BindingTypeEdgeButton || + priv->type == CompAction::BindingTypeButton) + { + if (priv->edgeMask) + priv->type = CompAction::BindingTypeEdgeButton; + else + priv->type = CompAction::BindingTypeButton; + } +} + +bool +CompAction::bell () +{ + return priv->bell; +} + +void +CompAction::setBell (bool bell) +{ + priv->bell = bell; +} + +void +CompAction::setState (CompAction::State state) +{ + priv->state = state; +} + +void +CompAction::copyState (const CompAction &action) +{ + priv->initiate = action.priv->initiate; + priv->terminate = action.priv->terminate; + priv->state = action.priv->state; + + memcpy (&priv->priv, &action.priv->priv, sizeof (CompPrivate)); +} + +bool +CompAction::operator== (const CompAction& val) +{ + if (priv->state != val.priv->state) + return false; + if (priv->type != val.priv->type) + return false; + if (priv->key.modifiers () != val.priv->key.modifiers ()) + return false; + if (priv->key.keycode () != val.priv->key.keycode ()) + return false; + if (priv->button.modifiers () != val.priv->button.modifiers ()) + return false; + if (priv->button.button () != val.priv->button.button ()) + return false; + if (priv->bell != val.priv->bell) + return false; + if (priv->edgeMask != val.priv->edgeMask) + return false; + if (memcmp (&priv->priv, &val.priv->priv, sizeof (CompPrivate)) != 0) + return false; + + return true; +} + +CompAction & +CompAction::operator= (const CompAction &action) +{ + delete priv; + priv = new PrivateAction (*action.priv); + + return *this; +} + +bool +CompAction::keyFromString (const CompString &str) +{ + bool retval = priv->key.fromString (str); + + if (retval) + { + priv->type = CompAction::BindingTypeKey; + } + else + { + priv->type = CompAction::BindingTypeNone; + if (str == "Disabled") + retval = true; + } + + return retval; +} + +bool +CompAction::buttonFromString (const CompString &str) +{ + bool retval = priv->button.fromString (str); + + if (retval) + { + priv->edgeMask = bindingStringToEdgeMask (str); + if (priv->edgeMask) + priv->type = CompAction::BindingTypeEdgeButton; + else + priv->type = CompAction::BindingTypeButton; + } + else + { + priv->type = CompAction::BindingTypeNone; + if (str == "Disabled") + retval = true; + } + + return retval; +} + +bool +CompAction::edgeMaskFromString (const CompString &str) +{ + unsigned int edgeMask = 0; + size_t pos; + + for (int i = 0; i < SCREEN_EDGE_NUM; i++) + { + pos = 0; + while ((pos = str.find (edgeToString (i), pos)) != std::string::npos) + { + if (pos > 0 && isalnum (str[pos - 1])) + { + pos++; + continue; + } + + pos += edgeToString (i).size (); + + if (pos < str.size () && isalnum (str[pos])) + continue; + + edgeMask |= 1 << i; + } + } + + priv->edgeMask = edgeMask; + + return (edgeMask != 0 || str.empty ()); +} + +CompString +CompAction::keyToString () +{ + CompString binding; + + binding = priv->key.toString (); + if (!binding.size ()) + return "Disabled"; + + return binding; +} + +CompString +CompAction::buttonToString () +{ + CompString binding, edge; + + binding = modifiersToString (priv->button.modifiers ()); + binding += edgeMaskToBindingString (priv->edgeMask); + + binding += compPrintf ("Button%d", priv->button.button ()); + + if (!priv->button.button ()) + return "Disabled"; + + return binding; +} + +CompString +CompAction::edgeMaskToString () +{ + CompString edge; + + for (int i = 0; i < SCREEN_EDGE_NUM; i++) + { + if (priv->edgeMask & (1 << i)) + { + if (!edge.empty ()) + edge += " | "; + + edge += edgeToString (i); + } + } + + return edge; +} + + +CompString +CompAction::edgeToString (unsigned int edge) +{ + return edges[edge].name; +} + +PrivateAction::PrivateAction () : + initiate (), + terminate (), + state (0), + type (0), + key (), + button (), + bell (false), + edgeMask (0) +{ + memset (&priv, 0, sizeof (CompPrivate)); +} + +PrivateAction::PrivateAction (const PrivateAction& a) : + initiate (a.initiate), + terminate (a.terminate), + state (a.state), + type (a.type), + key (a.key), + button (a.button), + bell (a.bell), + edgeMask (a.edgeMask) +{ + memcpy (&priv, &a.priv, sizeof (CompPrivate)); +} diff --git a/src/actions.cpp b/src/actions.cpp new file mode 100644 index 0000000..8ede0cf --- /dev/null +++ b/src/actions.cpp @@ -0,0 +1,289 @@ +/* + * Copyright © 2008 Dennis Kasprzyk + * Copyright © 2007 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Dennis Kasprzyk not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Dennis Kasprzyk makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org> + * David Reveman <davidr@novell.com> + */ + +#include <core/screen.h> +#include <core/window.h> +#include <core/atoms.h> +#include "privatescreen.h" +#include "privatewindow.h" + +bool +CompScreen::closeWin (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + unsigned int time; + + xid = CompOption::getIntOptionNamed (options, "window"); + time = CompOption::getIntOptionNamed (options, "time", CurrentTime); + + w = screen->findTopLevelWindow (xid); + if (w && (w->priv->actions & CompWindowActionCloseMask)) + w->close (time); + + return true; +} + +bool +CompScreen::unmaximizeWin (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w) + w->maximize (0); + + return true; +} + +bool +CompScreen::minimizeWin (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w && (w->actions () & CompWindowActionMinimizeMask)) + w->minimize (); + + return true; +} + +bool +CompScreen::maximizeWin (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w) + w->maximize (MAXIMIZE_STATE); + + return true; +} + +bool +CompScreen::maximizeWinHorizontally (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w) + w->maximize (w->state () | CompWindowStateMaximizedHorzMask); + + return true; +} + +bool +CompScreen::maximizeWinVertically (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w) + w->maximize (w->state () | CompWindowStateMaximizedVertMask); + + return true; +} + +bool +CompScreen::showDesktop (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + if (screen->priv->showingDesktopMask == 0) + screen->enterShowDesktopMode (); + else + screen->leaveShowDesktopMode (NULL); + + return true; +} + +bool +CompScreen::raiseWin (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w) + w->raise (); + + return true; +} + +bool +CompScreen::lowerWin (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w) + w->lower (); + + return true; +} + +bool +CompScreen::windowMenu (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w && screen->priv->grabs.empty ()) + { + int x, y, button; + Time time; + + time = CompOption::getIntOptionNamed (options, "time", CurrentTime); + button = CompOption::getIntOptionNamed (options, "button", 0); + x = CompOption::getIntOptionNamed (options, "x", + w->geometry ().x ()); + y = CompOption::getIntOptionNamed (options, "y", + w->geometry ().y ()); + + screen->toolkitAction (Atoms::toolkitActionWindowMenu, + time, w->id (), button, x, y); + } + + return true; +} + +bool +CompScreen::toggleWinMaximized (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w) + { + if ((w->priv->state & MAXIMIZE_STATE) == MAXIMIZE_STATE) + w->maximize (0); + else + w->maximize (MAXIMIZE_STATE); + } + + return true; +} + +bool +CompScreen::toggleWinMaximizedHorizontally (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w) + w->maximize (w->priv->state ^ CompWindowStateMaximizedHorzMask); + + return true; +} + +bool +CompScreen::toggleWinMaximizedVertically (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w) + w->maximize (w->priv->state ^ CompWindowStateMaximizedVertMask); + + return true; +} + +bool +CompScreen::shadeWin (CompAction *action, + CompAction::State state, + CompOption::Vector &options) +{ + CompWindow *w; + Window xid; + + xid = CompOption::getIntOptionNamed (options, "window"); + + w = screen->findTopLevelWindow (xid); + if (w && (w->priv->actions & CompWindowActionShadeMask)) + { + w->priv->state ^= CompWindowStateShadedMask; + w->updateAttributes (CompStackingUpdateModeNone); + } + + return true; +} diff --git a/src/atoms.cpp b/src/atoms.cpp new file mode 100644 index 0000000..6c7310e --- /dev/null +++ b/src/atoms.cpp @@ -0,0 +1,324 @@ +/* + * Copyright © 2008 Dennis Kasprzyk + * Copyright © 2007 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Dennis Kasprzyk not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Dennis Kasprzyk makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org> + * David Reveman <davidr@novell.com> + */ + +#include <core/atoms.h> + +namespace Atoms { + Atom supported; + Atom supportingWmCheck; + + Atom utf8String; + + Atom wmName; + + Atom winType; + Atom winTypeDesktop; + Atom winTypeDock; + Atom winTypeToolbar; + Atom winTypeMenu; + Atom winTypeUtil; + Atom winTypeSplash; + Atom winTypeDialog; + Atom winTypeNormal; + Atom winTypeDropdownMenu; + Atom winTypePopupMenu; + Atom winTypeTooltip; + Atom winTypeNotification; + Atom winTypeCombo; + Atom winTypeDnd; + + Atom winOpacity; + Atom winBrightness; + Atom winSaturation; + Atom winActive; + Atom winDesktop; + + Atom workarea; + + Atom desktopViewport; + Atom desktopGeometry; + Atom currentDesktop; + Atom numberOfDesktops; + + Atom winState; + Atom winStateModal; + Atom winStateSticky; + Atom winStateMaximizedVert; + Atom winStateMaximizedHorz; + Atom winStateShaded; + Atom winStateSkipTaskbar; + Atom winStateSkipPager; + Atom winStateHidden; + Atom winStateFullscreen; + Atom winStateAbove; + Atom winStateBelow; + Atom winStateDemandsAttention; + Atom winStateDisplayModal; + + Atom winActionMove; + Atom winActionResize; + Atom winActionStick; + Atom winActionMinimize; + Atom winActionMaximizeHorz; + Atom winActionMaximizeVert; + Atom winActionFullscreen; + Atom winActionClose; + Atom winActionShade; + Atom winActionChangeDesktop; + Atom winActionAbove; + Atom winActionBelow; + + Atom wmAllowedActions; + + Atom wmStrut; + Atom wmStrutPartial; + + Atom wmUserTime; + + Atom wmIcon; + Atom wmIconGeometry; + + Atom clientList; + Atom clientListStacking; + + Atom frameExtents; + Atom frameWindow; + + Atom wmState; + Atom wmChangeState; + Atom wmProtocols; + Atom wmClientLeader; + + Atom wmDeleteWindow; + Atom wmTakeFocus; + Atom wmPing; + Atom wmSyncRequest; + + Atom wmSyncRequestCounter; + + Atom wmFullscreenMonitors; + + Atom closeWindow; + Atom wmMoveResize; + Atom moveResizeWindow; + Atom restackWindow; + + Atom showingDesktop; + + Atom xBackground[2]; + + Atom toolkitAction; + Atom toolkitActionWindowMenu; + Atom toolkitActionForceQuitDialog; + + Atom mwmHints; + + Atom xdndAware; + Atom xdndEnter; + Atom xdndLeave; + Atom xdndPosition; + Atom xdndStatus; + Atom xdndDrop; + + Atom manager; + Atom targets; + Atom multiple; + Atom timestamp; + Atom version; + Atom atomPair; + + Atom startupId; + + void init (Display *dpy) + { + supported = XInternAtom (dpy, "_NET_SUPPORTED", 0); + supportingWmCheck = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", 0); + + utf8String = XInternAtom (dpy, "UTF8_STRING", 0); + + wmName = XInternAtom (dpy, "_NET_WM_NAME", 0); + + winType = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", 0); + winTypeDesktop = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", + 0); + winTypeDock = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0); + winTypeToolbar = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", + 0); + winTypeMenu = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", 0); + winTypeUtil = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", + 0); + winTypeSplash = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", 0); + winTypeDialog = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", 0); + winTypeNormal = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", 0); + + winTypeDropdownMenu = + XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", 0); + winTypePopupMenu = + XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", 0); + winTypeTooltip = + XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", 0); + winTypeNotification = + XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NOTIFICATION", 0); + winTypeCombo = + XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_COMBO", 0); + winTypeDnd = + XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DND", 0); + + winOpacity = XInternAtom (dpy, "_NET_WM_WINDOW_OPACITY", 0); + winBrightness = XInternAtom (dpy, "_NET_WM_WINDOW_BRIGHTNESS", 0); + winSaturation = XInternAtom (dpy, "_NET_WM_WINDOW_SATURATION", 0); + + winActive = XInternAtom (dpy, "_NET_ACTIVE_WINDOW", 0); + winDesktop = XInternAtom (dpy, "_NET_WM_DESKTOP", 0); + workarea = XInternAtom (dpy, "_NET_WORKAREA", 0); + + desktopViewport = XInternAtom (dpy, "_NET_DESKTOP_VIEWPORT", 0); + desktopGeometry = XInternAtom (dpy, "_NET_DESKTOP_GEOMETRY", 0); + currentDesktop = XInternAtom (dpy, "_NET_CURRENT_DESKTOP", 0); + numberOfDesktops = XInternAtom (dpy, "_NET_NUMBER_OF_DESKTOPS", 0); + + winState = XInternAtom (dpy, "_NET_WM_STATE", 0); + winStateModal = + XInternAtom (dpy, "_NET_WM_STATE_MODAL", 0); + winStateSticky = + XInternAtom (dpy, "_NET_WM_STATE_STICKY", 0); + winStateMaximizedVert = + XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_VERT", 0); + winStateMaximizedHorz = + XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", 0); + winStateShaded = + XInternAtom (dpy, "_NET_WM_STATE_SHADED", 0); + winStateSkipTaskbar = + XInternAtom (dpy, "_NET_WM_STATE_SKIP_TASKBAR", 0); + winStateSkipPager = + XInternAtom (dpy, "_NET_WM_STATE_SKIP_PAGER", 0); + winStateHidden = + XInternAtom (dpy, "_NET_WM_STATE_HIDDEN", 0); + winStateFullscreen = + XInternAtom (dpy, "_NET_WM_STATE_FULLSCREEN", 0); + winStateAbove = + XInternAtom (dpy, "_NET_WM_STATE_ABOVE", 0); + winStateBelow = + XInternAtom (dpy, "_NET_WM_STATE_BELOW", 0); + winStateDemandsAttention = + XInternAtom (dpy, "_NET_WM_STATE_DEMANDS_ATTENTION", 0); + winStateDisplayModal = + XInternAtom (dpy, "_NET_WM_STATE_DISPLAY_MODAL", 0); + + winActionMove = XInternAtom (dpy, "_NET_WM_ACTION_MOVE", 0); + winActionResize = + XInternAtom (dpy, "_NET_WM_ACTION_RESIZE", 0); + winActionStick = + XInternAtom (dpy, "_NET_WM_ACTION_STICK", 0); + winActionMinimize = + XInternAtom (dpy, "_NET_WM_ACTION_MINIMIZE", 0); + winActionMaximizeHorz = + XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_HORZ", 0); + winActionMaximizeVert = + XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_VERT", 0); + winActionFullscreen = + XInternAtom (dpy, "_NET_WM_ACTION_FULLSCREEN", 0); + winActionClose = + XInternAtom (dpy, "_NET_WM_ACTION_CLOSE", 0); + winActionShade = + XInternAtom (dpy, "_NET_WM_ACTION_SHADE", 0); + winActionChangeDesktop = + XInternAtom (dpy, "_NET_WM_ACTION_CHANGE_DESKTOP", 0); + winActionAbove = + XInternAtom (dpy, "_NET_WM_ACTION_ABOVE", 0); + winActionBelow = + XInternAtom (dpy, "_NET_WM_ACTION_BELOW", 0); + + wmAllowedActions = XInternAtom (dpy, "_NET_WM_ALLOWED_ACTIONS", 0); + + wmStrut = XInternAtom (dpy, "_NET_WM_STRUT", 0); + wmStrutPartial = XInternAtom (dpy, "_NET_WM_STRUT_PARTIAL", 0); + + wmUserTime = XInternAtom (dpy, "_NET_WM_USER_TIME", 0); + + wmIcon = XInternAtom (dpy,"_NET_WM_ICON", 0); + wmIconGeometry = XInternAtom (dpy, "_NET_WM_ICON_GEOMETRY", 0); + + clientList = XInternAtom (dpy, "_NET_CLIENT_LIST", 0); + clientListStacking = + XInternAtom (dpy, "_NET_CLIENT_LIST_STACKING", 0); + + frameExtents = XInternAtom (dpy, "_NET_FRAME_EXTENTS", 0); + frameWindow = XInternAtom (dpy, "_NET_FRAME_WINDOW", 0); + + wmState = XInternAtom (dpy, "WM_STATE", 0); + wmChangeState = XInternAtom (dpy, "WM_CHANGE_STATE", 0); + wmProtocols = XInternAtom (dpy, "WM_PROTOCOLS", 0); + wmClientLeader = XInternAtom (dpy, "WM_CLIENT_LEADER", 0); + + wmDeleteWindow = XInternAtom (dpy, "WM_DELETE_WINDOW", 0); + wmTakeFocus = XInternAtom (dpy, "WM_TAKE_FOCUS", 0); + wmPing = XInternAtom (dpy, "_NET_WM_PING", 0); + wmSyncRequest = XInternAtom (dpy, "_NET_WM_SYNC_REQUEST", 0); + + wmSyncRequestCounter = + XInternAtom (dpy, "_NET_WM_SYNC_REQUEST_COUNTER", 0); + + wmFullscreenMonitors = + XInternAtom (dpy, "_NET_WM_FULLSCREEN_MONITORS", 0); + + closeWindow = XInternAtom (dpy, "_NET_CLOSE_WINDOW", 0); + wmMoveResize = XInternAtom (dpy, "_NET_WM_MOVERESIZE", 0); + moveResizeWindow = XInternAtom (dpy, "_NET_MOVERESIZE_WINDOW", 0); + restackWindow = XInternAtom (dpy, "_NET_RESTACK_WINDOW", 0); + + showingDesktop = XInternAtom (dpy, "_NET_SHOWING_DESKTOP", 0); + + xBackground[0] = XInternAtom (dpy, "_XSETROOT_ID", 0); + xBackground[1] = XInternAtom (dpy, "_XROOTPMAP_ID", 0); + + toolkitAction = + XInternAtom (dpy, "_COMPIZ_TOOLKIT_ACTION", 0); + toolkitActionWindowMenu = + XInternAtom (dpy, "_COMPIZ_TOOLKIT_ACTION_WINDOW_MENU", 0); + toolkitActionForceQuitDialog = + XInternAtom (dpy, "_COMPIZ_TOOLKIT_ACTION_FORCE_QUIT_DIALOG", 0); + + mwmHints = XInternAtom (dpy, "_MOTIF_WM_HINTS", 0); + + xdndAware = XInternAtom (dpy, "XdndAware", 0); + xdndEnter = XInternAtom (dpy, "XdndEnter", 0); + xdndLeave = XInternAtom (dpy, "XdndLeave", 0); + xdndPosition = XInternAtom (dpy, "XdndPosition", 0); + xdndStatus = XInternAtom (dpy, "XdndStatus", 0); + xdndDrop = XInternAtom (dpy, "XdndDrop", 0); + + manager = XInternAtom (dpy, "MANAGER", 0); + targets = XInternAtom (dpy, "TARGETS", 0); + multiple = XInternAtom (dpy, "MULTIPLE", 0); + timestamp = XInternAtom (dpy, "TIMESTAMP", 0); + version = XInternAtom (dpy, "VERSION", 0); + atomPair = XInternAtom (dpy, "ATOM_PAIR", 0); + + startupId = XInternAtom (dpy, "_NET_STARTUP_ID", 0); + } +}; diff --git a/src/event.cpp b/src/event.cpp new file mode 100644 index 0000000..f764a13 --- /dev/null +++ b/src/event.cpp @@ -0,0 +1,1759 @@ +/* + * Copyright © 2005 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <davidr@novell.com> + */ + +#include <stdlib.h> +#include <string.h> + +#include <boost/bind.hpp> +#include <boost/foreach.hpp> +#define foreach BOOST_FOREACH + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/extensions/shape.h> +#include <X11/extensions/Xrandr.h> +#include <X11/extensions/Xfixes.h> + +#include <core/core.h> +#include <core/atoms.h> +#include "privatescreen.h" +#include "privatewindow.h" + +static Window xdndWindow = None; +static Window edgeWindow = None; + + + +bool +PrivateWindow::handleSyncAlarm () +{ + if (priv->syncWait) + { + priv->syncWait = false; + + if (window->resize (priv->syncGeometry)) + { + window->windowNotify (CompWindowNotifySyncAlarm); + } + else + { + /* resizeWindow failing means that there is another pending + resize and we must send a new sync request to the client */ + window->sendSyncRequest (); + } + } + + return false; +} + + +static bool +autoRaiseTimeout (CompScreen *screen) +{ + CompWindow *w = screen->findWindow (screen->activeWindow ()); + + if (screen->autoRaiseWindow () == screen->activeWindow () || + (w && (screen->autoRaiseWindow () == w->transientFor ()))) + { + w = screen->findWindow (screen->autoRaiseWindow ()); + if (w) + w->updateAttributes (CompStackingUpdateModeNormal); + } + + return false; +} + +#define REAL_MOD_MASK (ShiftMask | ControlMask | Mod1Mask | Mod2Mask | \ + Mod3Mask | Mod4Mask | Mod5Mask | CompNoMask) + +static bool +isCallBackBinding (CompOption &option, + CompAction::BindingType type, + CompAction::State state) +{ + if (!option.isAction ()) + return false; + + if (!(option.value ().action ().type () & type)) + return false; + + if (!(option.value ().action ().state () & state)) + return false; + + return true; +} + +static bool +isInitiateBinding (CompOption &option, + CompAction::BindingType type, + CompAction::State state, + CompAction **action) +{ + if (!isCallBackBinding (option, type, state)) + return false; + + if (option.value ().action ().initiate ().empty ()) + return false; + + *action = &option.value ().action (); + + return true; +} + +static bool +isTerminateBinding (CompOption &option, + CompAction::BindingType type, + CompAction::State state, + CompAction **action) +{ + if (!isCallBackBinding (option, type, state)) + return false; + + if (option.value ().action ().terminate ().empty ()) + return false; + + *action = &option.value ().action (); + + return true; +} + +bool +PrivateScreen::triggerButtonPressBindings (CompOption::Vector &options, + XButtonEvent *event, + CompOption::Vector &arguments) +{ + CompAction::State state = CompAction::StateInitButton; + CompAction *action; + unsigned int ignored = modHandler->ignoredModMask (); + unsigned int modMask = REAL_MOD_MASK & ~ignored; + unsigned int bindMods; + unsigned int edge = 0; + + if (edgeWindow) + { + unsigned int i; + + if (event->root != root) + return false; + + if (event->window != edgeWindow) + { + if (grabs.empty () || event->window != root) + return false; + } + + for (i = 0; i < SCREEN_EDGE_NUM; i++) + { + if (edgeWindow == screenEdge[i].id) + { + edge = 1 << i; + arguments[1].value ().set ((int) activeWindow); + break; + } + } + } + + foreach (CompOption &option, options) + { + if (isInitiateBinding (option, CompAction::BindingTypeButton, state, + &action)) + { + if (action->button ().button () == (int) event->button) + { + bindMods = modHandler->virtualToRealModMask ( + action->button ().modifiers ()); + + if ((bindMods & modMask) == (event->state & modMask)) + if (action->initiate () (action, state, arguments)) + return true; + } + } + + if (edge) + { + if (isInitiateBinding (option, CompAction::BindingTypeEdgeButton, + state | CompAction::StateInitEdge, &action)) + { + if ((action->button ().button () == (int) event->button) && + (action->edgeMask () & edge)) + { + bindMods = modHandler->virtualToRealModMask ( + action->button ().modifiers ()); + + if ((bindMods & modMask) == (event->state & modMask)) + if (action->initiate () (action, state | + CompAction::StateInitEdge, + arguments)) + return true; + } + } + } + } + + return false; +} + +bool +PrivateScreen::triggerButtonReleaseBindings (CompOption::Vector &options, + XButtonEvent *event, + CompOption::Vector &arguments) +{ + CompAction::State state = CompAction::StateTermButton; + CompAction::BindingType type = CompAction::BindingTypeButton | + CompAction::BindingTypeEdgeButton; + CompAction *action; + + foreach (CompOption &option, options) + { + if (isTerminateBinding (option, type, state, &action)) + { + if (action->button ().button () == (int) event->button) + { + if (action->terminate () (action, state, arguments)) + return true; + } + } + } + + return false; +} + +bool +PrivateScreen::triggerKeyPressBindings (CompOption::Vector &options, + XKeyEvent *event, + CompOption::Vector &arguments) +{ + CompAction::State state = 0; + CompAction *action; + unsigned int modMask = REAL_MOD_MASK & ~modHandler->ignoredModMask (); + unsigned int bindMods; + + if (event->keycode == escapeKeyCode) + state = CompAction::StateCancel; + else if (event->keycode == returnKeyCode) + state = CompAction::StateCommit; + + if (state) + { + foreach (CompOption &o, options) + { + if (o.isAction ()) + { + if (!o.value ().action ().terminate ().empty ()) + o.value ().action ().terminate () (&o.value ().action (), + state, noOptions); + } + } + + if (state == CompAction::StateCancel) + return false; + } + + state = CompAction::StateInitKey; + foreach (CompOption &option, options) + { + if (isInitiateBinding (option, CompAction::BindingTypeKey, + state, &action)) + { + bindMods = modHandler->virtualToRealModMask ( + action->key ().modifiers ()); + + if (action->key ().keycode () == (int) event->keycode) + { + if ((bindMods & modMask) == (event->state & modMask)) + if (action->initiate () (action, state, arguments)) + return true; + } + else if (!xkbEvent && action->key ().keycode () == 0) + { + if (bindMods == (event->state & modMask)) + if (action->initiate () (action, state, arguments)) + return true; + } + } + } + + return false; +} + +bool +PrivateScreen::triggerKeyReleaseBindings (CompOption::Vector &options, + XKeyEvent *event, + CompOption::Vector &arguments) +{ + CompAction::State state = CompAction::StateTermKey; + CompAction *action; + unsigned int ignored = modHandler->ignoredModMask (); + unsigned int modMask = REAL_MOD_MASK & ~ignored; + unsigned int bindMods; + unsigned int mods; + + mods = modHandler->keycodeToModifiers (event->keycode); + if (!xkbEvent && !mods) + return false; + + foreach (CompOption &option, options) + { + if (isTerminateBinding (option, CompAction::BindingTypeKey, + state, &action)) + { + bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ()); + + if ((bindMods & modMask) == 0) + { + if ((unsigned int) action->key ().keycode () == + (unsigned int) event->keycode) + { + if (action->terminate () (action, state, arguments)) + return true; + } + } + else if (!xkbEvent && ((mods & modMask & bindMods) != bindMods)) + { + if (action->terminate () (action, state, arguments)) + return true; + } + } + } + + return false; +} + +bool +PrivateScreen::triggerStateNotifyBindings (CompOption::Vector &options, + XkbStateNotifyEvent *event, + CompOption::Vector &arguments) +{ + CompAction::State state; + CompAction *action; + unsigned int ignored = modHandler->ignoredModMask (); + unsigned int modMask = REAL_MOD_MASK & ~ignored; + unsigned int bindMods; + + if (event->event_type == KeyPress) + { + state = CompAction::StateInitKey; + + foreach (CompOption &option, options) + { + if (isInitiateBinding (option, CompAction::BindingTypeKey, + state, &action)) + { + if (action->key ().keycode () == 0) + { + bindMods = + modHandler->virtualToRealModMask (action->key ().modifiers ()); + + if ((event->mods & modMask & bindMods) == bindMods) + { + if (action->initiate () (action, state, arguments)) + return true; + } + } + } + } + } + else + { + state = CompAction::StateTermKey; + + foreach (CompOption &option, options) + { + if (isTerminateBinding (option, CompAction::BindingTypeKey, + state, &action)) + { + bindMods = modHandler->virtualToRealModMask (action->key ().modifiers ()); + + if ((event->mods & modMask & bindMods) != bindMods) + { + if (action->terminate () (action, state, arguments)) + return true; + } + } + } + } + + return false; +} + +static bool +isBellAction (CompOption &option, + CompAction::State state, + CompAction **action) +{ + if (option.type () != CompOption::TypeAction && + option.type () != CompOption::TypeBell) + return false; + + if (!option.value ().action ().bell ()) + return false; + + if (!(option.value ().action ().state () & state)) + return false; + + if (option.value ().action ().initiate ().empty ()) + return false; + + *action = &option.value ().action (); + + return true; +} + +static bool +triggerBellNotifyBindings (CompOption::Vector &options, + CompOption::Vector &arguments) +{ + CompAction::State state = CompAction::StateInitBell; + CompAction *action; + + foreach (CompOption &option, options) + { + if (isBellAction (option, state, &action)) + { + if (action->initiate () (action, state, arguments)) + return true; + } + } + + return false; +} + +static bool +isEdgeAction (CompOption &option, + CompAction::State state, + unsigned int edge) +{ + if (option.type () != CompOption::TypeAction && + option.type () != CompOption::TypeButton && + option.type () != CompOption::TypeEdge) + return false; + + if (!(option.value ().action ().edgeMask () & edge)) + return false; + + if (!(option.value ().action ().state () & state)) + return false; + + return true; +} + +static bool +isEdgeEnterAction (CompOption &option, + CompAction::State state, + CompAction::State delayState, + unsigned int edge, + CompAction **action) +{ + if (!isEdgeAction (option, state, edge)) + return false; + + if (option.value ().action ().type () & CompAction::BindingTypeEdgeButton) + return false; + + if (option.value ().action ().initiate ().empty ()) + return false; + + if (delayState) + { + if ((option.value ().action ().state () & + CompAction::StateNoEdgeDelay) != + (delayState & CompAction::StateNoEdgeDelay)) + { + /* ignore edge actions which shouldn't be delayed when invoking + undelayed edges (or vice versa) */ + return false; + } + } + + + *action = &option.value ().action (); + + return true; +} + +static bool +isEdgeLeaveAction (CompOption &option, + CompAction::State state, + unsigned int edge, + CompAction **action) +{ + if (!isEdgeAction (option, state, edge)) + return false; + + if (option.value ().action ().terminate ().empty ()) + return false; + + *action = &option.value ().action (); + + return true; +} + +static bool +triggerEdgeEnterBindings (CompOption::Vector &options, + CompAction::State state, + CompAction::State delayState, + unsigned int edge, + CompOption::Vector &arguments) +{ + CompAction *action; + + foreach (CompOption &option, options) + { + if (isEdgeEnterAction (option, state, delayState, edge, &action)) + { + if (action->initiate () (action, state, arguments)) + return true; + } + } + + return false; +} + +static bool +triggerEdgeLeaveBindings (CompOption::Vector &options, + CompAction::State state, + unsigned int edge, + CompOption::Vector &arguments) +{ + CompAction *action; + + foreach (CompOption &option, options) + { + if (isEdgeLeaveAction (option, state, edge, &action)) + { + if (action->terminate () (action, state, arguments)) + return true; + } + } + + return false; +} + +static bool +triggerAllEdgeEnterBindings (CompAction::State state, + CompAction::State delayState, + unsigned int edge, + CompOption::Vector &arguments) +{ + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + if (triggerEdgeEnterBindings (options, state, delayState, edge, + arguments)) + { + return true; + } + } + return false; +} + +static bool +delayedEdgeTimeout (CompDelayedEdgeSettings *settings) +{ + triggerAllEdgeEnterBindings (settings->state, + ~CompAction::StateNoEdgeDelay, + settings->edge, + settings->options); + + return false; +} + +bool +PrivateScreen::triggerEdgeEnter (unsigned int edge, + CompAction::State state, + CompOption::Vector &arguments) +{ + int delay; + + delay = optionGetEdgeDelay (); + + if (delay > 0) + { + CompAction::State delayState; + edgeDelaySettings.edge = edge; + edgeDelaySettings.state = state; + edgeDelaySettings.options = arguments; + + edgeDelayTimer.start ( + boost::bind (delayedEdgeTimeout, &edgeDelaySettings), + delay, (unsigned int) ((float) delay * 1.2)); + + delayState = CompAction::StateNoEdgeDelay; + if (triggerAllEdgeEnterBindings (state, delayState, edge, arguments)) + return true; + } + else + { + if (triggerAllEdgeEnterBindings (state, 0, edge, arguments)) + return true; + } + + return false; +} + +bool +PrivateScreen::handleActionEvent (XEvent *event) +{ + static CompOption::Vector o (8); + Window xid; + o.resize (8); + + o[0].setName ("event_window", CompOption::TypeInt); + o[1].setName ("window", CompOption::TypeInt); + o[2].setName ("modifiers", CompOption::TypeInt); + o[3].setName ("x", CompOption::TypeInt); + o[4].setName ("y", CompOption::TypeInt); + o[5].setName ("root", CompOption::TypeInt); + + switch (event->type) { + case ButtonPress: + /* We need to determine if we clicked on a parent frame + * window, if so, pass the appropriate child window as + * "window" and the frame as "event_window" + */ + + xid = event->xbutton.window; + + foreach (CompWindow *w, screen->windows ()) + { + if (w->frame () == xid) + xid = w->id (); + } + + o[0].value ().set ((int) event->xbutton.window); + o[1].value ().set ((int) xid); + o[2].value ().set ((int) event->xbutton.state); + o[3].value ().set ((int) event->xbutton.x_root); + o[4].value ().set ((int) event->xbutton.y_root); + o[5].value ().set ((int) event->xbutton.root); + + o[6].setName ("button", CompOption::TypeInt); + o[7].setName ("time", CompOption::TypeInt); + + o[6].value ().set ((int) event->xbutton.button); + o[7].value ().set ((int) event->xbutton.time); + + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + if (triggerButtonPressBindings (options, &event->xbutton, o)) + return true; + } + break; + case ButtonRelease: + o[0].value ().set ((int) event->xbutton.window); + o[1].value ().set ((int) event->xbutton.window); + o[2].value ().set ((int) event->xbutton.state); + o[3].value ().set ((int) event->xbutton.x_root); + o[4].value ().set ((int) event->xbutton.y_root); + o[5].value ().set ((int) event->xbutton.root); + + o[6].setName ("button", CompOption::TypeInt); + o[7].setName ("time", CompOption::TypeInt); + + o[6].value ().set ((int) event->xbutton.button); + o[7].value ().set ((int) event->xbutton.time); + + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + if (triggerButtonReleaseBindings (options, &event->xbutton, o)) + return true; + } + break; + case KeyPress: + o[0].value ().set ((int) event->xkey.window); + o[1].value ().set ((int) activeWindow); + o[2].value ().set ((int) event->xkey.state); + o[3].value ().set ((int) event->xkey.x_root); + o[4].value ().set ((int) event->xkey.y_root); + o[5].value ().set ((int) event->xkey.root); + + o[6].setName ("keycode", CompOption::TypeInt); + o[7].setName ("time", CompOption::TypeInt); + + o[6].value ().set ((int) event->xkey.keycode); + o[7].value ().set ((int) event->xkey.time); + + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + if (triggerKeyPressBindings (options, &event->xkey, o)) + return true; + } + break; + case KeyRelease: + o[0].value ().set ((int) event->xkey.window); + o[1].value ().set ((int) activeWindow); + o[2].value ().set ((int) event->xkey.state); + o[3].value ().set ((int) event->xkey.x_root); + o[4].value ().set ((int) event->xkey.y_root); + o[5].value ().set ((int) event->xkey.root); + + o[6].setName ("keycode", CompOption::TypeInt); + o[7].setName ("time", CompOption::TypeInt); + + o[6].value ().set ((int) event->xkey.keycode); + o[7].value ().set ((int) event->xkey.time); + + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + if (triggerKeyReleaseBindings (options, &event->xkey, o)) + return true; + } + break; + case EnterNotify: + if (event->xcrossing.mode != NotifyGrab && + event->xcrossing.mode != NotifyUngrab && + event->xcrossing.detail != NotifyInferior) + { + unsigned int edge, i; + CompAction::State state; + + if (event->xcrossing.root != root) + return false; + + if (edgeDelayTimer.active ()) + edgeDelayTimer.stop (); + + if (edgeWindow && edgeWindow != event->xcrossing.window) + { + state = CompAction::StateTermEdge; + edge = 0; + + for (i = 0; i < SCREEN_EDGE_NUM; i++) + { + if (edgeWindow == screenEdge[i].id) + { + edge = 1 << i; + break; + } + } + + edgeWindow = None; + + o[0].value ().set ((int) event->xcrossing.window); + o[1].value ().set ((int) activeWindow); + o[2].value ().set ((int) event->xcrossing.state); + o[3].value ().set ((int) event->xcrossing.x_root); + o[4].value ().set ((int) event->xcrossing.y_root); + o[5].value ().set ((int) event->xcrossing.root); + + o[6].setName ("time", CompOption::TypeInt); + o[6].value ().set ((int) event->xcrossing.time); + + o.resize (7); + + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + if (triggerEdgeLeaveBindings (options, state, edge, o)) + return true; + } + } + + edge = 0; + + for (i = 0; i < SCREEN_EDGE_NUM; i++) + { + if (event->xcrossing.window == screenEdge[i].id) + { + edge = 1 << i; + break; + } + } + + if (edge) + { + state = CompAction::StateInitEdge; + + edgeWindow = event->xcrossing.window; + + o[0].value ().set ((int) event->xcrossing.window); + o[1].value ().set ((int) activeWindow); + o[2].value ().set ((int) event->xcrossing.state); + o[3].value ().set ((int) event->xcrossing.x_root); + o[4].value ().set ((int) event->xcrossing.y_root); + o[5].value ().set ((int) event->xcrossing.root); + + o[6].setName ("time", CompOption::TypeInt); + o[6].value ().set ((int) event->xcrossing.time); + + o.resize (7); + + if (triggerEdgeEnter (edge, state, o)) + return true; + } + } + break; + case ClientMessage: + if (event->xclient.message_type == Atoms::xdndEnter) + { + xdndWindow = event->xclient.window; + } + else if (event->xclient.message_type == Atoms::xdndLeave) + { + unsigned int edge = 0; + CompAction::State state; + + if (!xdndWindow) + { + CompWindow *w; + + w = screen->findWindow (event->xclient.window); + if (w) + { + unsigned int i; + + for (i = 0; i < SCREEN_EDGE_NUM; i++) + { + if (event->xclient.window == screenEdge[i].id) + { + edge = 1 << i; + break; + } + } + } + } + + if (edge) + { + state = CompAction::StateTermEdgeDnd; + + o[0].value ().set ((int) event->xclient.window); + o[1].value ().set ((int) activeWindow); + o[2].value ().set ((int) 0); /* fixme */ + o[3].value ().set ((int) 0); /* fixme */ + o[4].value ().set ((int) 0); /* fixme */ + o[5].value ().set ((int) root); + + o.resize (6); + + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + if (triggerEdgeLeaveBindings (options, state, edge, o)) + return true; + } + } + } + else if (event->xclient.message_type == Atoms::xdndPosition) + { + unsigned int edge = 0; + CompAction::State state; + + if (xdndWindow == event->xclient.window) + { + CompWindow *w; + + w = screen->findWindow (event->xclient.window); + if (w) + { + unsigned int i; + + for (i = 0; i < SCREEN_EDGE_NUM; i++) + { + if (xdndWindow == screenEdge[i].id) + { + edge = 1 << i; + break; + } + } + } + } + + if (edge) + { + state = CompAction::StateInitEdgeDnd; + + o[0].value ().set ((int) event->xclient.window); + o[1].value ().set ((int) activeWindow); + o[2].value ().set ((int) 0); /* fixme */ + o[3].value ().set ((int) event->xclient.data.l[2] >> 16); + o[4].value ().set ((int) event->xclient.data.l[2] & 0xffff); + o[5].value ().set ((int) root); + + o.resize (6); + + if (triggerEdgeEnter (edge, state, o)) + return true; + } + + xdndWindow = None; + } + break; + default: + if (event->type == xkbEvent) + { + XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event; + + if (xkbEvent->xkb_type == XkbStateNotify) + { + XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event; + + o[0].value ().set ((int) activeWindow); + o[1].value ().set ((int) activeWindow); + o[2].value ().set ((int) stateEvent->mods); + + o[3] = CompOption ("time", CompOption::TypeInt); + o[3].value ().set ((int) xkbEvent->time); + + o.resize (4); + + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + if (triggerStateNotifyBindings (options, stateEvent, o)) + return true; + } + } + else if (xkbEvent->xkb_type == XkbBellNotify) + { + o[0].value ().set ((int) activeWindow); + o[1].value ().set ((int) activeWindow); + + o[2] = CompOption ("time", CompOption::TypeInt); + o[2].value ().set ((int) xkbEvent->time); + + o.resize (3); + + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + if (triggerBellNotifyBindings (options, o)) + return true; + } + } + } + break; + } + + return false; +} + +void +CompScreen::handleCompizEvent (const char *plugin, + const char *event, + CompOption::Vector &options) + WRAPABLE_HND_FUNC (7, handleCompizEvent, plugin, event, options) + +void +CompScreen::handleEvent (XEvent *event) +{ + WRAPABLE_HND_FUNC (6, handleEvent, event) + + CompWindow *w; + + switch (event->type) { + case ButtonPress: + if (event->xbutton.root == priv->root) + priv->setCurrentOutput ( + outputDeviceForPoint (event->xbutton.x_root, + event->xbutton.y_root)); + break; + case MotionNotify: + if (event->xmotion.root == priv->root) + priv->setCurrentOutput ( + outputDeviceForPoint (event->xmotion.x_root, + event->xmotion.y_root)); + break; + case KeyPress: + w = findWindow (priv->activeWindow); + if (w) + priv->setCurrentOutput (w->outputDevice ()); + default: + break; + } + + if (priv->handleActionEvent (event)) + { + if (priv->grabs.empty ()) + XAllowEvents (priv->dpy, AsyncPointer, event->xbutton.time); + + return; + } + + switch (event->type) { + case SelectionRequest: + priv->handleSelectionRequest (event); + break; + case SelectionClear: + priv->handleSelectionClear (event); + break; + case ConfigureNotify: + w = findWindow (event->xconfigure.window); + if (w && !w->frame ()) + { + w->priv->configure (&event->xconfigure); + } + else + { + w = findTopLevelWindow (event->xconfigure.window); + + if (w && w->frame () == event->xconfigure.window) + { + w->priv->configureFrame (&event->xconfigure); + } + else + { + if (event->xconfigure.window == priv->root) + priv->configure (&event->xconfigure); + } + } + break; + case CreateNotify: + w = findTopLevelWindow (event->xcreatewindow.window, true); + + if (event->xcreatewindow.parent == priv->root && + (!w || w->frame () != event->xcreatewindow.window)) + { + new CompWindow (event->xcreatewindow.window, priv->getTopWindow ()); + } + break; + case DestroyNotify: + w = findWindow (event->xdestroywindow.window); + if (w) + { + w->moveInputFocusToOtherWindow (); + w->destroy (); + } + break; + case MapNotify: + w = findWindow (event->xmap.window); + if (w) + { + if (w->priv->pendingMaps || zcomp) + { + if (!w->priv->frame) + w->priv->reparent (); + w->priv->managed = true; + } + + /* been shaded */ + if (w->priv->height == 0) + { + if (w->id () == priv->activeWindow) + w->moveInputFocusTo (); + } + + w->map (); + } + break; + case UnmapNotify: + w = findWindow (event->xunmap.window); + if (w) + { + /* Normal -> Iconic */ + if (w->pendingUnmaps ()) + { + priv->setWmState (IconicState, w->id ()); + w->priv->pendingUnmaps--; + } + else /* X -> Withdrawn */ + { + /* Iconic -> Withdrawn */ + if (w->state () & CompWindowStateHiddenMask) + { + w->priv->minimized = false; + + w->changeState (w->state () & ~CompWindowStateHiddenMask); + + priv->updateClientList (); + } + else /* Closing */ + w->windowNotify (CompWindowNotifyClose); + + if (!w->overrideRedirect ()) + priv->setWmState (WithdrawnState, w->id ()); + + w->priv->placed = false; + w->priv->managed = false; + if (w->priv->frame) + { + w->priv->unreparent (); + } + } + + w->unmap (); + + if (!w->shaded () && !w->priv->pendingMaps) + w->moveInputFocusToOtherWindow (); + } + break; + case ReparentNotify: + w = findWindow (event->xreparent.window); + if (!w && event->xreparent.parent == priv->root) + { + new CompWindow (event->xreparent.window, priv->getTopWindow ()); + } + else if (w && !(event->xreparent.parent == w->priv->wrapper || + event->xreparent.parent == priv->root)) + { + /* This is the only case where a window is removed but not + destroyed. We must remove our event mask and all passive + grabs. */ + XSelectInput (priv->dpy, w->id (), NoEventMask); + XShapeSelectInput (priv->dpy, w->id (), NoEventMask); + XUngrabButton (priv->dpy, AnyButton, AnyModifier, w->id ()); + + w->moveInputFocusToOtherWindow (); + + w->destroy (); + } + break; + case CirculateNotify: + w = findWindow (event->xcirculate.window); + if (w) + w->priv->circulate (&event->xcirculate); + break; + case ButtonPress: + if (event->xbutton.root == priv->root) + { + if (event->xbutton.button == Button1 || + event->xbutton.button == Button2 || + event->xbutton.button == Button3) + { + w = findTopLevelWindow (event->xbutton.window); + if (w) + { + if (priv->optionGetRaiseOnClick ()) + w->updateAttributes ( + CompStackingUpdateModeAboveFullscreen); + + if (w->id () != priv->activeWindow) + if (!(w->type () & CompWindowTypeDockMask)) + w->moveInputFocusTo (); + } + } + + if (priv->grabs.empty ()) + XAllowEvents (priv->dpy, ReplayPointer, event->xbutton.time); + } + break; + case PropertyNotify: + if (event->xproperty.atom == Atoms::winType) + { + w = findWindow (event->xproperty.window); + if (w) + { + unsigned int type; + + type = priv->getWindowType (w->id ()); + + if (type != w->wmType ()) + { + if (w->isViewable ()) + { + if (w->type () == CompWindowTypeDesktopMask) + priv->desktopWindowCount--; + else if (type == CompWindowTypeDesktopMask) + priv->desktopWindowCount++; + } + + w->wmType () = type; + + w->recalcType (); + w->recalcActions (); + + if (type & (CompWindowTypeDockMask | + CompWindowTypeDesktopMask)) + w->setDesktop (0xffffffff); + + priv->updateClientList (); + + matchPropertyChanged (w); + } + } + } + else if (event->xproperty.atom == Atoms::winState) + { + w = findWindow (event->xproperty.window); + if (w && !w->managed ()) + { + unsigned int state; + + state = priv->getWindowState (w->id ()); + state = CompWindow::constrainWindowState (state, w->actions ()); + + /* EWMH suggests that we ignore changes + to _NET_WM_STATE_HIDDEN */ + if (w->state () & CompWindowStateHiddenMask) + state |= CompWindowStateHiddenMask; + else + state &= ~CompWindowStateHiddenMask; + + w->changeState (state); + } + } + else if (event->xproperty.atom == XA_WM_NORMAL_HINTS) + { + w = findWindow (event->xproperty.window); + if (w) + { + w->priv->updateNormalHints (); + w->recalcActions (); + } + } + else if (event->xproperty.atom == XA_WM_HINTS) + { + w = findWindow (event->xproperty.window); + if (w) + w->priv->updateWmHints (); + } + else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR) + { + w = findWindow (event->xproperty.window); + if (w) + { + w->priv->updateTransientHint (); + w->recalcActions (); + } + } + else if (event->xproperty.atom == Atoms::wmClientLeader) + { + w = findWindow (event->xproperty.window); + if (w) + w->priv->clientLeader = w->priv->getClientLeader (); + } + else if (event->xproperty.atom == Atoms::wmIconGeometry) + { + w = findWindow (event->xproperty.window); + if (w) + w->priv->updateIconGeometry (); + } + else if (event->xproperty.atom == Atoms::wmStrut || + event->xproperty.atom == Atoms::wmStrutPartial) + { + w = findWindow (event->xproperty.window); + if (w) + { + if (w->updateStruts ()) + updateWorkarea (); + } + } + else if (event->xproperty.atom == Atoms::mwmHints) + { + w = findWindow (event->xproperty.window); + if (w) + w->priv->updateMwmHints (); + } + else if (event->xproperty.atom == Atoms::wmProtocols) + { + w = findWindow (event->xproperty.window); + if (w) + w->priv->protocols = priv->getProtocols (w->id ()); + } + else if (event->xproperty.atom == Atoms::wmIcon) + { + w = findWindow (event->xproperty.window); + if (w) + w->priv->freeIcons (); + } + else if (event->xproperty.atom == Atoms::startupId) + { + w = findWindow (event->xproperty.window); + if (w) + w->priv->updateStartupId (); + } + else if (event->xproperty.atom == XA_WM_CLASS) + { + w = findWindow (event->xproperty.window); + if (w) + w->priv->updateClassHints (); + } + break; + case MotionNotify: + break; + case ClientMessage: + if (event->xclient.message_type == Atoms::winActive) + { + w = findWindow (event->xclient.window); + if (w) + { + /* use focus stealing prevention if request came + from an application */ + if (event->xclient.data.l[0] != ClientTypeApplication || + w->priv->allowWindowFocus (0, event->xclient.data.l[1])) + { + w->activate (); + } + } + } + else if (event->xclient.message_type == Atoms::winState) + { + w = findWindow (event->xclient.window); + if (w) + { + unsigned long wState, state; + int i; + + wState = w->state (); + + for (i = 1; i < 3; i++) + { + state = priv->windowStateMask (event->xclient.data.l[i]); + if (state & ~CompWindowStateHiddenMask) + { + +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 + + switch (event->xclient.data.l[0]) { + case _NET_WM_STATE_REMOVE: + wState &= ~state; + break; + case _NET_WM_STATE_ADD: + wState |= state; + break; + case _NET_WM_STATE_TOGGLE: + wState ^= state; + break; + } + } + } + + wState = CompWindow::constrainWindowState (wState, + w->actions ()); + if (w->id () == priv->activeWindow) + wState &= ~CompWindowStateDemandsAttentionMask; + + if (wState != w->state ()) + { + CompStackingUpdateMode stackingUpdateMode; + unsigned long dState = wState ^ w->state (); + + stackingUpdateMode = CompStackingUpdateModeNone; + + /* raise the window whenever its fullscreen state, + above/below state or maximization state changed */ + if (dState & (CompWindowStateFullscreenMask | + CompWindowStateAboveMask | + CompWindowStateBelowMask | + CompWindowStateMaximizedHorzMask | + CompWindowStateMaximizedVertMask)) + stackingUpdateMode = CompStackingUpdateModeNormal; + + w->changeState (wState); + + w->updateAttributes (stackingUpdateMode); + } + } + } + else if (event->xclient.message_type == Atoms::wmProtocols) + { + if ((unsigned long) event->xclient.data.l[0] == Atoms::wmPing) + { + w = findWindow (event->xclient.data.l[2]); + if (w) + w->priv->handlePing (priv->lastPing); + } + } + else if (event->xclient.message_type == Atoms::closeWindow) + { + w = findWindow (event->xclient.window); + if (w) + w->close (event->xclient.data.l[0]); + } + else if (event->xclient.message_type == Atoms::desktopGeometry) + { + if (event->xclient.window == priv->root) + { + CompOption::Value value; + + value.set ((int) (event->xclient.data.l[0] / + width ())); + + setOptionForPlugin ("core", "hsize", value); + + value.set ((int) (event->xclient.data.l[1] / + height ())); + + setOptionForPlugin ("core", "vsize", value); + } + } + else if (event->xclient.message_type == Atoms::moveResizeWindow) + { + w = findWindow (event->xclient.window); + if (w) + { + unsigned int xwcm = 0; + XWindowChanges xwc; + int gravity; + unsigned int source; + + memset (&xwc, 0, sizeof (xwc)); + + if (event->xclient.data.l[0] & (1 << 8)) + { + xwcm |= CWX; + xwc.x = event->xclient.data.l[1]; + } + + if (event->xclient.data.l[0] & (1 << 9)) + { + xwcm |= CWY; + xwc.y = event->xclient.data.l[2]; + } + + if (event->xclient.data.l[0] & (1 << 10)) + { + xwcm |= CWWidth; + xwc.width = event->xclient.data.l[3]; + } + + if (event->xclient.data.l[0] & (1 << 11)) + { + xwcm |= CWHeight; + xwc.height = event->xclient.data.l[4]; + } + + gravity = event->xclient.data.l[0] & 0xFF; + source = (event->xclient.data.l[0] >> 12) & 0xF; + + w->moveResize (&xwc, xwcm, gravity, source); + } + } + else if (event->xclient.message_type == Atoms::restackWindow) + { + w = findWindow (event->xclient.window); + if (w) + { + /* TODO: other stack modes than Above and Below */ + if (event->xclient.data.l[1]) + { + CompWindow *sibling; + + sibling = findWindow (event->xclient.data.l[1]); + if (sibling) + { + if (event->xclient.data.l[2] == Above) + w->restackAbove (sibling); + else if (event->xclient.data.l[2] == Below) + w->restackBelow (sibling); + } + } + else + { + if (event->xclient.data.l[2] == Above) + w->raise (); + else if (event->xclient.data.l[2] == Below) + w->lower (); + } + } + } + else if (event->xclient.message_type == Atoms::wmChangeState) + { + w = findWindow (event->xclient.window); + if (w) + { + if (event->xclient.data.l[0] == IconicState) + { + if (w->actions () & CompWindowActionMinimizeMask) + w->minimize (); + } + else if (event->xclient.data.l[0] == NormalState) + w->unminimize (); + } + } + else if (event->xclient.message_type == Atoms::showingDesktop) + { + if (event->xclient.window == priv->root || + event->xclient.window == None) + { + if (event->xclient.data.l[0]) + enterShowDesktopMode (); + else + leaveShowDesktopMode (NULL); + } + } + else if (event->xclient.message_type == Atoms::numberOfDesktops) + { + if (event->xclient.window == priv->root) + { + CompOption::Value value; + + value.set ((int) event->xclient.data.l[0]); + + setOptionForPlugin ("core", "number_of_desktops", value); + } + } + else if (event->xclient.message_type == Atoms::currentDesktop) + { + if (event->xclient.window == priv->root) + priv->setCurrentDesktop (event->xclient.data.l[0]); + } + else if (event->xclient.message_type == Atoms::winDesktop) + { + w = findWindow (event->xclient.window); + if (w) + w->setDesktop (event->xclient.data.l[0]); + } + else if (event->xclient.message_type == Atoms::wmFullscreenMonitors) + { + w = findWindow (event->xclient.window); + if (w) + { + CompFullscreenMonitorSet monitors; + + monitors.top = event->xclient.data.l[0]; + monitors.bottom = event->xclient.data.l[1]; + monitors.left = event->xclient.data.l[2]; + monitors.right = event->xclient.data.l[3]; + + w->priv->setFullscreenMonitors (&monitors); + } + } + break; + case MappingNotify: + modHandler->updateModifierMappings (); + break; + case MapRequest: + w = findWindow (event->xmaprequest.window); + if (w) + { + XWindowAttributes attr; + bool doMapProcessing = true; + + /* We should check the override_redirect flag here, because the + client might have changed it while being unmapped. */ + if (XGetWindowAttributes (priv->dpy, w->id (), &attr)) + w->priv->setOverrideRedirect (attr.override_redirect != 0); + + if (w->state () & CompWindowStateHiddenMask) + if (!w->minimized () && !w->inShowDesktopMode ()) + doMapProcessing = false; + + if (doMapProcessing) + w->priv->processMap (); + + w->priv->managed = true; + + setWindowProp (w->id (), Atoms::winDesktop, w->desktop ()); + } + else + { + XMapWindow (priv->dpy, event->xmaprequest.window); + } + break; + case ConfigureRequest: + w = findWindow (event->xconfigurerequest.window); + if (w && w->managed ()) + { + XWindowChanges xwc; + + memset (&xwc, 0, sizeof (xwc)); + + xwc.x = event->xconfigurerequest.x; + xwc.y = event->xconfigurerequest.y; + xwc.width = event->xconfigurerequest.width; + xwc.height = event->xconfigurerequest.height; + xwc.border_width = event->xconfigurerequest.border_width; + + w->moveResize (&xwc, event->xconfigurerequest.value_mask, + 0, ClientTypeUnknown); + + if (event->xconfigurerequest.value_mask & CWStackMode) + { + Window above = None; + CompWindow *sibling = NULL; + + if (event->xconfigurerequest.value_mask & CWSibling) + { + above = event->xconfigurerequest.above; + sibling = findTopLevelWindow (above); + } + + switch (event->xconfigurerequest.detail) { + case Above: + if (w->priv->allowWindowFocus (NO_FOCUS_MASK, 0)) + { + if (above) + { + if (sibling) + w->restackAbove (sibling); + } + else + w->raise (); + } + break; + case Below: + if (above) + { + if (sibling) + w->restackBelow (sibling); + } + else + w->lower (); + break; + default: + /* no handling of the TopIf, BottomIf, Opposite cases - + there will hardly be any client using that */ + break; + } + } + } + else + { + XWindowChanges xwc; + unsigned int xwcm; + + xwcm = event->xconfigurerequest.value_mask & + (CWX | CWY | CWWidth | CWHeight | CWBorderWidth); + + xwc.x = event->xconfigurerequest.x; + xwc.y = event->xconfigurerequest.y; + xwc.width = event->xconfigurerequest.width; + xwc.height = event->xconfigurerequest.height; + xwc.border_width = event->xconfigurerequest.border_width; + + if (w) + w->configureXWindow (xwcm, &xwc); + else + XConfigureWindow (priv->dpy, event->xconfigurerequest.window, + xwcm, &xwc); + } + break; + case CirculateRequest: + break; + case FocusIn: + if (event->xfocus.mode != NotifyGrab) + { + w = findTopLevelWindow (event->xfocus.window); + if (w && w->managed ()) + { + unsigned int state = w->state (); + + if (w->id () != priv->activeWindow) + { + w->windowNotify (CompWindowNotifyFocusChange); + + priv->activeWindow = w->id (); + w->priv->activeNum = priv->activeNum++; + + priv->addToCurrentActiveWindowHistory (w->id ()); + + XChangeProperty (priv->dpy , priv->root, + Atoms::winActive, + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &priv->activeWindow, 1); + } + + state &= ~CompWindowStateDemandsAttentionMask; + w->changeState (state); + } + } + break; + case EnterNotify: + if (event->xcrossing.root == priv->root) + w = findTopLevelWindow (event->xcrossing.window); + else + w = NULL; + + if (w && w->id () != priv->below) + { + priv->below = w->id (); + + if (!priv->optionGetClickToFocus () && + priv->grabs.empty () && + event->xcrossing.mode != NotifyGrab && + event->xcrossing.detail != NotifyInferior) + { + bool raise; + int delay; + + raise = priv->optionGetAutoraise (); + delay = priv->optionGetAutoraiseDelay (); + + if (priv->autoRaiseTimer.active () && + priv->autoRaiseWindow != w->id ()) + { + priv->autoRaiseTimer.stop (); + } + + if (w->type () & ~(CompWindowTypeDockMask | + CompWindowTypeDesktopMask)) + { + w->moveInputFocusTo (); + + if (raise) + { + if (delay > 0) + { + priv->autoRaiseWindow = w->id (); + priv->autoRaiseTimer.start ( + boost::bind (autoRaiseTimeout, this), + delay, (unsigned int) ((float) delay * 1.2)); + } + else + { + CompStackingUpdateMode mode = + CompStackingUpdateModeNormal; + + w->updateAttributes (mode); + } + } + } + } + } + break; + case LeaveNotify: + if (event->xcrossing.detail != NotifyInferior) + { + if (event->xcrossing.window == priv->below) + priv->below = None; + } + break; + default: + if (priv->shapeExtension && + event->type == priv->shapeEvent + ShapeNotify) + { + w = findWindow (((XShapeEvent *) event)->window); + if (w) + { + if (w->mapNum ()) + w->priv->updateRegion (); + } + } + else if (event->type == priv->syncEvent + XSyncAlarmNotify) + { + XSyncAlarmNotifyEvent *sa; + + sa = (XSyncAlarmNotifyEvent *) event; + + + foreach (w, priv->windows) + { + if (w->priv->syncAlarm == sa->alarm) + { + w->priv->handleSyncAlarm (); + break; + } + } + } + break; + } +} diff --git a/src/icon.cpp b/src/icon.cpp new file mode 100644 index 0000000..3118db0 --- /dev/null +++ b/src/icon.cpp @@ -0,0 +1,46 @@ +/* + * Copyright © 2008 Dennis Kasprzyk + * Copyright © 2007 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Dennis Kasprzyk not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Dennis Kasprzyk makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org> + * David Reveman <davidr@novell.com> + */ + +#include <core/icon.h> + +CompIcon::CompIcon (CompScreen *screen, unsigned int width, + unsigned int height) : + CompSize (width, height), + mData (new unsigned char[width * height * 4]) +{ +} + +CompIcon::~CompIcon () +{ + delete [] mData; +} + +unsigned char* +CompIcon::data () +{ + return mData; +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..bfbfc81 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,242 @@ +/* + * Copyright © 2005 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <davidr@novell.com> + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <compiz.h> + +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include <string.h> +#include <sys/wait.h> + +#include <core/core.h> +#include "privatescreen.h" + +char *programName; +char **programArgv; +int programArgc; + +char *backgroundImage = NULL; + +bool shutDown = false; +bool restartSignal = false; + +CompWindow *lastFoundWindow = 0; + +bool replaceCurrentWm = false; +bool indirectRendering = false; +bool noDetection = false; +bool useDesktopHints = false; +bool debugOutput = false; +bool useCow = true; +bool zcomp = false; + +unsigned int pluginClassHandlerIndex = 0; + +static void +usage (void) +{ + printf ("Usage: %s " + "[--replace] " + "[--display DISPLAY]\n " + "[--indirect-rendering] " + "[--sm-disable] " + "[--sm-client-id ID]\n " + "[--bg-image PNG] " + "[--no-detection] " + "[--keep-desktop-hints]\n " + "[--use-root-window] " + "[--debug] " + "[--zcomp] " + "[--version] " + "[--help] " + "[PLUGIN]...\n", + programName); +} + +static void +signalHandler (int sig) +{ + int status; + + switch (sig) { + case SIGCHLD: + waitpid (-1, &status, WNOHANG | WUNTRACED); + break; + case SIGHUP: + restartSignal = true; + break; + case SIGINT: + case SIGTERM: + shutDown = true; + default: + break; + } +} + +int +main (int argc, char **argv) +{ + char *displayName = 0; + std::vector<CompString> plugins; + int i; + bool disableSm = false; + char *clientId = NULL; + + programName = argv[0]; + programArgc = argc; + programArgv = argv; + + signal (SIGHUP, signalHandler); + signal (SIGCHLD, signalHandler); + signal (SIGINT, signalHandler); + signal (SIGTERM, signalHandler); + + for (i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "--help")) + { + usage (); + return 0; + } + else if (!strcmp (argv[i], "--version")) + { + printf (PACKAGE_STRING "\n"); + return 0; + } + else if (!strcmp (argv[i], "--debug")) + { + debugOutput = true; + } + else if (!strcmp (argv[i], "--display")) + { + if (i + 1 < argc) + displayName = argv[++i]; + } + else if (!strcmp (argv[i], "--indirect-rendering")) + { + indirectRendering = true; + } + else if (!strcmp (argv[i], "--keep-desktop-hints")) + { + useDesktopHints = true; + } + else if (!strcmp (argv[i], "--use-root-window")) + { + useCow = false; + } + else if (!strcmp (argv[i], "--replace")) + { + replaceCurrentWm = true; + } + else if (!strcmp (argv[i], "--sm-disable")) + { + disableSm = true; + } + else if (!strcmp (argv[i], "--sm-client-id")) + { + if (i + 1 < argc) + clientId = argv[++i]; + } + else if (!strcmp (argv[i], "--no-detection")) + { + noDetection = true; + } + else if (!strcmp (argv[i], "--bg-image")) + { + if (i + 1 < argc) + backgroundImage = argv[++i]; + } + else if (!strcmp (argv[i], "--zcomp")) + { + zcomp = true; + } + else if (*argv[i] == '-') + { + compLogMessage ("core", CompLogLevelWarn, + "Unknown option '%s'\n", argv[i]); + } + else + { + plugins.push_back (argv[i]); + } + } + + screen = new CompScreen (); + if (!screen) + return 1; + + modHandler = new ModifierHandler (); + + if (!modHandler) + return 1; + + if (!plugins.empty ()) + { + CompOption::Value::Vector list; + CompOption::Value value; + CompOption *o = screen->getOption ("active_plugins"); + + foreach (CompString &str, plugins) + { + value.set (str); + list.push_back (value); + } + + value.set (CompOption::TypeString, list); + + if (o) + o->set (value); + } + + if (!screen->init (displayName)) + return 1; + + modHandler->updateModifierMappings (); + + if (!disableSm) + CompSession::init (clientId); + + screen->eventLoop (); + + if (!disableSm) + CompSession::close (); + + delete screen; + delete modHandler; + + if (restartSignal) + { + execvp (programName, programArgv); + return 1; + } + + return 0; +} diff --git a/src/match.cpp b/src/match.cpp new file mode 100644 index 0000000..ff46aae --- /dev/null +++ b/src/match.cpp @@ -0,0 +1,744 @@ +/* + * Copyright © 2007 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <davidr@novell.com> + */ + +#include <stdlib.h> +#include <string.h> + +#include <boost/foreach.hpp> +#define foreach BOOST_FOREACH + +#include <core/core.h> + +#include <core/screen.h> +#include <core/match.h> +#include <core/window.h> +#include <core/plugin.h> +#include "privatematch.h" +#include "privatescreen.h" +#include "privatewindow.h" + +const CompMatch CompMatch::emptyMatch; + +class CoreExp : public CompMatch::Expression { + public: + virtual ~CoreExp () {}; + + typedef enum { + TypeXid, + TypeState, + TypeOverride, + TypeRGBA, + TypeType + } Type; + + CoreExp (const CompString& str) + { + if (str.compare (0, 4, "xid=") == 0) + { + mType = TypeXid; + priv.val = strtol (str.substr (4).c_str (), NULL, 0); + } + else if (str.compare (0, 6, "state=") == 0) + { + mType = TypeState; + priv.uval = PrivateScreen::windowStateFromString + (str.substr (6).c_str ()); + } + else if (str.compare (0, 18, "override_redirect=") == 0) + { + mType = TypeOverride; + priv.val = strtol (str.substr (18).c_str (), NULL, 0); + } + else if (str.compare (0, 5, "rgba=") == 0) + { + mType = TypeRGBA; + priv.val = strtol (str.substr (5).c_str (), NULL, 0); + } + else + { + size_t offset = (str.compare (0, 5, "type=") == 0) ? 5 : 0; + + mType = TypeType; + priv.uval = PrivateWindow::windowTypeFromString ( + str.substr (offset).c_str ()); + } + } + + bool evaluate (CompWindow *w) + { + switch (mType) + { + case TypeXid: + return ((unsigned int) priv.val == w->id ()); + case TypeState: + return (priv.uval & w->state ()); + case TypeOverride: + { + bool overrideRedirect = w->overrideRedirect (); + return ((priv.val == 1 && overrideRedirect) || + (priv.val == 0 && !overrideRedirect)); + } + case TypeRGBA: + return ((priv.val && w->alpha ()) || + (!priv.val && !w->alpha ())); + case TypeType: + return (priv.uval & w->wmType ()); + } + return true; + } + + Type mType; + CompPrivate priv; +}; + +CompMatch::Expression * +CompScreen::matchInitExp (const CompString& str) +{ + WRAPABLE_HND_FUNC_RETURN (10, CompMatch::Expression *, matchInitExp, str) + + return new CoreExp (str); +} + +static void +matchUpdateMatchOptions (CompOption::Vector& options) +{ + foreach (CompOption &option, options) + { + switch (option.type ()) { + case CompOption::TypeMatch: + option.value ().match ().update (); + break; + case CompOption::TypeList: + if (option.value ().listType () == CompOption::TypeMatch) + { + foreach (CompOption::Value &value, option.value ().list ()) + value.match ().update (); + } + default: + break; + } + } +} + +void +CompScreen::matchExpHandlerChanged () +{ + WRAPABLE_HND_FUNC (11, matchExpHandlerChanged) + + foreach (CompPlugin *p, CompPlugin::getPlugins ()) + { + CompOption::Vector &options = p->vTable->getOptions (); + matchUpdateMatchOptions (options); + } +} + +void +CompScreen::matchPropertyChanged (CompWindow *w) +{ + WRAPABLE_HND_FUNC (12, matchPropertyChanged, w) +} + +static void +matchResetOps (MatchOp::List &list) +{ + MatchExpOp *exp; + foreach (MatchOp *op, list) + { + switch (op->type ()) { + case MatchOp::TypeGroup: + matchResetOps (dynamic_cast <MatchGroupOp *> (op)->op); + break; + case MatchOp::TypeExp: + exp = dynamic_cast <MatchExpOp *> (op); + if (exp && exp->e) + exp->e.reset (); + break; + default: + break; + } + } +} + +static bool +matchOpsEqual (MatchOp::List &list1, + MatchOp::List &list2) +{ + MatchGroupOp *g1, *g2; + MatchExpOp *e1, *e2; + MatchOp::List::iterator it1 = list1.begin (), it2 = list2.begin (); + + if (list1.size () != list2.size ()) + return false; + + while (it1 != list1.end ()) + { + if ((*it1)->type () != (*it2)->type ()) + return false; + + if ((*it1)->flags != (*it2)->flags) + return false; + + switch ((*it1)->type ()) { + case MatchOp::TypeGroup: + g1 = dynamic_cast<MatchGroupOp *> (*it1); + g2 = dynamic_cast<MatchGroupOp *> (*it2); + + if (!matchOpsEqual (g1->op, g2->op)) + return false; + + break; + case MatchOp::TypeExp: + e1 = dynamic_cast<MatchExpOp *> (*it1); + e2 = dynamic_cast<MatchExpOp *> (*it2); + + if (e1->value != e2->value) + return false; + + break; + default: + break; + } + + it1++; + it2++; + } + + return true; +} + +static unsigned int +nextIndex (CompString &str, + unsigned int i) +{ + while (str[i] == '\\') + if (str[++i] != '\0') + i++; + + return i; +} + +static CompString +strndupValue (CompString str) +{ + CompString value; + + unsigned int i, j, n = str.length (); + + /* count trialing white spaces */ + i = j = 0; + while (i < n) + { + if (str[i] != ' ') + { + j = 0; + if (str[i] == '\\') + i++; + } + else + { + j++; + } + + i++; + } + + /* remove trialing white spaces */ + n -= j; + + i = j = 0; + for (;;) + { + if (str[i] == '\\') + i++; + + value += str[i++]; + + if (i >= n) + { + return value; + } + } +} + +/* + Add match expressions from string. Special characters are + '(', ')', '!', '&', '|'. Escape character is '\'. + + Example: + + "type=desktop | !type=dock" + "!type=dock & (state=fullscreen | state=shaded)" +*/ + +static void +matchAddFromString (MatchOp::List &list, + CompString str) +{ + CompString value; + int j, i = 0; + int flags = 0; + + str += "\0"; + + while (str[i] != '\0') + { + while (str[i] == ' ') + i++; + + if (str[i] == '!') + { + flags |= MATCH_OP_NOT_MASK; + + i++; + while (str[i] == ' ') + i++; + } + + if (str[i] == '(') + { + int level = 1; + int length; + + j = ++i; + + while (str[j] != '\0') + { + if (str[j] == '(') + { + level++; + } + else if (str[j] == ')') + { + level--; + if (level == 0) + break; + } + + j = nextIndex (str, ++j); + } + + length = j - i; + + MatchGroupOp *group = new MatchGroupOp (); + matchAddFromString (group->op, str.substr (i, length)); + group->flags = flags; + list.push_back (group); + + while (str[j] != '\0' && str[j] != '|' && str[j] != '&') + j++; + } + else + { + j = i; + + while (str[j] != '\0' && str[j] != '|' && str[j] != '&') + j = nextIndex (str, ++j); + + if (j > i) + { + MatchExpOp *exp = new MatchExpOp (); + exp->value = strndupValue (str.substr (i, j - i)); + exp->flags = flags; + list.push_back (exp); + } + } + + i = j; + + if (str[i] != '\0') + { + if (str[i] == '&') + flags = MATCH_OP_AND_MASK; + + i++; + } + } + + if (list.size ()) + list.front ()->flags &= ~MATCH_OP_AND_MASK; + +} + +static CompString +matchOpsToString (MatchOp::List &list) +{ + CompString value (""), group; + + foreach (MatchOp *op, list) + { + switch (op->type ()) { + case MatchOp::TypeGroup: + group = + matchOpsToString (dynamic_cast <MatchGroupOp *> (op)->op); + + if (group.length ()) + { + if (value.length ()) + { + value += ((op->flags & MATCH_OP_AND_MASK) ? + "& " : "| "); + } + if (op->flags & MATCH_OP_NOT_MASK) + value += "!"; + value += "(" + group + ") "; + } + break; + case MatchOp::TypeExp: + if (value.length ()) + value += ((op->flags & MATCH_OP_AND_MASK) ? "& " : "| "); + + if (op->flags & MATCH_OP_NOT_MASK) + value += "!"; + + value += dynamic_cast <MatchExpOp *> (op)->value; + value += " "; + break; + default: + break; + } + } + + if (!value.empty ()) + value.erase (value.length () - 1); + + return value; +} + +static void +matchUpdateOps (MatchOp::List &list) +{ + MatchExpOp *exp; + foreach (MatchOp *op, list) + { + switch (op->type ()) { + case MatchOp::TypeGroup: + matchUpdateOps (dynamic_cast <MatchGroupOp *> (op)->op); + break; + case MatchOp::TypeExp: + exp = dynamic_cast <MatchExpOp *> (op); + if (exp && screen) + exp->e.reset (screen->matchInitExp (exp->value)); + break; + default: + break; + } + } +} + +static bool +matchEvalOps (MatchOp::List &list, + CompWindow *w) +{ + bool value, result = false; + MatchExpOp *exp; + + foreach (MatchOp *op, list) + { + /* fast evaluation */ + if (op->flags & MATCH_OP_AND_MASK) + { + /* result will never be true */ + if (!result) + return false; + } + else + { + /* result will always be true */ + if (result) + return true; + } + + switch (op->type ()) { + case MatchOp::TypeGroup: + value = + matchEvalOps (dynamic_cast <MatchGroupOp *> (op)->op, w); + break; + case MatchOp::TypeExp: + exp = dynamic_cast <MatchExpOp *> (op); + if (exp->e.get ()) + value = exp->e->evaluate (w); + else + value = true; + break; + default: + value = true; + break; + } + + if (op->flags & MATCH_OP_NOT_MASK) + value = !value; + + if (op->flags & MATCH_OP_AND_MASK) + result = (result && value); + else + result = (result || value); + } + + return result; +} + +MatchOp::MatchOp () : + flags (0) +{ +} + +MatchOp::~MatchOp () +{ +} + +MatchExpOp::MatchExpOp () : + value (""), + e () +{ +} + +MatchExpOp::MatchExpOp (const MatchExpOp &ex) : + value (ex.value), + e (ex.e) +{ + flags = ex.flags; +} + +MatchGroupOp::MatchGroupOp () : + op (0) +{ +} + +MatchGroupOp::MatchGroupOp (const MatchGroupOp &gr) : + op (0) +{ + *this = gr; + flags = gr.flags; +} + +MatchGroupOp::~MatchGroupOp () +{ + foreach (MatchOp *o, op) + delete o; +} + +MatchGroupOp & +MatchGroupOp::operator= (const MatchGroupOp &gr) +{ + MatchGroupOp *gop; + MatchExpOp *eop; + + foreach (MatchOp *o, op) + delete o; + + op.clear (); + + foreach (MatchOp *o, gr.op) + { + switch (o->type ()) + { + case MatchOp::TypeGroup: + gop = new MatchGroupOp (dynamic_cast <MatchGroupOp &> (*o)); + op.push_back (gop); + break; + case MatchOp::TypeExp: + eop = new MatchExpOp (dynamic_cast <MatchExpOp &> (*o)); + op.push_back (eop); + break; + default: + break; + } + } + + return *this; +} + +PrivateMatch::PrivateMatch () : + op () +{ +} + + +CompMatch::CompMatch () : + priv (new PrivateMatch ()) +{ +} + +CompMatch::CompMatch (const CompString str) : + priv (new PrivateMatch ()) +{ + matchAddFromString (priv->op.op, str); + update (); +} + +CompMatch::CompMatch (const CompMatch &match) : + priv (new PrivateMatch ()) +{ + priv->op = match.priv->op; + update (); +} + +CompMatch::~CompMatch () +{ + delete priv; +} + +void +CompMatch::update () +{ + matchResetOps (priv->op.op); + matchUpdateOps (priv->op.op); +} + +bool +CompMatch::evaluate (CompWindow *window) +{ + return matchEvalOps (priv->op.op, window); +} + +CompString +CompMatch::toString () const +{ + return matchOpsToString (priv->op.op); +} + +bool +CompMatch::isEmpty () const +{ + return (*this == emptyMatch); +} + +CompMatch & +CompMatch::operator= (const CompMatch &match) +{ + priv->op = match.priv->op; + update (); + + return *this; +} + +CompMatch & +CompMatch::operator&= (const CompMatch &match) +{ + MatchGroupOp *g1 = new MatchGroupOp (priv->op); + MatchGroupOp *g2 = new MatchGroupOp (match.priv->op); + + g2->flags = MATCH_OP_AND_MASK; + + priv->op = MatchGroupOp (); + priv->op.op.push_back (g1); + priv->op.op.push_back (g2); + update (); + + return *this; +} + +CompMatch & +CompMatch::operator|= (const CompMatch &match) +{ + MatchGroupOp *g1 = new MatchGroupOp (priv->op); + MatchGroupOp *g2 = new MatchGroupOp (match.priv->op); + + priv->op = MatchGroupOp (); + priv->op.op.push_back (g1); + priv->op.op.push_back (g2); + update (); + + return *this; +} + +const CompMatch & +CompMatch::operator& (const CompMatch &match) +{ + return CompMatch (*this) &= match; +} + +const CompMatch & +CompMatch::operator| (const CompMatch &match) +{ + return CompMatch (*this) |= match; +} + +const CompMatch & +CompMatch::operator! () +{ + MatchGroupOp *g = new MatchGroupOp (priv->op); + + g->flags ^= MATCH_OP_NOT_MASK; + priv->op = MatchGroupOp (); + priv->op.op.push_back (g); + update (); + + return *this; +} + +CompMatch & +CompMatch::operator= (const CompString &str) +{ + priv->op = MatchGroupOp (); + matchAddFromString (priv->op.op, str); + update (); + + return *this; +} + +CompMatch & +CompMatch::operator&= (const CompString &str) +{ + *this &= CompMatch (str); + + return *this; +} + +CompMatch & +CompMatch::operator|= (const CompString &str) +{ + *this |= CompMatch (str); + + return *this; +} + +const CompMatch & +CompMatch::operator& (const CompString &str) +{ + *this &= str; + + return *this; +} + +const CompMatch & +CompMatch::operator| (const CompString &str) +{ + *this |= str; + + return *this; +} + +bool +CompMatch::operator== (const CompMatch &match) const +{ + return matchOpsEqual (priv->op.op, match.priv->op.op); +} + +bool +CompMatch::operator!= (const CompMatch &match) const +{ + return !(*this == match); +} diff --git a/src/modifierhandler.cpp b/src/modifierhandler.cpp new file mode 100644 index 0000000..3e7c480 --- /dev/null +++ b/src/modifierhandler.cpp @@ -0,0 +1,204 @@ +/* + * Copyright © 2008 Dennis Kasprzyk + * Copyright © 2007 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Dennis Kasprzyk not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Dennis Kasprzyk makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org> + * David Reveman <davidr@novell.com> + * Sam Spilsbury <smspillaz@gmail.com> + */ + +#include <core/screen.h> +#include "privatescreen.h" + +const unsigned int ModifierHandler::virtualModMask[7] = { + CompAltMask, CompMetaMask, CompSuperMask, CompHyperMask, + CompModeSwitchMask, CompNumLockMask, CompScrollLockMask +}; + +const int ModifierHandler::maskTable[8] = { + ShiftMask, LockMask, ControlMask, Mod1Mask, + Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask +}; + +unsigned int +ModifierHandler::ignoredModMask () +{ + return mIgnoredModMask; +} + +const XModifierKeymap * +ModifierHandler::modMap () +{ + return mModMap; +} + +void +ModifierHandler::updateModifierMappings () +{ + unsigned int modMask[CompModNum]; + int i, minKeycode, maxKeycode, keysymsPerKeycode = 0; + KeySym* key; + + for (i = 0; i < CompModNum; i++) + modMask[i] = 0; + + XDisplayKeycodes (screen->dpy (), &minKeycode, &maxKeycode); + key = XGetKeyboardMapping (screen->dpy (), + minKeycode, (maxKeycode - minKeycode + 1), + &keysymsPerKeycode); + + if (mModMap) + XFreeModifiermap (mModMap); + + mModMap = XGetModifierMapping (screen->dpy ()); + if (mModMap && mModMap->max_keypermod > 0) + { + KeySym keysym; + int index, size, mask; + + size = maskTableSize * mModMap->max_keypermod; + + for (i = 0; i < size; i++) + { + if (!mModMap->modifiermap[i]) + continue; + + index = 0; + do + { + keysym = XKeycodeToKeysym (screen->dpy (), + mModMap->modifiermap[i], + index++); + } while (!keysym && index < keysymsPerKeycode); + + if (keysym) + { + mask = maskTable[i / mModMap->max_keypermod]; + + if (keysym == XK_Alt_L || + keysym == XK_Alt_R) + { + modMask[CompModAlt] |= mask; + } + else if (keysym == XK_Meta_L || + keysym == XK_Meta_R) + { + modMask[CompModMeta] |= mask; + } + else if (keysym == XK_Super_L || + keysym == XK_Super_R) + { + modMask[CompModSuper] |= mask; + } + else if (keysym == XK_Hyper_L || + keysym == XK_Hyper_R) + { + modMask[CompModHyper] |= mask; + } + else if (keysym == XK_Mode_switch) + { + modMask[CompModModeSwitch] |= mask; + } + else if (keysym == XK_Scroll_Lock) + { + modMask[CompModScrollLock] |= mask; + } + else if (keysym == XK_Num_Lock) + { + modMask[CompModNumLock] |= mask; + } + } + } + + for (i = 0; i < CompModNum; i++) + { + if (!modMask[i]) + modMask[i] = CompNoMask; + } + + if (memcmp (modMask, mModMask, sizeof (modMask))) + { + memcpy (mModMask, modMask, sizeof (modMask)); + + mIgnoredModMask = LockMask | + (modMask[CompModNumLock] & ~CompNoMask) | + (modMask[CompModScrollLock] & ~CompNoMask); + + screen->priv->updatePassiveKeyGrabs (); + } + } + + if (key) + XFree (key); +} + +unsigned int +ModifierHandler::virtualToRealModMask (unsigned int modMask) +{ + int i; + + for (i = 0; i < CompModNum; i++) + { + if (modMask & virtualModMask[i]) + { + modMask &= ~virtualModMask[i]; + modMask |= mModMask[i]; + } + } + + return modMask; +} + +unsigned int +ModifierHandler::keycodeToModifiers (int keycode) +{ + unsigned int mods = 0; + int mod, k; + + for (mod = 0; mod < maskTableSize; mod++) + { + for (k = 0; k < mModMap->max_keypermod; k++) + { + if (mModMap->modifiermap[mod * + mModMap->max_keypermod + k] == keycode) + mods |= maskTable[mod]; + } + } + + return mods; +} + +ModifierHandler::ModifierHandler () : + mIgnoredModMask (LockMask), + mModMap (0) +{ + for (int i = 0; i < ModNum; i++) + mModMask[i] = NoMask; +} + +ModifierHandler::~ModifierHandler () +{ + if (mModMap) + XFreeModifiermap (mModMap); + + mModMap = NULL; +} diff --git a/src/option.cpp b/src/option.cpp new file mode 100644 index 0000000..1fb69f0 --- /dev/null +++ b/src/option.cpp @@ -0,0 +1,964 @@ +/* + * Copyright © 2005 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <davidr@novell.com> + */ + +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <ctype.h> +#include <math.h> + +#include <boost/foreach.hpp> +#define foreach BOOST_FOREACH + +#include <core/core.h> +#include <core/option.h> +#include "privateoption.h" + +CompOption::Vector noOptions (0); + +CompOption::Value::Value () : + priv (new PrivateValue ()) +{ +} + +CompOption::Value::Value (const Value &v) : + priv (new PrivateValue (*v.priv)) +{ +} + +CompOption::Value::~Value () +{ + delete priv; +} + +CompOption::Value::Value (const bool b) : + priv (new PrivateValue ()) +{ + set (b); +} + +CompOption::Value::Value (const int i) : + priv (new PrivateValue ()) +{ + set (i); +} + +CompOption::Value::Value (const float f) : + priv (new PrivateValue ()) +{ + set (f); +} + +CompOption::Value::Value (const unsigned short *color) : + priv (new PrivateValue ()) +{ + set (color); +} + +CompOption::Value::Value (const CompString& s) : + priv (new PrivateValue ()) +{ + set (s); +} + +CompOption::Value::Value (const char *s) : + priv (new PrivateValue ()) +{ + set (s); +} + + +CompOption::Value::Value (const CompMatch& m) : + priv (new PrivateValue ()) +{ + set (m); +} + +CompOption::Value::Value (const CompAction& a) : + priv (new PrivateValue ()) +{ + set (a); +} + +CompOption::Value::Value (CompOption::Type type, const Vector& l) : + priv (new PrivateValue ()) +{ + set (type, l); +} + +CompOption::Type +CompOption::Value::type () const +{ + return priv->type; +} + +void +CompOption::Value::set (const bool b) +{ + priv->reset (); + priv->type = CompOption::TypeBool; + priv->value.b = b; +} + +void +CompOption::Value::set (const int i) +{ + priv->reset (); + priv->type = CompOption::TypeInt; + priv->value.i = i; +} + +void +CompOption::Value::set (const float f) +{ + priv->reset (); + priv->type = CompOption::TypeFloat; + priv->value.f = f; +} + +void +CompOption::Value::set (const unsigned short *color) +{ + priv->reset (); + priv->type = CompOption::TypeColor; + priv->value.c[0] = color[0]; + priv->value.c[1] = color[1]; + priv->value.c[2] = color[2]; + priv->value.c[3] = color[3]; +} + +void +CompOption::Value::set (const CompString& s) +{ + priv->reset (); + priv->type = CompOption::TypeString; + priv->string = s; +} + +void +CompOption::Value::set (const char *s) +{ + priv->reset (); + priv->type = CompOption::TypeString; + priv->string = CompString (s); +} + +void +CompOption::Value::set (const CompMatch& m) +{ + priv->reset (); + priv->type = CompOption::TypeMatch; + priv->match = m; +} + +void +CompOption::Value::set (const CompAction& a) +{ + priv->reset (); + priv->type = CompOption::TypeAction; + priv->action = a; +} + +void +CompOption::Value::set (CompOption::Type type, const Vector& l) +{ + priv->reset (); + priv->type = CompOption::TypeList; + priv->list = l; + priv->listType = type; +} + +static bool +checkIsAction (CompOption::Type type) +{ + switch (type) { + case CompOption::TypeAction: + case CompOption::TypeKey: + case CompOption::TypeButton: + case CompOption::TypeEdge: + case CompOption::TypeBell: + return true; + default: + break; + } + + return false; +} + +bool +CompOption::Value::b () +{ + if (!priv->checkType (CompOption::TypeBool)) + return false; + + return priv->value.b; +} + +int +CompOption::Value::i () +{ + if (!priv->checkType (CompOption::TypeInt)) + return 0; + + return priv->value.i; +} + +float +CompOption::Value::f () +{ + if (!priv->checkType (CompOption::TypeFloat)) + return 0.0; + + return priv->value.f; +} + +static unsigned short defaultColor[4] = { 0x0, 0x0, 0x0, 0xffff}; + +unsigned short * +CompOption::Value::c () +{ + if (!priv->checkType (CompOption::TypeColor)) + return reinterpret_cast<unsigned short *> (defaultColor); + + return priv->value.c; +} + +CompString +CompOption::Value::s () +{ + if (!priv->checkType (CompOption::TypeString)) + return ""; + + return priv->string; +} + +CompMatch & +CompOption::Value::match () +{ + priv->checkType (CompOption::TypeMatch); + + return priv->match; +} + +CompAction & +CompOption::Value::action () +{ + priv->checkType (priv->type); + + if (!checkIsAction (priv->type)) + compLogMessage ("core", CompLogLevelWarn, + "CompOption::Value not an action"); + + return priv->action; +} + +CompOption::Type +CompOption::Value::listType () +{ + priv->checkType (CompOption::TypeList); + + return priv->listType; +} + +CompOption::Value::Vector & +CompOption::Value::list () +{ + priv->checkType (CompOption::TypeList); + + return priv->list; +} + +CompOption::Value::operator bool () +{ + return b (); +} + +CompOption::Value::operator int () +{ + return i (); +} + +CompOption::Value::operator float () +{ + return f (); +} + +CompOption::Value::operator unsigned short * () +{ + return c (); +} + +CompOption::Value::operator CompString () +{ + return s (); +} + +CompOption::Value::operator CompMatch & () +{ + return match (); +} + +CompOption::Value::operator CompAction & () +{ + return action (); +} + +CompOption::Value::operator CompAction * () +{ + return &action (); +} + +CompOption::Value::operator Type () +{ + return listType (); +} + +CompOption::Value::operator Vector & () +{ + return list (); +} + +bool +CompOption::Value::operator== (const CompOption::Value &val) +{ + if (priv->type != val.priv->type) + return false; + + switch (priv->type) + { + case CompOption::TypeBool: + return priv->value.b == val.priv->value.b; + break; + + case CompOption::TypeInt: + return priv->value.i == val.priv->value.i; + break; + + case CompOption::TypeFloat: + return priv->value.f == val.priv->value.f; + break; + + case CompOption::TypeColor: + return (priv->value.c[0] == val.priv->value.c[0]) && + (priv->value.c[1] == val.priv->value.c[1]) && + (priv->value.c[2] == val.priv->value.c[2]) && + (priv->value.c[3] == val.priv->value.c[3]); + break; + + case CompOption::TypeString: + return priv->string.compare (val.priv->string) == 0; + break; + + case CompOption::TypeMatch: + return priv->match == val.priv->match; + break; + + case CompOption::TypeAction: + return priv->action == val.priv->action; + break; + + case CompOption::TypeList: + if (priv->listType != val.priv->listType) + return false; + + if (priv->list.size () != val.priv->list.size ()) + return false; + + for (unsigned int i = 0; i < priv->list.size (); i++) + if (priv->list[i] != val.priv->list[i]) + return false; + + return true; + break; + + default: + break; + } + + return true; +} + +bool +CompOption::Value::operator!= (const CompOption::Value &val) +{ + return !(*this == val); +} + +CompOption::Value & +CompOption::Value::operator= (const CompOption::Value &val) +{ + delete priv; + priv = new PrivateValue (*val.priv); + + return *this; +} + +PrivateValue::PrivateValue () : + type (CompOption::TypeUnset), + string (""), + action (), + match (), + listType (CompOption::TypeUnset), + list () +{ + memset (&value, 0, sizeof (ValueUnion)); +} + +PrivateValue::PrivateValue (const PrivateValue& p) : + type (p.type), + string (p.string), + action (p.action), + match (p.match), + listType (p.listType), + list (p.list) +{ + memcpy (&value, &p.value, sizeof (ValueUnion)); +} + +bool +PrivateValue::checkType (CompOption::Type refType) +{ + if (type == CompOption::TypeUnset) + { + compLogMessage ("core", CompLogLevelWarn, + "Value type is not yet set"); + return false; + } + + if (type != refType) + { + compLogMessage ("core", CompLogLevelWarn, + "Value type does not match (is %d, expected %d)", + type, refType); + return false; + } + + return true; +} + +void +PrivateValue::reset () +{ + switch (type) { + case CompOption::TypeString: + string = ""; + break; + case CompOption::TypeMatch: + match = CompMatch (); + break; + case CompOption::TypeAction: + action = CompAction (); + break; + case CompOption::TypeList: + list.clear (); + listType = CompOption::TypeBool; + break; + default: + break; + } + type = CompOption::TypeBool; +} + +CompOption::Restriction::Restriction () : + priv (new PrivateRestriction ()) +{ +} + +CompOption::Restriction::Restriction (const CompOption::Restriction &r) : + priv (new PrivateRestriction (*r.priv)) +{ +} + +CompOption::Restriction::~Restriction () +{ + delete priv; +} + +int +CompOption::Restriction::iMin () +{ + if (priv->type == CompOption::TypeInt) + return priv->rest.i.min; + return MINSHORT; +} + +int +CompOption::Restriction::iMax () +{ + if (priv->type == CompOption::TypeInt) + return priv->rest.i.max; + return MAXSHORT; +} + +float +CompOption::Restriction::fMin () +{ + if (priv->type == CompOption::TypeFloat) + return priv->rest.f.min; + return MINSHORT; +} + +float +CompOption::Restriction::fMax () +{ + if (priv->type == CompOption::TypeFloat) + return priv->rest.f.min; + return MINSHORT; +} + +float +CompOption::Restriction::fPrecision () +{ + if (priv->type == CompOption::TypeFloat) + return priv->rest.f.precision; + return 0.1f; +} + + +void +CompOption::Restriction::set (int min, int max) +{ + priv->type = CompOption::TypeInt; + priv->rest.i.min = min; + priv->rest.i.max = max; +} + +void +CompOption::Restriction::set (float min, float max, float precision) +{ + priv->type = CompOption::TypeFloat; + priv->rest.f.min = min; + priv->rest.f.max = max; + priv->rest.f.precision = precision; +} + +bool +CompOption::Restriction::inRange (int i) +{ + if (priv->type != CompOption::TypeInt) + return true; + if (i < priv->rest.i.min) + return false; + if (i > priv->rest.i.max) + return false; + return true; +} + +bool +CompOption::Restriction::inRange (float f) +{ + if (priv->type != CompOption::TypeFloat) + return true; + if (f < priv->rest.f.min) + return false; + if (f > priv->rest.f.max) + return false; + return true; +} + +CompOption::Restriction & +CompOption::Restriction::operator= (const CompOption::Restriction &rest) +{ + delete priv; + priv = new PrivateRestriction (*rest.priv); + return *this; +} + +CompOption * +CompOption::Class::getOption (const CompString &name) +{ + CompOption *o = CompOption::findOption (getOptions (), name); + return o; +} + +CompOption * +CompOption::findOption (CompOption::Vector &options, + CompString name, + unsigned int *index) +{ + unsigned int i; + + for (i = 0; i < options.size (); i++) + { + if (options[i].priv->name == name) + { + if (index) + *index = i; + + return &options[i]; + } + } + + return NULL; +} + +CompOption::CompOption () : + priv (new PrivateOption ()) +{ +} + +CompOption::CompOption (const CompOption &o) : + priv (new PrivateOption (*o.priv)) +{ +} + +CompOption::CompOption (CompString name, CompOption::Type type) : + priv (new PrivateOption ()) +{ + setName (name, type); +} + +static void +finiScreenOptionValue (CompScreen *s, + CompOption::Value &v, + CompOption::Type type) +{ + switch (type) { + case CompOption::TypeAction: + case CompOption::TypeKey: + case CompOption::TypeButton: + case CompOption::TypeEdge: + case CompOption::TypeBell: + if (v.action ().state () & CompAction::StateAutoGrab) + s->removeAction (&v.action ()); + break; + + case CompOption::TypeList: + foreach (CompOption::Value &val, v.list ()) + finiScreenOptionValue (s, val, v.listType ()); + break; + + default: + break; + } +} + +static void +finiOptionValue (CompOption::Value &v, + CompOption::Type type) +{ + switch (type) { + case CompOption::TypeAction: + case CompOption::TypeKey: + case CompOption::TypeButton: + case CompOption::TypeEdge: + case CompOption::TypeBell: + if (v.action ().state () & CompAction::StateAutoGrab && screen) + screen->removeAction (&v.action ()); + break; + + case CompOption::TypeList: + foreach (CompOption::Value &val, v.list ()) + finiOptionValue (val, v.listType ()); + break; + + default: + break; + } +} + +CompOption::~CompOption () +{ + finiOptionValue (priv->value, priv->type); + delete priv; +} + +void +CompOption::setName (CompString name, CompOption::Type type) +{ + priv->name = name; + priv->type = type; +} + +CompString +CompOption::name () +{ + return priv->name; +} + +CompOption::Type +CompOption::type () +{ + return priv->type; +} + +CompOption::Value & +CompOption::value () +{ + return priv->value; +} + +CompOption::Restriction & +CompOption::rest () +{ + return priv->rest; +} + +bool +CompOption::set (CompOption::Value &val) +{ + if (isAction () && priv->type != CompOption::TypeAction) + val.action ().copyState (priv->value.action ()); + + if (priv->type != val.type () && + (!isAction () || !checkIsAction (val.type ()))) + { + compLogMessage ("core", CompLogLevelWarn, + "Can't set Value with type %d to " + "option \"%s\" with type %d", + val.type (), priv->name.c_str (), priv->type); + return false; + } + + if (priv->value == val) + return false; + + if (isAction () && + priv->value.action ().state () & CompAction::StateAutoGrab && screen) + { + if (!screen->addAction (&val.action ())) + return false; + else + screen->removeAction (&priv->value.action ()); + } + + switch (priv->type) + { + case CompOption::TypeInt: + if (!priv->rest.inRange (val.i ())) + return false; + break; + + case CompOption::TypeFloat: + { + float v, p; + int sign = (val.f () < 0 ? -1 : 1); + + if (!priv->rest.inRange (val.f ())) + return false; + + p = 1.0f / priv->rest.fPrecision (); + v = ((int) (val.f () * p + sign * 0.5f)) / p; + + priv->value.set (v); + return true; + } + + case CompOption::TypeAction: + return false; + + case CompOption::TypeKey: + if (val.action ().type () == value().action ().type () && + !(val.action ().type () & CompAction::BindingTypeKey)) + return false; + break; + + case CompOption::TypeButton: + if (val.action ().type () == value().action ().type () && + !(val.action ().type () & (CompAction::BindingTypeButton | + CompAction::BindingTypeEdgeButton))) + return false; + break; + + default: + break; + } + + priv->value = val; + + return true; +} + +bool +CompOption::isAction () +{ + return checkIsAction (priv->type); +} + +CompOption & +CompOption::operator= (const CompOption &option) +{ + delete priv; + priv = new PrivateOption (*option.priv); + return *this; +} + +bool +CompOption::getBoolOptionNamed (const Vector& options, + const CompString& name, + bool defaultValue) +{ + foreach (const CompOption &o, options) + if (o.priv->type == CompOption::TypeBool && o.priv->name == name) + return o.priv->value.b (); + + return defaultValue; +} + +int +CompOption::getIntOptionNamed (const Vector& options, + const CompString& name, + int defaultValue) +{ + foreach (const CompOption &o, options) + if (o.priv->type == CompOption::TypeInt && o.priv->name == name) + return o.priv->value.i (); + + return defaultValue; +} + +float +CompOption::getFloatOptionNamed (const Vector& options, + const CompString& name, + const float& defaultValue) +{ + foreach (const CompOption &o, options) + if (o.priv->type == CompOption::TypeFloat && o.priv->name == name) + return o.priv->value.f (); + + return defaultValue; +} + +CompString +CompOption::getStringOptionNamed (const Vector& options, + const CompString& name, + const CompString& defaultValue) +{ + foreach (const CompOption &o, options) + if (o.priv->type == CompOption::TypeString && o.priv->name == name) + return o.priv->value.s (); + + return defaultValue; +} + +unsigned short * +CompOption::getColorOptionNamed (const Vector& options, + const CompString& name, + unsigned short *defaultValue) +{ + foreach (const CompOption &o, options) + if (o.priv->type == CompOption::TypeColor && o.priv->name == name) + return o.priv->value.c (); + + return defaultValue; +} + +CompMatch +CompOption::getMatchOptionNamed (const Vector& options, + const CompString& name, + const CompMatch& defaultValue) +{ + foreach (const CompOption &o, options) + if (o.priv->type == CompOption::TypeMatch && o.priv->name == name) + return o.priv->value.match (); + + return defaultValue; +} + +bool +CompOption::stringToColor (CompString color, + unsigned short *rgba) +{ + int c[4]; + + if (sscanf (color.c_str (), "#%2x%2x%2x%2x", + &c[0], &c[1], &c[2], &c[3]) == 4) + { + rgba[0] = c[0] << 8 | c[0]; + rgba[1] = c[1] << 8 | c[1]; + rgba[2] = c[2] << 8 | c[2]; + rgba[3] = c[3] << 8 | c[3]; + + return true; + } + + return false; +} + +CompString +CompOption::colorToString (unsigned short *rgba) +{ + return compPrintf ("#%.2x%.2x%.2x%.2x", rgba[0] / 256, rgba[1] / 256, + rgba[2] / 256, rgba[3] / 256); +} + +CompString +CompOption::typeToString (CompOption::Type type) +{ + switch (type) { + case CompOption::TypeBool: + return "bool"; + case CompOption::TypeInt: + return "int"; + case CompOption::TypeFloat: + return "float"; + case CompOption::TypeString: + return "string"; + case CompOption::TypeColor: + return "color"; + case CompOption::TypeAction: + return "action"; + case CompOption::TypeKey: + return "key"; + case CompOption::TypeButton: + return "button"; + case CompOption::TypeEdge: + return "edge"; + case CompOption::TypeBell: + return "bell"; + case CompOption::TypeMatch: + return "match"; + case CompOption::TypeList: + return "list"; + default: + break; + } + + return "unknown"; +} + +bool +CompOption::setOption (CompOption &o, + CompOption::Value &value) +{ + return o.set (value); +} + +PrivateOption::PrivateOption () : + name (""), + type (CompOption::TypeUnset), + value (), + rest () +{ +} + +PrivateOption::PrivateOption (const PrivateOption &p) : + name (p.name), + type (p.type), + value (p.value), + rest (p.rest) +{ +} + diff --git a/src/output.cpp b/src/output.cpp new file mode 100644 index 0000000..a1d1940 --- /dev/null +++ b/src/output.cpp @@ -0,0 +1,90 @@ +/* + * Copyright © 2008 Dennis Kasprzyk + * Copyright © 2007 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Dennis Kasprzyk not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Dennis Kasprzyk makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org> + * David Reveman <davidr@novell.com> + */ + +#include <core/core.h> +#include <core/output.h> + +CompOutput::CompOutput () +{ + mName = ""; + mId = ~0; +} + +CompString +CompOutput::name () const +{ + return mName; +} + +unsigned int +CompOutput::id () const +{ + return mId; +} + +const CompRect& +CompOutput::workArea () const +{ + return mWorkArea; +} + +void +CompOutput::setWorkArea (const CompRect& workarea) +{ + mWorkArea = workarea; + + if (workarea.x () < (int) x1 ()) + mWorkArea.setX (x1 ()); + + if (workarea.y () < (int) y1 ()) + mWorkArea.setY (y1 ()); + + if (workarea.x2 () > (int) x2 ()) + mWorkArea.setWidth (x2 () - mWorkArea.x ()); + + if (workarea.y2 () > (int) y2 ()) + mWorkArea.setHeight (y2 () - mWorkArea.y ()); +} + +void +CompOutput::setGeometry (int x, + int y, + int width, + int height) +{ + CompRect::setGeometry (x, y, width, height); + + mWorkArea = *this; +} + +void +CompOutput::setId (CompString name, unsigned int id) +{ + mName = name; + mId = id; +} + diff --git a/src/plugin.cpp b/src/plugin.cpp new file mode 100644 index 0000000..f9d8954 --- /dev/null +++ b/src/plugin.cpp @@ -0,0 +1,700 @@ +/* + * Copyright © 2005 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * Novell, Inc. makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: David Reveman <davidr@novell.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <dirent.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <list> + +#include <boost/foreach.hpp> +#define foreach BOOST_FOREACH + +#include <core/core.h> +#include "privatescreen.h" + +CompPlugin::Map pluginsMap; +CompPlugin::List plugins; + +class CorePluginVTable : public CompPlugin::VTable +{ + public: + + bool init (); + + CompOption::Vector & getOptions (); + + bool setOption (const CompString &name, + CompOption::Value &value); +}; + +COMPIZ_PLUGIN_20090315 (core, CorePluginVTable) + +CompPlugin::VTable * getCoreVTable () +{ + if (!coreVTable) + { + return getCompPluginVTable20090315_core (); + } + + return coreVTable; +} + +bool +CorePluginVTable::init () +{ + return true; +} + +CompOption::Vector & +CorePluginVTable::getOptions () +{ + return screen->getOptions (); +} + +bool +CorePluginVTable::setOption (const CompString &name, + CompOption::Value &value) +{ + return screen->setOption (name, value); +} + +static bool +cloaderLoadPlugin (CompPlugin *p, + const char *path, + const char *name) +{ + if (path) + return false; + + if (strcmp (name, getCoreVTable ()->name ().c_str ())) + return false; + + p->vTable = getCoreVTable (); + p->devPrivate.ptr = NULL; + p->devType = "cloader"; + + return true; +} + +static void +cloaderUnloadPlugin (CompPlugin *p) +{ + delete p->vTable; +} + +static CompStringList +cloaderListPlugins (const char *path) +{ + CompStringList rv; + + if (path) + return CompStringList (); + + rv.push_back (CompString (getCoreVTable ()->name ())); + + return rv; +} + +static bool +dlloaderLoadPlugin (CompPlugin *p, + const char *path, + const char *name) +{ + CompString file; + void *dlhand; + bool loaded = false; + struct stat fileInfo; + + if (cloaderLoadPlugin (p, path, name)) + return true; + + if (path) + { + file = path; + file += "/"; + } + + file += "lib"; + file += name; + file += ".so"; + + if (stat (file.c_str (), &fileInfo) != 0) + { + /* file likely not present */ + compLogMessage ("core", CompLogLevelDebug, + "Could not stat() file %s : %s", + file.c_str (), strerror (errno)); + return false; + } + + dlhand = dlopen (file.c_str (), RTLD_LAZY); + if (dlhand) + { + PluginGetInfoProc getInfo; + char *error; + char sym[1024]; + + dlerror (); + + snprintf (sym, 1024, "getCompPluginVTable20090315_%s", name); + getInfo = (PluginGetInfoProc) dlsym (dlhand, sym); + + error = dlerror (); + if (error) + { + compLogMessage ("core", CompLogLevelError, "dlsym: %s", error); + getInfo = 0; + } + + if (getInfo) + { + p->vTable = (*getInfo) (); + if (!p->vTable) + { + compLogMessage ("core", CompLogLevelError, + "Couldn't get vtable from '%s' plugin", + file.c_str ()); + } + else + { + p->devPrivate.ptr = dlhand; + p->devType = "dlloader"; + loaded = true; + } + } + } + else + { + compLogMessage ("core", CompLogLevelError, + "Couldn't load plugin '%s' : %s", + file.c_str (), dlerror ()); + } + + if (!loaded && dlhand) + dlclose (dlhand); + + return loaded; +} + +static void +dlloaderUnloadPlugin (CompPlugin *p) +{ + if (p->devType == "dlloader") + { + delete p->vTable; + dlclose (p->devPrivate.ptr); + } + else + cloaderUnloadPlugin (p); +} + +static int +dlloaderFilter (const struct dirent *name) +{ + int length = strlen (name->d_name); + + if (length < 7) + return 0; + + if (strncmp (name->d_name, "lib", 3) || + strncmp (name->d_name + length - 3, ".so", 3)) + return 0; + + return 1; +} + +static CompStringList +dlloaderListPlugins (const char *path) +{ + struct dirent **nameList; + char name[1024]; + int length, nFile, i; + + CompStringList rv = cloaderListPlugins (path); + + if (!path) + path = "."; + + nFile = scandir (path, &nameList, dlloaderFilter, alphasort); + if (!nFile) + return rv; + + for (i = 0; i < nFile; i++) + { + length = strlen (nameList[i]->d_name); + + strncpy (name, nameList[i]->d_name + 3, length - 6); + name[length - 6] = '\0'; + + rv.push_back (CompString (name)); + } + + return rv; +} + +LoadPluginProc loaderLoadPlugin = dlloaderLoadPlugin; +UnloadPluginProc loaderUnloadPlugin = dlloaderUnloadPlugin; +ListPluginsProc loaderListPlugins = dlloaderListPlugins; + + +static bool +initPlugin (CompPlugin *p) +{ + + if (!p->vTable->init ()) + { + compLogMessage ("core", CompLogLevelError, + "InitPlugin '%s' failed", p->vTable->name ().c_str ()); + return false; + } + + if (screen) + { + if (!p->vTable->initScreen (screen)) + { + compLogMessage (p->vTable->name ().c_str (), CompLogLevelError, + "initScreen failed"); + p->vTable->fini (); + return false; + } + if (!screen->initPluginForScreen (p)) + { + p->vTable->fini (); + return false; + } + } + + return true; +} + +static void +finiPlugin (CompPlugin *p) +{ + + if (screen) + { + screen->finiPluginForScreen (p); + p->vTable->finiScreen (screen); + } + + p->vTable->fini (); +} + +bool +CompScreen::initPluginForScreen (CompPlugin *p) +{ + WRAPABLE_HND_FUNC_RETURN (2, bool, initPluginForScreen, p) + + bool status = true; + CompWindowList::iterator it, fail; + CompWindow *w; + + it = fail = priv->windows.begin (); + for (;it != priv->windows.end (); it++) + { + w = *it; + if (!p->vTable->initWindow (w)) + { + compLogMessage (p->vTable->name ().c_str (), CompLogLevelError, + "initWindow failed"); + fail = it; + status = false; + } + } + + it = priv->windows.begin (); + for (;it != fail; it++) + { + w = *it; + p->vTable->finiWindow (w); + } + + return status; +} + +void +CompScreen::finiPluginForScreen (CompPlugin *p) +{ + WRAPABLE_HND_FUNC (3, finiPluginForScreen, p) + + foreach (CompWindow *w, priv->windows) + p->vTable->finiWindow (w); +} + +bool +CompPlugin::screenInitPlugins (CompScreen *s) +{ + CompPlugin::List::reverse_iterator rit = plugins.rbegin (); + + CompPlugin *p = NULL; + + while (rit != plugins.rend ()) + { + p = (*rit); + + if (p->vTable->initScreen (s)) + s->initPluginForScreen (p); + + rit++; + } + + return true; +} + +void +CompPlugin::screenFiniPlugins (CompScreen *s) +{ + foreach (CompPlugin *p, plugins) + { + s->finiPluginForScreen (p); + p->vTable->finiScreen (s); + } + +} + +bool +CompPlugin::windowInitPlugins (CompWindow *w) +{ + bool status = true; + + CompPlugin::List::reverse_iterator rit = plugins.rbegin (); + + CompPlugin *p = NULL; + + while (rit != plugins.rend ()) + { + p = (*rit); + + status &= p->vTable->initWindow (w); + + rit++; + } + + return status; +} + +void +CompPlugin::windowFiniPlugins (CompWindow *w) +{ + foreach (CompPlugin *p, plugins) + { + p->vTable->finiWindow (w); + } +} + + +CompPlugin * +CompPlugin::find (const char *name) +{ + CompPlugin::Map::iterator it = pluginsMap.find (name); + + if (it != pluginsMap.end ()) + return it->second; + + return NULL; +} + +void +CompPlugin::unload (CompPlugin *p) +{ + (*loaderUnloadPlugin) (p); + delete p; +} + +CompPlugin * +CompPlugin::load (const char *name) +{ + CompPlugin *p; + char *home, *plugindir; + bool status; + + p = new CompPlugin (); + if (!p) + return 0; + + p->devPrivate.uval = 0; + p->devType = ""; + p->vTable = 0; + + home = getenv ("HOME"); + if (home) + { + plugindir = (char *) malloc (strlen (home) + strlen (HOME_PLUGINDIR) + 3); + if (plugindir) + { + sprintf (plugindir, "%s/%s", home, HOME_PLUGINDIR); + status = (*loaderLoadPlugin) (p, plugindir, name); + free (plugindir); + + if (status) + return p; + } + } + + status = (*loaderLoadPlugin) (p, PLUGINDIR, name); + if (status) + return p; + + status = (*loaderLoadPlugin) (p, NULL, name); + if (status) + return p; + + compLogMessage ("core", CompLogLevelError, + "Couldn't load plugin '%s'", name); + + return 0; +} + +bool +CompPlugin::push (CompPlugin *p) +{ + const char *name = p->vTable->name ().c_str (); + + std::pair<CompPlugin::Map::iterator, bool> insertRet = + pluginsMap.insert (std::pair<const char *, CompPlugin *> (name, p)); + + if (!insertRet.second) + { + compLogMessage ("core", CompLogLevelWarn, + "Plugin '%s' already active", + p->vTable->name ().c_str ()); + + return false; + } + + plugins.push_front (p); + + if (!initPlugin (p)) + { + compLogMessage ("core", CompLogLevelError, + "Couldn't activate plugin '%s'", name); + + pluginsMap.erase (name); + plugins.pop_front (); + + return false; + } + + return true; +} + +CompPlugin * +CompPlugin::pop (void) +{ + if (plugins.empty ()) + return NULL; + + CompPlugin *p = plugins.front (); + + if (!p) + return 0; + + pluginsMap.erase (p->vTable->name ().c_str ()); + + finiPlugin (p); + + plugins.pop_front (); + + return p; +} + +CompPlugin::List & +CompPlugin::getPlugins (void) +{ + return plugins; +} + +static bool +stringExist (CompStringList &list, + CompString s) +{ + foreach (CompString &l, list) + if (s.compare (l) == 0) + return true; + + return false; +} + +CompStringList +CompPlugin::availablePlugins () +{ + char *home, *plugindir; + CompStringList list, currentList, pluginList, homeList; + + home = getenv ("HOME"); + if (home) + { + plugindir = (char *) malloc (strlen (home) + strlen (HOME_PLUGINDIR) + 3); + if (plugindir) + { + sprintf (plugindir, "%s/%s", home, HOME_PLUGINDIR); + homeList = (*loaderListPlugins) (plugindir); + free (plugindir); + } + } + + pluginList = (*loaderListPlugins) (PLUGINDIR); + currentList = (*loaderListPlugins) (NULL); + + if (!homeList.empty ()) + { + foreach (CompString &s, homeList) + if (!stringExist (list, s)) + list.push_back (s); + } + + if (!pluginList.empty ()) + { + foreach (CompString &s, pluginList) + if (!stringExist (list, s)) + list.push_back (s); + } + + if (!currentList.empty ()) + { + foreach (CompString &s, currentList) + if (!stringExist (list, s)) + list.push_back (s); + } + + return list; +} + +int +CompPlugin::getPluginABI (const char *name) +{ + CompPlugin *p = find (name); + CompString s = name; + + if (!p) + return 0; + + s += "_ABI"; + + if (!screen->hasValue (s)) + return 0; + + return screen->getValue (s).uval; +} + +bool +CompPlugin::checkPluginABI (const char *name, + int abi) +{ + int pluginABI; + + pluginABI = getPluginABI (name); + if (!pluginABI) + { + compLogMessage ("core", CompLogLevelError, + "Plugin '%s' not loaded.\n", name); + return false; + } + else if (pluginABI != abi) + { + compLogMessage ("core", CompLogLevelError, + "Plugin '%s' has ABI version '%d', expected " + "ABI version '%d'.\n", + name, pluginABI, abi); + return false; + } + + return true; +} + +CompPlugin::VTable::VTable () : + mName (""), + mSelf (NULL) +{ +} + +CompPlugin::VTable::~ |