diff options
Diffstat (limited to 'plugins/unityshell/src')
31 files changed, 2541 insertions, 527 deletions
diff --git a/plugins/unityshell/src/CompoundGestureRecognizer.cpp b/plugins/unityshell/src/CompoundGestureRecognizer.cpp new file mode 100644 index 000000000..bbbbc88cc --- /dev/null +++ b/plugins/unityshell/src/CompoundGestureRecognizer.cpp @@ -0,0 +1,250 @@ +/* + * CompoundGestureRecognizer.cpp + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + */ + +#include "CompoundGestureRecognizer.h" +#include <NuxCore/Logger.h> +#include <NuxGraphics/GestureEvent.h> + +namespace +{ + nux::logging::Logger logger("unity.compound_gesture_recognizer"); +} + +namespace unity +{ + class CompoundGestureRecognizerPrivate + { + public: + CompoundGestureRecognizerPrivate(); + + enum class State + { + WaitingFirstTapBegin, + WaitingFirstTapEnd, + WaitingSecondGestureBegin, + RecognizingSecondGesture + }; + + RecognitionResult GestureEvent(nux::GestureEvent const& event); + + RecognitionResult WaitingFirstTapBegin(nux::GestureEvent const& event); + RecognitionResult WaitingFirstTapEnd(nux::GestureEvent const& event); + RecognitionResult WaitingSecondGestureBegin(nux::GestureEvent const& event); + RecognitionResult RecognizingSecondGesture(nux::GestureEvent const& event); + void ResetStateMachine(); + + State state; + + class GestureInfo + { + public: + GestureInfo() {Clear();} + int begin_time; + int end_time; + int id; + int Duration() const {return end_time - begin_time;} + void Clear() {begin_time = end_time = id = -1;} + }; + GestureInfo first_gesture; + GestureInfo second_gesture; + }; +} + +using namespace unity; + +/////////////////////////////////////////// +// private class + +CompoundGestureRecognizerPrivate::CompoundGestureRecognizerPrivate() + : state(State::WaitingFirstTapBegin) +{ +} + +RecognitionResult CompoundGestureRecognizerPrivate::GestureEvent(nux::GestureEvent const& event) +{ + switch (state) + { + case State::WaitingFirstTapBegin: + return WaitingFirstTapBegin(event); + break; + case State::WaitingFirstTapEnd: + return WaitingFirstTapEnd(event); + break; + case State::WaitingSecondGestureBegin: + return WaitingSecondGestureBegin(event); + break; + default: // State::RecognizingSecondGesture: + return RecognizingSecondGesture(event); + } +} + +RecognitionResult CompoundGestureRecognizerPrivate::WaitingFirstTapBegin(nux::GestureEvent const& event) +{ + if (event.type == nux::EVENT_GESTURE_BEGIN) + { + first_gesture.id = event.GetGestureId(); + first_gesture.begin_time = event.GetTimestamp(); + state = State::WaitingFirstTapEnd; + } + return RecognitionResult::NONE; +} + +RecognitionResult CompoundGestureRecognizerPrivate::WaitingFirstTapEnd(nux::GestureEvent const& event) +{ + if (event.type != nux::EVENT_GESTURE_END) + return RecognitionResult::NONE; + + if (first_gesture.id != event.GetGestureId()) + { + ResetStateMachine(); + return RecognitionResult::NONE; + } + + if (event.GetGestureClasses() != nux::TOUCH_GESTURE) + { + // some other gesture class such as drag or pinch was also recognized, + // meaning that the touch points moved too much and therefore it cannot + // be a tap. + ResetStateMachine(); + return RecognitionResult::NONE; + } + + first_gesture.end_time = event.GetTimestamp(); + if (first_gesture.Duration() > CompoundGestureRecognizer::MAX_TAP_TIME) + { + // can't be a tap. it took too long + ResetStateMachine(); + return RecognitionResult::NONE; + } + + state = State::WaitingSecondGestureBegin; + + return RecognitionResult::NONE; +} + +RecognitionResult CompoundGestureRecognizerPrivate::WaitingSecondGestureBegin( + nux::GestureEvent const& event) +{ + + if (event.type != nux::EVENT_GESTURE_BEGIN) + { + // that's not right. there shouldn't be any ongoing gesture now. + ResetStateMachine(); + return RecognitionResult::NONE; + } + + if (event.GetGestureClasses() != nux::TOUCH_GESTURE) + { + ResetStateMachine(); + return RecognitionResult::NONE; + } + + int interval = event.GetTimestamp() - first_gesture.end_time; + if (interval > CompoundGestureRecognizer::MAX_TIME_BETWEEN_GESTURES) + { + ResetStateMachine(); + // consider it as the possible first tap of a new compound gesture + GestureEvent(event); + return RecognitionResult::NONE; + } + + second_gesture.id = event.GetGestureId(); + second_gesture.begin_time = event.GetTimestamp(); + + state = State::RecognizingSecondGesture; + + return RecognitionResult::NONE; +} + +RecognitionResult CompoundGestureRecognizerPrivate::RecognizingSecondGesture( + nux::GestureEvent const& event) +{ + if (event.GetGestureId() != second_gesture.id) + { + // no simultaneous gestures + ResetStateMachine(); + return RecognitionResult::NONE; + } + + if (event.GetGestureClasses() != nux::TOUCH_GESTURE) + { + // some other gesture class such as drag or pinch was also recognized, + // meaning that the touch points moved too much and therefore it cannot + // be a tap or a hold + ResetStateMachine(); + return RecognitionResult::NONE; + } + + RecognitionResult result = RecognitionResult::NONE; + + if (event.type == nux::EVENT_GESTURE_UPDATE) + { + if (event.GetTimestamp() - second_gesture.begin_time >= CompoundGestureRecognizer::HOLD_TIME) + { + result = RecognitionResult::TAP_AND_HOLD_RECOGNIZED; + ResetStateMachine(); + } + } + else if (event.type == nux::EVENT_GESTURE_END) + { + second_gesture.end_time = event.GetTimestamp(); + + if (second_gesture.Duration() <= CompoundGestureRecognizer::MAX_TAP_TIME) + { + result = RecognitionResult::DOUBLE_TAP_RECOGNIZED; + } + ResetStateMachine(); + } + else + { + // This really shouldn't happen. + LOG_ERROR(logger) << "Unexpected gesture type." + " CompoundGestureRecognizer left in an undefined state."; + } + + return result; +} + +void CompoundGestureRecognizerPrivate::ResetStateMachine() +{ + first_gesture.Clear(); + second_gesture.Clear(); + state = State::WaitingFirstTapBegin; +} + +/////////////////////////////////////////// +// public class + +CompoundGestureRecognizer::CompoundGestureRecognizer() + : p(new CompoundGestureRecognizerPrivate) +{ +} + +CompoundGestureRecognizer::~CompoundGestureRecognizer() +{ + delete p; +} + +RecognitionResult CompoundGestureRecognizer::GestureEvent(nux::GestureEvent const& event) +{ + return p->GestureEvent(event); +} diff --git a/plugins/unityshell/src/CompoundGestureRecognizer.h b/plugins/unityshell/src/CompoundGestureRecognizer.h new file mode 100644 index 000000000..bf6e64dfc --- /dev/null +++ b/plugins/unityshell/src/CompoundGestureRecognizer.h @@ -0,0 +1,71 @@ +/* + * CompoundGestureRecognizer.h + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + */ + +#ifndef COMPOUND_GESTURE_RECOGNIZER_H +#define COMPOUND_GESTURE_RECOGNIZER_H + +#include <sigc++/sigc++.h> + +namespace nux +{ + class GestureEvent; +} + +namespace unity +{ + +enum class RecognitionResult +{ + NONE, + DOUBLE_TAP_RECOGNIZED, /*! Returned when a double-tap is recognized */ + TAP_AND_HOLD_RECOGNIZED, /*!< Returned when a "tap and hold" is recognized + At this point the user is still "holding". I.e., + his fingers are still on the touchscreen or + trackpad. */ +}; + +class CompoundGestureRecognizerPrivate; + +/*! + Recognizes compound gestures. I.e. high level gestures that are maded up by + two sequencial regular gestures (like a tap followed by a second tap). + */ +class CompoundGestureRecognizer +{ + public: + // in milliseconds + static const int MAX_TIME_BETWEEN_GESTURES = 600; + static const int MAX_TAP_TIME = 300; + static const int HOLD_TIME = 600; + + CompoundGestureRecognizer(); + virtual ~CompoundGestureRecognizer(); + + virtual RecognitionResult GestureEvent(nux::GestureEvent const& event); + + private: + CompoundGestureRecognizerPrivate* p; +}; + +} // namespace unity + +#endif // COMPOUND_GESTURE_RECOGNIZER_H diff --git a/plugins/unityshell/src/GesturalWindowSwitcher.cpp b/plugins/unityshell/src/GesturalWindowSwitcher.cpp new file mode 100644 index 000000000..910762139 --- /dev/null +++ b/plugins/unityshell/src/GesturalWindowSwitcher.cpp @@ -0,0 +1,446 @@ +/* + * GesturalWindowSwitcher.cpp + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + */ + +#include "GesturalWindowSwitcher.h" +#include <Nux/Nux.h> +#include <NuxCore/Logger.h> +#include "unityshell.h" + +namespace +{ + nux::logging::Logger logger("unity.gestural_window_switcher"); +} + +using namespace nux; +using namespace unity; + +const float GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION = 100.0f; +const float GesturalWindowSwitcher::MOUSE_DRAG_THRESHOLD = 20.0f; + +namespace unity +{ + class GesturalWindowSwitcherPrivate + { + public: + GesturalWindowSwitcherPrivate(); + virtual ~GesturalWindowSwitcherPrivate(); + + void CloseSwitcherAfterTimeout(int timeout); + bool OnCloseSwitcherTimeout(); + void CloseSwitcher(); + + // show the switcher and select the next application/window + void InitiateSwitcherNext(); + + // show the switcher and select the previous application/window + void InitiateSwitcherPrevious(); + + void ProcessAccumulatedHorizontalDrag(); + + nux::GestureDeliveryRequest GestureEvent(nux::GestureEvent const& event); + + nux::GestureDeliveryRequest WaitingCompoundGesture(nux::GestureEvent const& event); + nux::GestureDeliveryRequest WaitingEndOfTapAndHold(nux::GestureEvent const& event); + nux::GestureDeliveryRequest WaitingSwitcherManipulation(nux::GestureEvent const& event); + nux::GestureDeliveryRequest DraggingSwitcher(nux::GestureEvent const& event); + nux::GestureDeliveryRequest RecognizingMouseClickOrDrag(nux::GestureEvent const& event); + nux::GestureDeliveryRequest DraggingSwitcherWithMouse(nux::GestureEvent const& event); + + void ProcessSwitcherViewMouseDown(int x, int y, + unsigned long button_flags, unsigned long key_flags); + void ProcessSwitcherViewMouseUp(int x, int y, + unsigned long button_flags, unsigned long key_flags); + void ProcessSwitcherViewMouseDrag(int x, int y, int dx, int dy, + unsigned long button_flags, unsigned long key_flags); + + void ConnectToSwitcherViewMouseEvents(); + + enum class State + { + WaitingCompoundGesture, + WaitingEndOfTapAndHold, + WaitingSwitcherManipulation, + DraggingSwitcher, + RecognizingMouseClickOrDrag, + DraggingSwitcherWithMouse, + WaitingMandatorySwitcherClose, + } state; + + unity::UnityScreen* unity_screen; + unity::switcher::Controller::Ptr switcher_controller; + CompoundGestureRecognizer gesture_recognizer; + CompTimer timer_close_switcher; + float accumulated_horizontal_drag; + int index_icon_hit; + + sigc::connection view_built_connection; + sigc::connection mouse_down_connection; + sigc::connection mouse_up_connection; + sigc::connection mouse_drag_connection; + }; +} + +/////////////////////////////////////////// +// private class + +GesturalWindowSwitcherPrivate::GesturalWindowSwitcherPrivate() +{ + state = State::WaitingCompoundGesture; + + unity_screen = unity::UnityScreen::get(screen); + switcher_controller = unity_screen->switcher_controller(); + + timer_close_switcher.setCallback( + boost::bind(&GesturalWindowSwitcherPrivate::OnCloseSwitcherTimeout, this)); + + view_built_connection = switcher_controller->view_built.connect( + sigc::mem_fun(this, &GesturalWindowSwitcherPrivate::ConnectToSwitcherViewMouseEvents)); +} + +GesturalWindowSwitcherPrivate::~GesturalWindowSwitcherPrivate() +{ + view_built_connection.disconnect(); + mouse_down_connection.disconnect(); + mouse_up_connection.disconnect(); + mouse_drag_connection.disconnect(); +} + +GestureDeliveryRequest GesturalWindowSwitcherPrivate::GestureEvent(nux::GestureEvent const& event) +{ + switch (state) + { + case State::WaitingCompoundGesture: + return WaitingCompoundGesture(event); + break; + case State::WaitingEndOfTapAndHold: + return WaitingEndOfTapAndHold(event); + break; + case State::WaitingSwitcherManipulation: + return WaitingSwitcherManipulation(event); + break; + case State::DraggingSwitcher: + return DraggingSwitcher(event); + break; + case State::RecognizingMouseClickOrDrag: + return RecognizingMouseClickOrDrag(event); + break; + case State::DraggingSwitcherWithMouse: + return DraggingSwitcherWithMouse(event); + break; + case State::WaitingMandatorySwitcherClose: + // do nothing + return GestureDeliveryRequest::NONE; + break; + default: + g_assert(false); // should never happen + return GestureDeliveryRequest::NONE; + break; + } +} + +GestureDeliveryRequest GesturalWindowSwitcherPrivate::WaitingCompoundGesture(nux::GestureEvent const& event) +{ + GestureDeliveryRequest request = GestureDeliveryRequest::NONE; + + switch (gesture_recognizer.GestureEvent(event)) + { + case RecognitionResult::NONE: + // Do nothing; + break; + case RecognitionResult::DOUBLE_TAP_RECOGNIZED: + InitiateSwitcherNext(); + CloseSwitcherAfterTimeout(GesturalWindowSwitcher::SWITCHER_TIME_AFTER_DOUBLE_TAP); + break; + default: // RecognitionResult::TAP_AND_HOLD_RECOGNIZED: + InitiateSwitcherNext(); + request = GestureDeliveryRequest::EXCLUSIVITY; + state = State::WaitingEndOfTapAndHold; + } + + return request; +} + +GestureDeliveryRequest GesturalWindowSwitcherPrivate::WaitingEndOfTapAndHold(nux::GestureEvent const& event) +{ + GestureDeliveryRequest request = GestureDeliveryRequest::NONE; + + if (event.type == EVENT_GESTURE_BEGIN) + { + LOG_ERROR(logger) << "There should be no simultaneous/overlapping gestures."; + return request; + } + + if (event.type == EVENT_GESTURE_UPDATE) + { + if (event.GetGestureClasses() & nux::DRAG_GESTURE) + { + state = State::DraggingSwitcher; + accumulated_horizontal_drag = 0.0f; + request = DraggingSwitcher(event); + } + } + else // event.type == EVENT_GESTURE_END + { + CloseSwitcherAfterTimeout(GesturalWindowSwitcher::SWITCHER_TIME_AFTER_HOLD_RELEASED); + state = State::WaitingSwitcherManipulation; + } + + return request; +} + +GestureDeliveryRequest +GesturalWindowSwitcherPrivate::WaitingSwitcherManipulation(nux::GestureEvent const& event) +{ + GestureDeliveryRequest request = GestureDeliveryRequest::NONE; + + if (event.type == EVENT_GESTURE_BEGIN) + { + // Don't leak gestures to windows behind the switcher + request = GestureDeliveryRequest::EXCLUSIVITY; + } + + if (event.GetGestureClasses() & nux::DRAG_GESTURE) + { + state = State::DraggingSwitcher; + timer_close_switcher.stop(); + DraggingSwitcher(event); + } + + return request; +} + +GestureDeliveryRequest GesturalWindowSwitcherPrivate::DraggingSwitcher(nux::GestureEvent const& event) +{ + if (event.type == EVENT_GESTURE_BEGIN) + { + LOG_ERROR(logger) << "There should be no simultaneous/overlapping gestures."; + return GestureDeliveryRequest::NONE; + } + + if (!(event.GetGestureClasses() & nux::DRAG_GESTURE)) + { + LOG_ERROR(logger) << "Didn't get the expected drag gesture."; + return GestureDeliveryRequest::NONE; + } + + if (event.type == EVENT_GESTURE_UPDATE) + { + accumulated_horizontal_drag += event.GetDelta().x; + ProcessAccumulatedHorizontalDrag(); + } + else // event.type == EVENT_GESTURE_END + { + CloseSwitcher(); + state = State::WaitingCompoundGesture; + } + + return GestureDeliveryRequest::NONE; +} + +GestureDeliveryRequest +GesturalWindowSwitcherPrivate::RecognizingMouseClickOrDrag(nux::GestureEvent const& event) +{ + // Mouse press event has come but gestures have precedence over mouse + // for interacting with the switcher. + // Therefore act in the same way is if the mouse press didn't come + return WaitingSwitcherManipulation(event); +} + +GestureDeliveryRequest +GesturalWindowSwitcherPrivate::DraggingSwitcherWithMouse(nux::GestureEvent const& event) +{ + // Mouse press event has come but gestures have precedence over mouse + // for interacting with the switcher. + // Therefore act in the same way is if the mouse press didn't come + return WaitingSwitcherManipulation(event); +} + +void GesturalWindowSwitcherPrivate::CloseSwitcherAfterTimeout(int timeout) +{ + timer_close_switcher.stop(); + // min and max timeouts + timer_close_switcher.setTimes(timeout, + timeout+50); + timer_close_switcher.start(); +} + +bool GesturalWindowSwitcherPrivate::OnCloseSwitcherTimeout() +{ + + switch (state) + { + case State::WaitingSwitcherManipulation: + case State::WaitingMandatorySwitcherClose: + state = State::WaitingCompoundGesture; + CloseSwitcher(); + break; + default: + CloseSwitcher(); + } + // I'm assuming that by returning false I'm telling the timer to stop. + return false; +} + +void GesturalWindowSwitcherPrivate::CloseSwitcher() +{ + switcher_controller->Hide(); +} + +void GesturalWindowSwitcherPrivate::InitiateSwitcherNext() +{ + timer_close_switcher.stop(); + + if (switcher_controller->Visible()) + switcher_controller->Next(); + else + { + unity_screen->SetUpAndShowSwitcher(); + } +} + +void GesturalWindowSwitcherPrivate::InitiateSwitcherPrevious() +{ + timer_close_switcher.stop(); + + if (switcher_controller->Visible()) + { + switcher_controller->Prev(); + } +} + +void GesturalWindowSwitcherPrivate::ProcessSwitcherViewMouseDown(int x, int y, + unsigned long button_flags, unsigned long key_flags) +{ + if (state != State::WaitingSwitcherManipulation) + return; + + // Don't close the switcher while the mouse is pressed over it + timer_close_switcher.stop(); + + state = State::RecognizingMouseClickOrDrag; + + index_icon_hit = switcher_controller->GetView()->IconIndexAt(x, y); + accumulated_horizontal_drag = 0.0f; +} + +void GesturalWindowSwitcherPrivate::ProcessSwitcherViewMouseUp(int x, int y, + unsigned long button_flags, unsigned long key_flags) +{ + switch (state) + { + case State::RecognizingMouseClickOrDrag: + if (index_icon_hit >= 0) + { + // it was a click after all. + switcher_controller->Select(index_icon_hit); + // it was not a double tap gesture but we use the same timeout + CloseSwitcherAfterTimeout(GesturalWindowSwitcher::SWITCHER_TIME_AFTER_DOUBLE_TAP); + state = State::WaitingMandatorySwitcherClose; + } + else + { + CloseSwitcher(); + state = State::WaitingCompoundGesture; + } + break; + case State::DraggingSwitcherWithMouse: + CloseSwitcher(); + state = State::WaitingCompoundGesture; + break; + default: + // do nothing + break; + } +} + +void GesturalWindowSwitcherPrivate::ProcessSwitcherViewMouseDrag(int x, int y, int dx, int dy, + unsigned long button_flags, unsigned long key_flags) +{ + switch (state) + { + case State::RecognizingMouseClickOrDrag: + accumulated_horizontal_drag += dx; + if (fabsf(accumulated_horizontal_drag) >= + GesturalWindowSwitcher::MOUSE_DRAG_THRESHOLD) + { + state = State::DraggingSwitcherWithMouse; + ProcessAccumulatedHorizontalDrag(); + } + break; + case State::DraggingSwitcherWithMouse: + accumulated_horizontal_drag += dx; + ProcessAccumulatedHorizontalDrag(); + break; + default: + // do nothing + break; + } +} + +void GesturalWindowSwitcherPrivate::ProcessAccumulatedHorizontalDrag() +{ + if (accumulated_horizontal_drag >= + GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION) + { + InitiateSwitcherNext(); + accumulated_horizontal_drag = 0.0f; + } + else if (accumulated_horizontal_drag <= + -GesturalWindowSwitcher::DRAG_DELTA_FOR_CHANGING_SELECTION) + { + InitiateSwitcherPrevious(); + accumulated_horizontal_drag = 0.0f; + } +} + +void GesturalWindowSwitcherPrivate::ConnectToSwitcherViewMouseEvents() +{ + unity::switcher::SwitcherView *switcher_view = switcher_controller->GetView(); + g_assert(switcher_view); + + mouse_down_connection = switcher_view->mouse_down.connect( + sigc::mem_fun(this, &GesturalWindowSwitcherPrivate::ProcessSwitcherViewMouseDown)); + + mouse_up_connection = switcher_view->mouse_up.connect( + sigc::mem_fun(this, &GesturalWindowSwitcherPrivate::ProcessSwitcherViewMouseUp)); + + mouse_drag_connection = switcher_view->mouse_drag.connect( + sigc::mem_fun(this, &GesturalWindowSwitcherPrivate::ProcessSwitcherViewMouseDrag)); +} + +/////////////////////////////////////////// +// public class + +GesturalWindowSwitcher::GesturalWindowSwitcher() + : p(new GesturalWindowSwitcherPrivate) +{ +} + +GesturalWindowSwitcher::~GesturalWindowSwitcher() +{ + delete p; +} + +GestureDeliveryRequest GesturalWindowSwitcher::GestureEvent(nux::GestureEvent const& event) +{ + return p->GestureEvent(event); +} diff --git a/plugins/unityshell/src/GesturalWindowSwitcher.h b/plugins/unityshell/src/GesturalWindowSwitcher.h new file mode 100644 index 000000000..527c7e301 --- /dev/null +++ b/plugins/unityshell/src/GesturalWindowSwitcher.h @@ -0,0 +1,85 @@ +/* + * GesturalWindowSwitcher.h + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> + */ + +#ifndef GESTURAL_WINDOW_SWITCHER_H +#define GESTURAL_WINDOW_SWITCHER_H + +#include <Nux/Gesture.h> +#include "CompoundGestureRecognizer.h" +#include "SwitcherController.h" +#include <core/timer.h> + +namespace unity +{ + +class UnityScreen; +class GesturalWindowSwitcherPrivate; + +/* + Manipulates the window switcher according to multi-touch gestures + + The following gestural interactions with the window switcher are implemented: + + 1. 3-fingers double tap -> switches to previous window + + 2. 3-fingers tap followed by 3-fingers hold -> shows window switcher + - drag those 3-fingers -> change selected window icon + - release fingers -> selects window and closes switcher + + 3. 3-fingers tap followed by 3-fingers hold -> shows window switcher + - release fingers -> switcher will kept being shown for some seconds still + - drag with one or three fingers -> change selected window + - release finger(s) -> selects window and closes switcher + + 4. 3-fingers tap followed by 3-fingers hold -> shows window switcher + - release fingers -> switcher will kept being shown for some seconds still + - tap on some window icon -> selects that icon and closes the switcher + + */ +class GesturalWindowSwitcher : public nux::GestureTarget +{ + public: + GesturalWindowSwitcher(); + virtual ~GesturalWindowSwitcher(); + + // in milliseconds + static const int SWITCHER_TIME_AFTER_DOUBLE_TAP = 350; + static const int SWITCHER_TIME_AFTER_HOLD_RELEASED = 7000; + + // How far, in screen pixels, a drag gesture must go in order + // to trigger a change in the selected window. + static const float DRAG_DELTA_FOR_CHANGING_SELECTION; + + // How far, in screen pixels, a mouse pointer must move in order + // to be considered dragging the switcher. + static const float MOUSE_DRAG_THRESHOLD; + + virtual nux::GestureDeliveryRequest GestureEvent(nux::GestureEvent const& event); + + private: + GesturalWindowSwitcherPrivate* p; +}; +typedef std::shared_ptr<GesturalWindowSwitcher> ShPtGesturalWindowSwitcher; + +} // namespace unity + +#endif // GESTURAL_WINDOW_SWITCHER_H diff --git a/plugins/unityshell/src/GestureEngine.cpp b/plugins/unityshell/src/GestureEngine.cpp deleted file mode 100644 index 9bf825b3a..000000000 --- a/plugins/unityshell/src/GestureEngine.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/* - * GestureEngine.cpp - * This file is part of Unity - * - * Copyright (C) 2011 - Canonical Ltd. - * - * Unity is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Unity is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Unity; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include <X11/cursorfont.h> - -#include "ubus-server.h" -#include "UBusMessages.h" -#include "GestureEngine.h" -#include "PluginAdapter.h" - -GestureEngine::GestureEngine(CompScreen* screen) -{ - _screen = screen; - - _drag_id = 0; - _drag_window = 0; - _pinch_id = 0; - _touch_id = 0; - _drag_grab = 0; - _pinch_grab = 0; - _fleur_cursor = XCreateFontCursor (screen->dpy (), XC_fleur); - - GeisAdapter& adapter = GeisAdapter::Instance(); - - adapter.tap.connect(sigc::mem_fun(this, &GestureEngine::OnTap)); - - adapter.drag_start.connect(sigc::mem_fun(this, &GestureEngine::OnDragStart)); - adapter.drag_update.connect(sigc::mem_fun(this, &GestureEngine::OnDragUpdate)); - adapter.drag_finish.connect(sigc::mem_fun(this, &GestureEngine::OnDragFinish)); - - adapter.rotate_start.connect(sigc::mem_fun(this, &GestureEngine::OnRotateStart)); - adapter.rotate_update.connect(sigc::mem_fun(this, &GestureEngine::OnRotateUpdate)); - adapter.rotate_finish.connect(sigc::mem_fun(this, &GestureEngine::OnRotateFinish)); - - adapter.pinch_start.connect(sigc::mem_fun(this, &GestureEngine::OnPinchStart)); - adapter.pinch_update.connect(sigc::mem_fun(this, &GestureEngine::OnPinchUpdate)); - adapter.pinch_finish.connect(sigc::mem_fun(this, &GestureEngine::OnPinchFinish)); - - adapter.touch_start.connect(sigc::mem_fun(this, &GestureEngine::OnTouchStart)); - adapter.touch_update.connect(sigc::mem_fun(this, &GestureEngine::OnTouchUpdate)); - adapter.touch_finish.connect(sigc::mem_fun(this, &GestureEngine::OnTouchFinish)); -} - -GestureEngine::~GestureEngine() -{ - if (_fleur_cursor) - XFreeCursor (screen->dpy (), _fleur_cursor); -} - -void -GestureEngine::OnTap(GeisAdapter::GeisTapData* data) -{ - if (data->touches == 4) - { - UBusServer* ubus = ubus_server_get_default(); - ubus_server_send_message(ubus, UBUS_DASH_EXTERNAL_ACTIVATION, NULL); - } -} - -CompWindow* GestureEngine::FindCompWindowAtPos(float fpos_x, float fpos_y) -{ - const CompWindowVector& client_list_stacking = _screen->clientList(true); - - int pos_x = fpos_x; - int pos_y = fpos_y; - - for (auto iter = client_list_stacking.rbegin(), - end = client_list_stacking.rend(); - iter != end; ++iter) - { - CompWindow* window = *iter; - - if (pos_x >= window->x() && pos_x <= (window->width() + window->x()) - && - pos_y >= window->y() && pos_y <= (window->height() + window->y())) - return window; - } - - return nullptr; -} - -void -GestureEngine::OnDragStart(GeisAdapter::GeisDragData* data) -{ - if (data->touches == 3) - { - _drag_window = FindCompWindowAtPos(data->focus_x, data->focus_y); - - - if (!_drag_window) - return; - - if (!(_drag_window->actions() & CompWindowActionMoveMask)) - { - _drag_window = 0; - return; - } - - /* Don't allow windows to be dragged if completely maximized */ - if ((_drag_window->state() & MAXIMIZE_STATE) == MAXIMIZE_STATE) - { - _drag_window = 0; - return; - } - - if (_drag_grab) - _screen->removeGrab(_drag_grab, NULL); - _drag_id = data->id; - _drag_grab = _screen->pushGrab(_fleur_cursor, "unity"); - _drag_window->grabNotify (_drag_window->serverGeometry ().x (), - _drag_window->serverGeometry ().y (), - 0, CompWindowGrabMoveMask | CompWindowGrabButtonMask); - } -} - -/* FIXME: CompScreen::warpPointer filters out motion events which - * other plugins may need to process, but for most cases in core - * they should be filtered out. */ -void -GestureEngine::OnDragUpdate(GeisAdapter::GeisDragData* data) -{ - if (_drag_id == data->id && _drag_window) - { - unsigned int px = std::max (std::min (pointerX + static_cast <int> (data->delta_x), screen->width ()), 0); - unsigned int py = std::max (std::min (pointerY + static_cast <int> (data->delta_y), screen->height ()), 0); - - if (_drag_window->state () & CompWindowStateMaximizedVertMask) - py = pointerY; - if (_drag_window->state () & CompWindowStateMaximizedHorzMask) - px = pointerX; - - XWarpPointer(screen->dpy (), - None, screen->root (), - 0, 0, 0, 0, - px, py); - - XSync(screen->dpy (), false); - _drag_window->move(px - pointerX, py - pointerY, false); - - pointerX = px; - pointerY = py; - } -} - -void -GestureEngine::OnDragFinish(GeisAdapter::GeisDragData* data) -{ - if (_drag_id == data->id && _drag_window) - { - _drag_window->ungrabNotify (); - _drag_window->syncPosition(); - EndDrag(); - } -} - -void -GestureEngine::EndDrag() -{ - if (_drag_window) - { - _screen->removeGrab(_drag_grab, NULL); - _drag_grab = 0; - _drag_window = 0; - _drag_id = 0; - } -} - -void -GestureEngine::OnRotateStart(GeisAdapter::GeisRotateData* data) -{ - -} -void -GestureEngine::OnRotateUpdate(GeisAdapter::GeisRotateData* data) -{ - -} -void -GestureEngine::OnRotateFinish(GeisAdapter::GeisRotateData* data) -{ - -} - -void -GestureEngine::OnTouchStart(GeisAdapter::GeisTouchData* data) -{ - if (data->touches == 3 && data->window != 0) - { - CompWindow* result = FindCompWindowAtPos(data->focus_x, data->focus_y); - - if (result) - { - PluginAdapter::Default()->ShowGrabHandles(result, false); - _touch_id = data->id; - _touch_window = result; - } - } -} - -void -GestureEngine::OnTouchUpdate(GeisAdapter::GeisTouchData* data) -{ - -} - -void -GestureEngine::OnTouchFinish(GeisAdapter::GeisTouchData* data) -{ - if (_touch_id == data->id) - { - if (_touch_window) - PluginAdapter::Default()->ShowGrabHandles(_touch_window, true); - _touch_id = 0; - _touch_window = 0; - } -} - -void -GestureEngine::OnPinchStart(GeisAdapter::GeisPinchData* data) -{ - if (data->touches == 3) - { - _pinch_window = FindCompWindowAtPos(data->focus_x, data->focus_y); - - if (!_pinch_window) - return; - - _pinch_id = data->id; - - if (_pinch_grab) - _screen->removeGrab(_pinch_grab, NULL); - _pinch_grab = _screen->pushGrab(_screen->invisibleCursor(), "unity"); - } -} -void -GestureEngine::OnPinchUpdate(GeisAdapter::GeisPinchData* data) -{ - if (data->id != _pinch_id) - return; - - if (data->radius > 1.25) - { - _pinch_window->maximize(MAXIMIZE_STATE); - EndDrag(); - } - else if (data->radius < 0.8) - { - _pinch_window->maximize(0); - EndDrag(); - } -} -void -GestureEngine::OnPinchFinish(GeisAdapter::GeisPinchData* data) -{ - if (_pinch_id == data->id && _pinch_window) - { - _screen->removeGrab(_pinch_grab, NULL); - _pinch_grab = 0; - _pinch_id = 0; - } -} diff --git a/plugins/unityshell/src/GestureEngine.h b/plugins/unityshell/src/GestureEngine.h deleted file mode 100644 index bce81628d..000000000 --- a/plugins/unityshell/src/GestureEngine.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * GestureEngine.h - * This file is part of Unity - * - * Copyright (C) 2011 - Canonical Ltd. - * - * Unity is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Unity is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Unity; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include <core/core.h> - -#include <sigc++/sigc++.h> -#include "GeisAdapter.h" - -class GestureEngine : public sigc::trackable -{ -public: - GestureEngine(CompScreen* screen); - virtual ~GestureEngine(); - - void OnTap(GeisAdapter::GeisTapData* data); - - void OnDragStart(GeisAdapter::GeisDragData* data); - void OnDragUpdate(GeisAdapter::GeisDragData* data); - void OnDragFinish(GeisAdapter::GeisDragData* data); - - void OnRotateStart(GeisAdapter::GeisRotateData* data); - void OnRotateUpdate(GeisAdapter::GeisRotateData* data); - void OnRotateFinish(GeisAdapter::GeisRotateData* data); - - void OnPinchStart(GeisAdapter::GeisPinchData* data); - void OnPinchUpdate(GeisAdapter::GeisPinchData* data); - void OnPinchFinish(GeisAdapter::GeisPinchData* data); - - void OnTouchStart(GeisAdapter::GeisTouchData* data); - void OnTouchUpdate(GeisAdapter::GeisTouchData* data); - void OnTouchFinish(GeisAdapter::GeisTouchData* data); - - void EndDrag(); -private: - CompWindow* FindCompWindowAtPos(float pos_x, float pos_y); - - CompScreen* _screen; - CompWindow* _drag_window; - CompWindow* _pinch_window; - CompWindow* _touch_window; - CompScreen::GrabHandle _drag_grab; - CompScreen::GrabHandle _pinch_grab; - - int _drag_id; - int _pinch_id; - int _touch_id; - - Cursor _fleur_cursor; -}; diff --git a/plugins/unityshell/src/ScreenEffectFramebufferObject.cpp b/plugins/unityshell/src/ScreenEffectFramebufferObject.cpp index 99d9ff485..de9be43f3 100644 --- a/plugins/unityshell/src/ScreenEffectFramebufferObject.cpp +++ b/plugins/unityshell/src/ScreenEffectFramebufferObject.cpp @@ -17,7 +17,7 @@ * Authored By: Sam Spilsbury <sam.spilsbury@canonical.com> */ -#ifndef USE_MODERN_COMPIZ_GL +#ifndef USE_GLES #include "ScreenEffectFramebufferObject.h" #include "BackgroundEffectHelper.h" #include <NuxCore/Logger.h> @@ -239,5 +239,5 @@ unity::ScreenEffectFramebufferObject::~ScreenEffectFramebufferObject () glDeleteTextures (1, &mFBTexture); } -#endif // USE_MODERN_COMPIZ_GL +#endif // USE_GLES diff --git a/plugins/unityshell/src/UnityGestureBroker.cpp b/plugins/unityshell/src/UnityGestureBroker.cpp new file mode 100644 index 000000000..89e22ff66 --- /dev/null +++ b/plugins/unityshell/src/UnityGestureBroker.cpp @@ -0,0 +1,133 @@ +/* + * UnityGestureBroker.cpp + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Unity; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "UnityGestureBroker.h" +#include "UnityGestureTarget.h" +#include "WindowGestureTarget.h" + +#include <X11/cursorfont.h> + +UnityGestureBroker::UnityGestureBroker() + : nux::GestureBroker() +{ + g_assert(WindowGestureTarget::fleur_cursor == 0); + WindowGestureTarget::fleur_cursor = XCreateFontCursor (screen->dpy (), XC_fleur); + + unity_target.reset(new UnityGestureTarget); + gestural_window_switcher_.reset(new unity::GesturalWindowSwitcher); +} + +UnityGestureBroker::~UnityGestureBroker() +{ + if (WindowGestureTarget::fleur_cursor) + { + XFreeCursor (screen->dpy (), WindowGestureTarget::fleur_cursor); + WindowGestureTarget::fleur_cursor = 0; + } +} + +std::vector<nux::ShPtGestureTarget> +UnityGestureBroker::FindGestureTargets(const nux::GestureEvent &event) +{ + std::vector<nux::ShPtGestureTarget> targets; + + const std::vector<nux::TouchPoint> &touches = event.GetTouches(); + + if (touches.size() == 4) + { + targets.push_back(unity_target); + } + else if (touches.size() == 3) + { + targets.push_back(gestural_window_switcher_); + + CompWindow *window = FindWindowHitByGesture(event); + if (window) + { + targets.push_back(nux::ShPtGestureTarget(new WindowGestureTarget(window))); + } + } + + return targets; +} + +CompWindow *UnityGestureBroker::FindWindowHitByGesture(const nux::GestureEvent &event) +{ + if (event.IsDirectTouch()) + { + /* If a direct device is being used (e.g., a touchscreen), all touch + points must hit the same window */ + CompWindow *last_window = nullptr; + const std::vector<nux::TouchPoint> &touches = event.GetTouches(); + for (auto touch : touches) + { + CompWindow *window = FindCompWindowAtPos(touch.x, touch.y); + if (last_window) + { + if (window != last_window) + { + return nullptr; + } + } + else + { + last_window = window; + } + } + + return last_window; + } + else + { + /* If a indirect device is being used (e.g., a trackpad), the individual + touch points are not in screen coordinates and therefore it doesn't make + sense to hit-test them individually against the window tree. Instead, + we use just the focus point, which is the same as the cursor + position in this case (which is in screen coordinates). */ + return FindCompWindowAtPos(event.GetFocus().x, event.GetFocus().y); + } +} + +CompWindow* UnityGestureBroker::FindCompWindowAtPos(int pos_x, int pos_y) +{ + const CompWindowVector& client_list_stacking = screen->clientList(true); + + for (auto iter = client_list_stacking.rbegin(), + end = client_list_stacking.rend(); + iter != end; ++iter) + { + CompWindow* window = *iter; + + if (window->minimized()) + continue; + + if (window->state() & CompWindowStateHiddenMask) + continue; + + if (pos_x >= window->x() && pos_x <= (window->width() + window->x()) + && + pos_y >= window->y() && pos_y <= (window->height() + window->y())) + return window; + } + + return nullptr; +} diff --git a/plugins/unityshell/src/UnityGestureBroker.h b/plugins/unityshell/src/UnityGestureBroker.h new file mode 100644 index 000000000..75b4f13c1 --- /dev/null +++ b/plugins/unityshell/src/UnityGestureBroker.h @@ -0,0 +1,52 @@ +/* + * UnityGestureBroker.h + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Unity; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef UNITY_GESTURE_BROKER +#define UNITY_GESTURE_BROKER + +#include <core/core.h> + +#include <Nux/GestureBroker.h> +#include "GesturalWindowSwitcher.h" + +class UnityGestureBroker : public nux::GestureBroker +{ +public: + UnityGestureBroker(); + virtual ~UnityGestureBroker(); + +private: + std::vector<nux::ShPtGestureTarget> + virtual FindGestureTargets(const nux::GestureEvent &event); + + CompWindow *FindWindowHitByGesture(const nux::GestureEvent &event); + + /*! + Returns the top-most CompWindow at the given position, if any. + */ + CompWindow* FindCompWindowAtPos(int pos_x, int pos_y); + + nux::ShPtGestureTarget unity_target; + unity::ShPtGesturalWindowSwitcher gestural_window_switcher_; +}; + +#endif // UNITY_GESTURE_BROKER diff --git a/plugins/unityshell/src/UnityGestureTarget.cpp b/plugins/unityshell/src/UnityGestureTarget.cpp new file mode 100644 index 000000000..3c4ff2ab6 --- /dev/null +++ b/plugins/unityshell/src/UnityGestureTarget.cpp @@ -0,0 +1,55 @@ +/* + * UnityGestureTarget.cpp + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Unity; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "UnityGestureTarget.h" + +#include <Nux/Nux.h> // otherwise unityshell.h inclusion will cause failures +#include "unityshell.h" +#include "Launcher.h" + +#include "UBusMessages.h" +#include "ubus-server.h" + +using namespace nux; + +UnityGestureTarget::UnityGestureTarget() +{ + launcher = &unity::UnityScreen::get(screen)->launcher_controller()->launcher(); +} + +GestureDeliveryRequest UnityGestureTarget::GestureEvent(const nux::GestureEvent &event) +{ + if (event.GetGestureClasses() & DRAG_GESTURE) + { + if (launcher.IsValid()) + launcher->GestureEvent(event); + } + else if (event.GetGestureClasses() == TAP_GESTURE + && event.type == EVENT_GESTURE_END) + { + ubus_server_send_message(ubus_server_get_default(), + UBUS_DASH_EXTERNAL_ACTIVATION, + NULL); + } + + return GestureDeliveryRequest::NONE; +} diff --git a/plugins/unityshell/src/UnityGestureTarget.h b/plugins/unityshell/src/UnityGestureTarget.h new file mode 100644 index 000000000..f47996e63 --- /dev/null +++ b/plugins/unityshell/src/UnityGestureTarget.h @@ -0,0 +1,44 @@ +/* + * UnityGestureTarget.h + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Unity; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef UNITY_GESTURE_TARGET_H +#define UNITY_GESTURE_TARGET_H + +#include <Nux/Gesture.h> + +/* + Target for Unity-level gestures. + I.e., for gestures that act on Unity elements, such as + the dash or launcher. + */ +class UnityGestureTarget : public nux::GestureTarget +{ + public: + UnityGestureTarget(); + + virtual nux::GestureDeliveryRequest GestureEvent(const nux::GestureEvent &event); + + private: + nux::ObjectWeakPtr<nux::InputArea> launcher; +}; + +#endif // UNITY_GESTURE_TARGET_H diff --git a/plugins/unityshell/src/WindowGestureTarget.cpp b/plugins/unityshell/src/WindowGestureTarget.cpp new file mode 100644 index 000000000..8bcaa7b40 --- /dev/null +++ b/plugins/unityshell/src/WindowGestureTarget.cpp @@ -0,0 +1,215 @@ +/* + * WindowGestureTarget.cpp + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Unity; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include "WindowGestureTarget.h" + +#include <Nux/Nux.h> // otherwise unityshell.h inclusion will cause failures +#include "unityshell.h" + +#include "PluginAdapter.h" + +using namespace nux; + +Cursor WindowGestureTarget::fleur_cursor = 0; + +WindowGestureTarget::WindowGestureTarget(CompWindow *window) + : window_(window), drag_grab_(0), started_window_move_(false), + window_restored_by_pinch_(false) +{ + // A workaround for the lack of weak pointers. + unity::UnityWindow *unity_window = unity::UnityWindow::get(window); + + connection_window_destruction = + unity_window->being_destroyed.connect( + sigc::mem_fun(this, &WindowGestureTarget::NullifyWindowPointer)); +} + +WindowGestureTarget::~WindowGestureTarget() +{ + connection_window_destruction.disconnect(); + if (drag_grab_) + { + if (window_) + window_->ungrabNotify(); + screen->removeGrab(drag_grab_, NULL); + } +} + +void WindowGestureTarget::NullifyWindowPointer() +{ + window_ = nullptr; +} + +GestureDeliveryRequest WindowGestureTarget::GestureEvent(const nux::GestureEvent &event) +{ + if (!window_) + return GestureDeliveryRequest::NONE; + + switch (event.type) + { + case nux::EVENT_GESTURE_BEGIN: + PluginAdapter::Default()->ShowGrabHandles(window_, false); + break; + case EVENT_GESTURE_UPDATE: + if (event.GetGestureClasses() & PINCH_GESTURE) + MaximizeOrRestoreWindowDueToPinch(event); + if (event.GetGestureClasses() & DRAG_GESTURE) + { + if (WindowCanMove()) + { + if (!started_window_move_) + { + StartWindowMove(event); + started_window_move_ = true; + } + MoveWindow(event); + } + } + break; + default: // EVENT_GESTURE_END | EVENT_GESTURE_LOST + if (event.GetGestureClasses() & DRAG_GESTURE) + { + EndWindowMove(event); + started_window_move_ = false; + } + PluginAdapter::Default()->ShowGrabHandles(window_, true); + break; + }; + + return GestureDeliveryRequest::NONE; +} + +bool WindowGestureTarget::WindowCanMove() +{ + if (!(window_->actions() & CompWindowActionMoveMask)) + return false; + + /* Don't allow windows to be dragged if completely maximized */ + if ((window_->state() & MAXIMIZE_STATE) == MAXIMIZE_STATE) + return false; + + /* Don't start moving a window that has just been restored. The user is likely + still performing the pinch and not expecting the window to start moving */ + if (window_restored_by_pinch_) + return false; + + return true; +} + +void WindowGestureTarget::MaximizeOrRestoreWindowDueToPinch(const nux::GestureEvent &event) +{ + if (event.GetRadius() > 1.25f) + { + window_->maximize(MAXIMIZE_STATE); + RemoveDragGrab(); + window_restored_by_pinch_ = false; + } + else if (event.GetRadius() < 0.8f) + { + if (window_->state() & MAXIMIZE_STATE) + { + window_->maximize(0); + RemoveDragGrab(); + window_restored_by_pinch_ = true; + } + } +} + +void WindowGestureTarget::StartWindowMove(const nux::GestureEvent &event) +{ + if (!event.IsDirectTouch()) + { + drag_grab_ = screen->pushGrab(fleur_cursor, "unity"); + window_->grabNotify(window_->serverGeometry().x(), + window_->serverGeometry().y(), + 0, + CompWindowGrabMoveMask | CompWindowGrabButtonMask); + } +} + +void WindowGestureTarget::MoveWindow(const nux::GestureEvent &event) +{ + const nux::Point2D<float> &delta = event.GetDelta(); + + unsigned int px = std::max(std::min(pointerX + static_cast<int>(delta.x), + screen->width()), + 0); + + unsigned int py = std::max(std::min(pointerY + static_cast<int>(delta.y), + screen->height()), + 0); + + if (window_->state() & CompWindowStateMaximizedVertMask) + py = pointerY; + if (window_->state() & CompWindowStateMaximizedHorzMask) + px = pointerX; + + if (!event.IsDirectTouch()) + { + /* FIXME: CompScreen::warpPointer filters out motion events which + other plugins may need to process, but for most cases in core + they should be filtered out. */ + XWarpPointer(screen->dpy (), + None, screen->root (), + 0, 0, 0, 0, + px, py); + } + + XSync(screen->dpy (), false); + window_->move(px - pointerX, py - pointerY, false); + + pointerX = px; + pointerY = py; +} + +void WindowGestureTarget::EndWindowMove(const nux::GestureEvent &event) +{ + window_->ungrabNotify(); + RemoveDragGrab(); + window_->syncPosition(); +} + +void WindowGestureTarget::RemoveDragGrab() +{ + if (drag_grab_) + { + screen->removeGrab(drag_grab_, NULL); + drag_grab_ = 0; + } +} + +bool WindowGestureTarget::Equals(const nux::GestureTarget& other) const +{ + const WindowGestureTarget *window_target = dynamic_cast<const WindowGestureTarget *>(&other); + + if (window_target) + { + if (window_ && window_target->window_) + return window_->id() == window_target->window_->id(); + else + return window_ == window_target->window_; + } + else + { + return false; + } +} diff --git a/plugins/unityshell/src/WindowGestureTarget.h b/plugins/unityshell/src/WindowGestureTarget.h new file mode 100644 index 000000000..e805e3948 --- /dev/null +++ b/plugins/unityshell/src/WindowGestureTarget.h @@ -0,0 +1,57 @@ +/* + * WindowGestureTarget.h + * This file is part of Unity + * + * Copyright (C) 2012 - Canonical Ltd. + * + * Unity is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Unity is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Unity; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef WINDOW_GESTURE_TARGET_H +#define WINDOW_GESTURE_TARGET_H + +#include <Nux/Gesture.h> + +#include <core/core.h> // compiz stuff + +class WindowGestureTarget : public nux::GestureTarget +{ + public: + WindowGestureTarget(CompWindow *window); + virtual ~WindowGestureTarget(); + + virtual nux::GestureDeliveryRequest GestureEvent(const nux::GestureEvent &event); + + static Cursor fleur_cursor; + + CompWindow *window() {return window_;} + private: + virtual bool Equals(const nux::GestureTarget& other) const; + void StartWindowMove(const nux::GestureEvent &event); + void MoveWindow(const nux::GestureEvent &event); + void EndWindowMove(const nux::GestureEvent &event); + void MaximizeOrRestoreWindowDueToPinch(const nux::GestureEvent &event); + bool WindowCanMove(); + void NullifyWindowPointer(); + void RemoveDragGrab(); + CompWindow *window_; + CompScreen::GrabHandle drag_grab_; + bool started_window_move_; + bool window_restored_by_pinch_; + sigc::connection connection_window_destruction; +}; + +#endif // WINDOW_GESTURE_TARGET_H diff --git a/plugins/unityshell/src/WindowMinimizeSpeedController.cpp b/plugins/unityshell/src/WindowMinimizeSpeedController.cpp new file mode 100644 index 000000000..66f28d8fc --- /dev/null +++ b/plugins/unityshell/src/WindowMinimizeSpeedController.cpp @@ -0,0 +1,108 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* Compiz unity plugin + * unity.h + * + * Copyright (c) 2010-11 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Your own copyright notice would go above. You are free to choose whatever + * licence you want, just take note that some compiz code is GPL and you will + * not be able to re-use it if you want to use a different licence. + */ + +#include <gio/gio.h> +#include <NuxCore/Logger.h> + +#include "WindowMinimizeSpeedController.h" + +namespace +{ + +nux::logging::Logger logger ("unity.WindowMinimizeSpeedController"); + +namespace local +{ +const std::string UNITY_SCHEMA = "com.canonical.Unity"; +} +} + +WindowMinimizeSpeedController::WindowMinimizeSpeedController() + : _settings(g_settings_new(local::UNITY_SCHEMA.c_str())) + , _minimize_count(g_settings_get_int(_settings, "minimize-count")) + , _minimize_speed_threshold(g_settings_get_int(_settings, "minimize-speed-threshold")) + , _minimize_slow_duration(g_settings_get_int(_settings, "minimize-slow-duration")) + , _minimize_fast_duration(g_settings_get_int(_settings, "minimize-fast-duration")) +{ + _minimize_count_changed.Connect(_settings, "changed::minimize-count", + [&] (GSettings*, gchar* name) { + _minimize_count = g_settings_get_int(_settings, name); + SetDuration(); + }); + _minimize_speed_threshold_changed.Connect(_settings, "changed::minimize-speed-threshold", + [&] (GSettings*, gchar* name) { + _minimize_speed_threshold = g_settings_get_int(_settings, name); + SetDuration(); + }); + _minimize_fast_duration_changed.Connect(_settings, "changed::minimize-fast-duration", + [&] (GSettings*, gchar* name) { + _minimize_fast_duration = g_settings_get_int(_settings, name); + SetDuration(); + }); + _minimize_slow_duration_changed.Connect(_settings, "changed::minimize-slow-duration", + [&] (GSettings*, gchar* name) { + _minimize_slow_duration = g_settings_get_int(_settings, name); + SetDuration(); + }); +} + +void WindowMinimizeSpeedController::UpdateCount() +{ + if (_minimize_count < _minimize_speed_threshold) { + _minimize_count += 1; + g_settings_set_int(_settings, "minimize-count", _minimize_count); + } +} + +int WindowMinimizeSpeedController::getDuration() +{ + return mDuration; +} + +void WindowMinimizeSpeedController::SetDuration() +{ + /* Perform some sanity checks on the configuration values */ + if (_minimize_fast_duration > _minimize_slow_duration) + { + LOG_WARN(logger) << "Configuration mismatch: minimize-fast-duration (" + << _minimize_fast_duration + << ") is longer than minimize-slow-duration (" + << _minimize_slow_duration << "). Not changing speed."; + return; + } + + if (_minimize_count < 0) + _minimize_count = 0; + if (_minimize_count > _minimize_speed_threshold) + _minimize_count = _minimize_speed_threshold; + + /* Adjust the speed so that it gets linearly closer to maximum speed as we + approach the threshold */ + int speed_range = _minimize_slow_duration - _minimize_fast_duration; + float position = (_minimize_speed_threshold <= 0) ? 1.0 : + static_cast<float>(_minimize_count) / _minimize_speed_threshold; + int duration = _minimize_slow_duration - std::ceil(position * speed_range); + + if (duration != mDuration) { + mDuration = duration; + DurationChanged.emit(); + } +} diff --git a/plugins/unityshell/src/WindowMinimizeSpeedController.h b/plugins/unityshell/src/WindowMinimizeSpeedController.h new file mode 100644 index 000000000..49bcbad14 --- /dev/null +++ b/plugins/unityshell/src/WindowMinimizeSpeedController.h @@ -0,0 +1,57 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* Compiz unity plugin + * unity.h + * + * Copyright (c) 2010-11 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Your own copyright notice would go above. You are free to choose whatever + * licence you want, just take note that some compiz code is GPL and you will + * not be able to re-use it if you want to use a different licence. + */ + +#ifndef WINDOWMINIMIZESPEEDCONTROLLER_H +#define WINDOWMINIMIZESPEEDCONTROLLER_H + +#include <core/core.h> +#include <UnityCore/GLibWrapper.h> +#include <UnityCore/GLibSignal.h> +#include <sigc++/sigc++.h> + +typedef struct _GSettings GSettings; + +using namespace unity; + +class WindowMinimizeSpeedController +{ +public: + WindowMinimizeSpeedController(); + void UpdateCount(); + int getDuration(); + sigc::signal<void> DurationChanged; + +private: + void SetDuration(); + + glib::Object<GSettings> _settings; + int _minimize_count; + int _minimize_speed_threshold; + int _minimize_slow_duration; + int _minimize_fast_duration; + glib::Signal<void, GSettings*, gchar* > _minimize_count_changed; + glib::Signal<void, GSettings*, gchar* > _minimize_speed_threshold_changed; + glib::Signal<void, GSettings*, gchar* > _minimize_slow_duration_changed; + glib::Signal<void, GSettings*, gchar* > _minimize_fast_duration_changed; + int mDuration; +}; + +#endif // WINDOWMINIMIZESPEEDCONTROLLER_H diff --git a/plugins/unityshell/src/nux-area-accessible.cpp b/plugins/unityshell/src/nux-area-accessible.cpp index ca4d02696..64a6c0424 100644 --- a/plugins/unityshell/src/nux-area-accessible.cpp +++ b/plugins/unityshell/src/nux-area-accessible.cpp @@ -26,26 +26,26 @@ * nux::Area, exposing the common elements on each basic individual * element (position, extents, etc) * - * In this object is also implemented the main support for the focused - * object. This is complex due several reasons: + * In this object the main support for the focused object is also + * implemented. This is complex due to several reasons: * - * * We need to ensure the proper order when the objects gets the focus + * * We need to ensure the proper order when the objects get the focus * - * * It doesn't make too sense to give the focus to an object that it - * is inside a inactive window, so it is also convenient to emit + * * It doesn't make sense to give the focus to an object that is + * inside an inactive window too, so it is also convenient to emit * the window:active event before the focus change. * - * => this is the reason there is implemented a system to delay the - * focus notification until the top level window became active + * => this is the reason why there is a system to delay the focus + * notification, until the top level window becomes active, implemented * * * But the main complexity comes from the fact that not all the - * objects on unity are implementing key nav in the same way. + * objects of Unity are implementing key nav the same way. * - * * Launcher uses exclusively InputArea methods like - * SetKeyboardFocus, OnStartKeyboardReceiver, etc. This is the - * key focus at a low level abstraction + * * The Launcher uses InputArea methods like + * SetKeyboardFocus, OnStartKeyboardReceiver, etc exclusively. + * This is the key focus at a low level abstraction * - * * Dash objects uses the events from Focusable. But in the same + * * Dash objects use the events from Focusable. But in the same * way, they require the low level key focus (OnStartFocus) and * so on * @@ -179,10 +179,10 @@ nux_area_accessible_initialize(AtkObject* accessible, atk_component_add_focus_handler(ATK_COMPONENT(accessible), nux_area_accessible_focus_handler); - /* NOTE: we can't search for the parent window on initilization as a - general rule, or we could enter on a infinite loop. At area this + /* NOTE: we can't search for the parent window on initialization as a + general rule, or we could enter an infinite loop. At area this is done on the focus event. On the Switcher this is done on their - initialize itself */ + initialization itself */ } static AtkObject* @@ -210,7 +210,7 @@ nux_area_accessible_get_parent(AtkObject* obj) } /* - * Checks if the parent actor, and his parent, etc is all visible + * Checks if the parent actor, and his parent, etc are all visible * Used to check the showing state */ static gboolean @@ -349,7 +349,7 @@ nux_area_accessible_grab_focus(AtkComponent* component) //area = dynamic_cast<nux::Area*>(nux_object); - /* FIXME: SetFocused doesn't return if the force was succesful or + /* FIXME: SetFocused doesn't return if the force was successful or not, we suppose that this is the case like in cally and gail */ return TRUE; @@ -494,7 +494,7 @@ on_parent_window_activate_cb(AtkObject* parent_window, * This method checks if there is any pending notification, and emits * it if it is possible * - * Returns: TRUE if a atk notification was emitted, FALSE otherwise + * Returns: TRUE if an atk notification was emitted, FALSE otherwise */ gboolean nux_area_accessible_check_pending_notification(NuxAreaAccessible* self) @@ -582,7 +582,7 @@ nux_area_accessible_get_parent_window(NuxAreaAccessible* self) { g_return_val_if_fail(NUX_IS_AREA_ACCESSIBLE(self), NULL); - /* Ensures that at least whe made a search for it */ + /* At least ensure that we made a search for it */ check_parent_window_connected(self); return self->priv->parent_window; diff --git a/plugins/unityshell/src/nux-area-accessible.h b/plugins/unityshell/src/nux-area-accessible.h index 207247a3f..a5326c63f 100644 --- a/plugins/unityshell/src/nux-area-accessible.h +++ b/plugins/unityshell/src/nux-area-accessible.h @@ -49,9 +49,9 @@ struct _NuxAreaAccessibleClass NuxObjectAccessibleClass parent_class; /* - * Usually objects shouldn emit events like focus or selection + * Usually objects shouldn't emit events like focus or selection * changes until the toplevel window is active. This method is - * called when the toplevel window became active. Redefine it if you + * called when the toplevel window becomes active. Redefine it if you * need to check any pending state change notification. */ gboolean(*check_pending_notification)(NuxAreaAccessible* self); diff --git a/plugins/unityshell/src/nux-base-window-accessible.cpp b/plugins/unityshell/src/nux-base-window-accessible.cpp index 4ec4a7836..baa991b8b 100644 --- a/plugins/unityshell/src/nux-base-window-accessible.cpp +++ b/plugins/unityshell/src/nux-base-window-accessible.cpp @@ -26,11 +26,11 @@ * * Expose the child of BaseWindow (the layout) * * Window event notification (activate, deactivate, and so on) * - * BTW: we consider that one window is active if it has directly the - * keyboard focus, or if one of his child has the keyboard focus (ie: + * BTW: we consider that one window is active, if it directly has + * keyboard focus, or if one of its children has keyboard focus (ie: * the Launcher via GrabKeyboardFocus) * - * HasKeyboardFocus is not a reliable to check that: + * HasKeyboardFocus is not reliable to check that: * see bug https://bugs.launchpad.net/nux/+bug/745049 * * So we need to update the state of the objects using the information @@ -147,7 +147,7 @@ nux_base_window_accessible_ref_state_set(AtkObject* obj) atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); - /* HasKeyboardFocus is not a reliable here: + /* HasKeyboardFocus is not reliable here: see bug https://bugs.launchpad.net/nux/+bug/745049 */ if (self->priv->active) { @@ -162,7 +162,7 @@ nux_base_window_accessible_ref_state_set(AtkObject* obj) static void atk_window_interface_init(AtkWindowIface* iface) { - /* AtkWindow just define signals at this moment */ + /* AtkWindow just defines signals at this moment */ } /* public */ diff --git a/plugins/unityshell/src/nux-layout-accessible.cpp b/plugins/unityshell/src/nux-layout-accessible.cpp index 8bec1d9e2..b706df620 100644 --- a/plugins/unityshell/src/nux-layout-accessible.cpp +++ b/plugins/unityshell/src/nux-layout-accessible.cpp @@ -24,7 +24,7 @@ * * #NuxLayoutAccessible implements the required ATK interfaces of * nux::Layout, implementing the container related methods on - * AtkObject, in order to expose his objects + * AtkObject, in order to expose its objects * */ @@ -203,7 +203,7 @@ search_for_child(AtkObject* accessible, element_list = layout->GetChildren(); - for (it = element_list.begin(); it != element_list.end(); it++, result++) + for (it = element_list.begin(); it != element_list.end(); ++it, result++) { current_area = *it; if (current_area == area) diff --git a/plugins/unityshell/src/nux-object-accessible.cpp b/plugins/unityshell/src/nux-object-accessible.cpp index ccdc4b1de..4e25c2963 100644 --- a/plugins/unityshell/src/nux-object-accessible.cpp +++ b/plugins/unityshell/src/nux-object-accessible.cpp @@ -23,7 +23,7 @@ * @see_also: nux::Object * * #NuxObjectAccessible implements the required ATK interfaces of - * nux::Object, exposing the common elements on each basic individual + * nux::Object, exposing the common elements of each basic individual * element (position, extents, etc) * */ @@ -129,11 +129,11 @@ nux_object_accessible_initialize(AtkObject* accessible, /** * nux_object_accessible_get_object: * - * Returns the nux::Object this object is providing accessibility support. + * Returns the nux::Object this object is providing accessibility support for. * * Note that there isn't a _set method. This is because setting that - * should only be done during initilization, and it doesn't make sense - * to change that during the life of the object. + * should only be done during initialization, and it doesn't make sense + * to change that during the lifetime of the object. * */ nux::Object* diff --git a/plugins/unityshell/src/nux-view-accessible.cpp b/plugins/unityshell/src/nux-view-accessible.cpp index d928ed315..7dd14eb49 100644 --- a/plugins/unityshell/src/nux-view-accessible.cpp +++ b/plugins/unityshell/src/nux-view-accessible.cpp @@ -165,7 +165,7 @@ nux_view_accessible_ref_state_set(AtkObject* obj) if (nux_object == NULL) /* defunct */ return state_set; - /* HasKeyboardFocus is not a reliable here: + /* HasKeyboardFocus is not reliable here: see bug https://bugs.launchpad.net/nux/+bug/745049 */ if (self->priv->key_focused) atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); @@ -262,7 +262,7 @@ on_change_keyboard_receiver_cb(AtkObject* accessible, { self->priv->key_focused = focus_in; - /* we always led the focus notification to + /* we always lead the focus notification to _check_pending_notification, in order to allow the proper window_activate -> focus_change order */ self->priv->pending_notification = TRUE; @@ -275,7 +275,7 @@ nux_view_accessible_check_pending_notification(NuxAreaAccessible* area_accessibl NuxViewAccessible* self = NULL; nux::Object* nux_object = NULL; - /* We also call parent implementation, as we are not totally + /* We also call the parent implementation, as we are not totally overriding check_pending_notification, just adding extra functionality*/ NUX_AREA_ACCESSIBLE_CLASS(nux_view_accessible_parent_class)->check_pending_notification(area_accessible); diff --git a/plugins/unityshell/src/unity-launcher-accessible.cpp b/plugins/unityshell/src/unity-launcher-accessible.cpp index d20deed28..4cb4301ae 100644 --- a/plugins/unityshell/src/unity-launcher-accessible.cpp +++ b/plugins/unityshell/src/unity-launcher-accessible.cpp @@ -441,7 +441,7 @@ update_children_index(UnityLauncherAccessible* self) if (launcher_model == NULL) return; - for (it = launcher_model->begin(); it != launcher_model->end(); it++) + for (it = launcher_model->begin(); it != launcher_model->end(); ++it) { child = dynamic_cast<nux::Object*>((*it).GetPointer()); child_accessible = unity_a11y_get_accessible(child); diff --git a/plugins/unityshell/src/unity-launcher-icon-accessible.cpp b/plugins/unityshell/src/unity-launcher-icon-accessible.cpp index 44b5051a7..b0331eb00 100644 --- a/plugins/unityshell/src/unity-launcher-icon-accessible.cpp +++ b/plugins/unityshell/src/unity-launcher-icon-accessible.cpp @@ -281,7 +281,7 @@ unity_launcher_icon_accessible_ref_state_set(AtkObject* obj) icon = dynamic_cast<LauncherIcon*>(nux_object); - if (icon->GetQuirk(LauncherIcon::QUIRK_VISIBLE)) + if (icon->GetQuirk(LauncherIcon::Quirk::VISIBLE)) { atk_state_set_add_state(state_set, ATK_STATE_VISIBLE); atk_state_set_add_state(state_set, ATK_STATE_SHOWING); diff --git a/plugins/unityshell/src/unity-quicklist-menu-item-accessible.cpp b/plugins/unityshell/src/unity-quicklist-menu-item-accessible.cpp index 4d0258492..bdfd7fd81 100644 --- a/plugins/unityshell/src/unity-quicklist-menu-item-accessible.cpp +++ b/plugins/unityshell/src/unity-quicklist-menu-item-accessible.cpp @@ -210,7 +210,7 @@ unity_quicklist_menu_item_accessible_get_name(AtkObject* obj) menu_item = dynamic_cast<QuicklistMenuItem*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj))); if (menu_item != NULL) { - name = menu_item->GetLabel(); + name = menu_item->GetLabel().c_str(); } } diff --git a/plugins/unityshell/src/unity-root-accessible.cpp b/plugins/unityshell/src/unity-root-accessible.cpp index 789f83210..681d676d6 100644 --- a/plugins/unityshell/src/unity-root-accessible.cpp +++ b/plugins/unityshell/src/unity-root-accessible.cpp @@ -395,7 +395,7 @@ register_interesting_messages(UnityRootAccessible* self) sigc::bind(sigc::ptr_fun(ubus_launcher_register_interest_cb), self)); - ubus_manager.RegisterInterest(UBUS_LAUNCHER_START_KEY_SWTICHER, + ubus_manager.RegisterInterest(UBUS_LAUNCHER_START_KEY_SWITCHER, sigc::bind(sigc::ptr_fun(ubus_launcher_register_interest_cb), self)); diff --git a/plugins/unityshell/src/unity-rvgrid-accessible.cpp b/plugins/unityshell/src/unity-rvgrid-accessible.cpp index 0cc379419..4f7058843 100644 --- a/plugins/unityshell/src/unity-rvgrid-accessible.cpp +++ b/plugins/unityshell/src/unity-rvgrid-accessible.cpp @@ -146,8 +146,6 @@ check_selection(UnityRvgridAccessible* self) { AtkObject* child = NULL; gint index = 0; - ResultView::ResultList result_list; - Result* result; nux::Object* object = NULL; ResultViewGrid* rvgrid = NULL; std::string name; @@ -162,13 +160,12 @@ check_selection(UnityRvgridAccessible* self) rvgrid = dynamic_cast<ResultViewGrid*>(object); - result_list = rvgrid->GetResultList(); index = rvgrid->GetSelectedIndex(); if (index >= 0) { - result = &result_list[index]; - name = result->name; + Result result(*rvgrid->GetIteratorAtRow(index)); + name = result.name; child = ATK_OBJECT(self->priv->result); self->priv->has_selection = TRUE; diff --git a/plugins/unityshell/src/unity-switcher-accessible.cpp b/plugins/unityshell/src/unity-switcher-accessible.cpp index e4e2a968f..189e7d703 100644 --- a/plugins/unityshell/src/unity-switcher-accessible.cpp +++ b/plugins/unityshell/src/unity-switcher-accessible.cpp @@ -404,7 +404,7 @@ create_children(UnitySwitcherAccessible* self) if (switcher_model == NULL) return; - for (it = switcher_model->begin(); it != switcher_model->end(); it++) + for (it = switcher_model->begin(); it != switcher_model->end(); ++it) { child = *it; child_accessible = unity_launcher_icon_accessible_new(child.GetPointer()); diff --git a/plugins/unityshell/src/unitya11y.cpp b/plugins/unityshell/src/unitya11y.cpp index fb0016f0d..1035af609 100644 --- a/plugins/unityshell/src/unitya11y.cpp +++ b/plugins/unityshell/src/unitya11y.cpp @@ -77,7 +77,6 @@ load_unity_atk_util(nux::WindowThread* wt) g_type_class_unref(g_type_class_ref(UNITY_TYPE_UTIL_ACCESSIBLE)); } -/********************************************************************************/ /* * In order to avoid the atk-bridge loading and the GAIL * initialization during the gtk_init, it is required to set some @@ -108,17 +107,17 @@ unity_a11y_init(nux::WindowThread* wt) a11y_initialized = TRUE; -// NOTE: we run manually the unit tests while developing by -// uncommenting this. Take a look to the explanation on +// NOTE: we run the unit tests manually while developing by +// uncommenting this. Take a look at the explanation in the // unitya11ytests.h header for more information // unity_run_a11y_unit_tests (); } /* - * Finalize the related issues related with the accessibility. + * Finalize the issues related with accessibility. * - * It mainly clean the resources related with the accessibility + * It mainly cleans the resources related with accessibility */ void unity_a11y_finalize(void) @@ -143,9 +142,9 @@ unity_a11y_finalize(void) * that would be add a ->get_accessible method on the nux::View * subclasses itself. * - * WARNING: as a reason the previous comment it is true. Take into - * account that you should be careful with the order you add those - * defines. The order will be from more specific classes to more + * WARNING: as a reason the previous comment is true. Take into + * account that you should be careful with the order in which you add + * those defines. The order will be from more specific classes to more * abstracted classes. * */ @@ -211,7 +210,7 @@ on_object_destroy_cb(nux::Object* base_object, AtkObject* accessible_object) { /* NOTE: the pair key:value (base_object:accessible_object) could be - already removed on on_accessible_destroy_cb. That just mean that + already removed on on_accessible_destroy_cb. That just means that g_hash_table_remove would return FALSE. We don't add a debug/warning message to avoid being too verbose */ @@ -223,7 +222,7 @@ on_accessible_destroy_cb(gpointer data, GObject* where_the_object_was) { /* NOTE: the pair key:value (base_object:accessible_object) could be - already removed on on_object_destroy_cb. That just mean that + already removed on on_object_destroy_cb. That just means that g_hash_table_remove would return FALSE. We don't add a debug/warning message to avoid being too verbose */ @@ -234,9 +233,9 @@ on_accessible_destroy_cb(gpointer data, * Returns the accessible object of a nux::View object * * This method tries to: - * * Check if area has already a accessibility object - * * If this is the case, returns that - * * If not, creates it and return the object + * * Check if area already has a accessibility object + * * If this is the case, return that + * * If not, create it and return the object * * FIXME: this should be a temporal method. The best way to implement * that would be add a ->get_accessible method on the nux::View @@ -263,7 +262,7 @@ unity_a11y_get_accessible(nux::Object* object) g_hash_table_insert(accessible_table, object, accessible_object); /* there are two reasons the object should be removed from the - * table: base object destroyed, or accessible object + * table: base object destroyed or accessible object * destroyed */ g_object_weak_ref(G_OBJECT(accessible_object), diff --git a/plugins/unityshell/src/unitya11ytests.cpp b/plugins/unityshell/src/unitya11ytests.cpp index 20328a674..1ec2c1af0 100644 --- a/plugins/unityshell/src/unitya11ytests.cpp +++ b/plugins/unityshell/src/unitya11ytests.cpp @@ -48,7 +48,7 @@ using unity::launcher::SimpleLauncherIcon; * This unit test checks if the destroy management is working: * * - If the state of a accessibility object is properly updated after - * the object destruction + * the object's destruction * */ static gboolean @@ -224,7 +224,7 @@ a11y_unit_test_launcher_connection(void) g_debug("[a11y] Launcher accessible created correctly"); } - launcher_icon = new SimpleLauncherIcon(); + launcher_icon = new SimpleLauncherIcon(unity::launcher::AbstractLauncherIcon::IconType::NONE); launcher_icon->SinkReference(); launcher_icon_accessible = unity_a11y_get_accessible(launcher_icon); diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp index 9290633e8..640fd3654 100644 --- a/plugins/unityshell/src/unityshell.cpp +++ b/plugins/unityshell/src/unityshell.cpp @@ -29,8 +29,6 @@ #include "Launcher.h" #include "LauncherIcon.h" #include "LauncherController.h" -#include "GeisAdapter.h" -#include "DevicesSettings.h" #include "PluginAdapter.h" #include "QuicklistManager.h" #include "StartupNotifyService.h" @@ -38,14 +36,16 @@ #include "KeyboardUtil.h" #include "unityshell.h" #include "BackgroundEffectHelper.h" +#include "UnityGestureBroker.h" -#include <dbus/dbus.h> -#include <dbus/dbus-glib.h> #include <glib/gi18n-lib.h> #include <gtk/gtk.h> #include <gdk/gdk.h> #include <gdk/gdkx.h> #include <libnotify/notify.h> +#include <cairo-xlib-xrender.h> + +#include <text/text.h> #include <sstream> #include <memory> @@ -83,6 +83,10 @@ nux::logging::Logger logger("unity.shell"); UnityScreen* uScreen = 0; +static unsigned int CLOSE_ICON_SIZE = 19; +static unsigned int CLOSE_ICON_SPACE = 5; +static unsigned int SCALE_WINDOW_TITLE_SIZE = 28; + void reset_glib_logging(); void configure_logging(); void capture_g_log_calls(const gchar* log_domain, @@ -103,15 +107,43 @@ const std::string RELAYOUT_TIMEOUT = "relayout-timeout"; } // namespace local } // anon namespace +class WindowCairoContext +{ + public: + Pixmap pixmap_; + cairo_surface_t* surface_; + GLTexture::List texture_; + cairo_t *cr_; + + WindowCairoContext () + : pixmap_ (0), surface_ (0), cr_ (0) + { + } + + ~WindowCairoContext () + { + if (cr_) + cairo_destroy (cr_); + + if (surface_) + cairo_surface_destroy (surface_); + + texture_.clear (); + + if (pixmap_) + XFreePixmap (screen->dpy (), pixmap_); + } +}; + UnityScreen::UnityScreen(CompScreen* screen) : BaseSwitchScreen (screen) , PluginClassHandler <UnityScreen, CompScreen> (screen) , screen(screen) , cScreen(CompositeScreen::get(screen)) , gScreen(GLScreen::get(screen)) + , animation_controller_(tick_source_) , debugger_(this) , enable_shortcut_overlay_(true) - , gesture_engine_(screen) , needsRelayout(false) , _in_paint(false) , super_keypressed_(false) @@ -131,10 +163,14 @@ UnityScreen::UnityScreen(CompScreen* screen) , panel_texture_has_changed_(true) , paint_panel_(false) , scale_just_activated_(false) + , highlighted_window_(0) + , minimize_speed_controller(new WindowMinimizeSpeedController()) { Timer timer; +#ifndef USE_GLES gfloat version; gchar* extensions; +#endif bool failed = false; configure_logging(); LOG_DEBUG(logger) << __PRETTY_FUNCTION__; @@ -203,8 +239,6 @@ UnityScreen::UnityScreen(CompScreen* screen) { notify_init("unityshell"); - dbus_g_thread_init(); - unity_a11y_preset_environment(); XSetErrorHandler(old_handler); @@ -214,10 +248,6 @@ UnityScreen::UnityScreen(CompScreen* screen) CompositeScreenInterface::setHandler(cScreen); GLScreenInterface::setHandler(gScreen); -#ifdef USE_MODERN_COMPIZ_GL - gScreen->glPaintCompositedOutputSetEnabled (this, true); -#endif - PluginAdapter::Initialize(screen); WindowManager::SetDefault(PluginAdapter::Default()); AddChild(PluginAdapter::Default()); @@ -287,7 +317,6 @@ UnityScreen::UnityScreen(CompScreen* screen) optionSetIconSizeNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAutohideAnimationNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetDashBlurExperimentalNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); - optionSetDevicesOptionNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetShortcutOverlayNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetShowDesktopIconNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetShowLauncherInitiate(boost::bind(&UnityScreen::showLauncherKeyInitiate, this, _1, _2, _3)); @@ -300,6 +329,7 @@ UnityScreen::UnityScreen(CompScreen* screen) optionSetAutomaximizeValueNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAltTabTimeoutNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAltTabBiasViewportNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); + optionSetDisableShowDesktopNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetAltTabForwardAllInitiate(boost::bind(&UnityScreen::altTabForwardAllInitiate, this, _1, _2, _3)); optionSetAltTabForwardInitiate(boost::bind(&UnityScreen::altTabForwardInitiate, this, _1, _2, _3)); @@ -337,6 +367,7 @@ UnityScreen::UnityScreen(CompScreen* screen) optionSetOvercomePressureNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetDecayRateNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetShowMinimizedWindowsNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); + optionSetEdgePassedDisabledMsNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetNumLaunchersNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); optionSetLauncherCaptureMouseNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2)); @@ -344,13 +375,13 @@ UnityScreen::UnityScreen(CompScreen* screen) ubus_manager_.RegisterInterest(UBUS_LAUNCHER_START_KEY_NAV, sigc::mem_fun(this, &UnityScreen::OnLauncherStartKeyNav)); - ubus_manager_.RegisterInterest(UBUS_LAUNCHER_START_KEY_SWTICHER, + ubus_manager_.RegisterInterest(UBUS_LAUNCHER_START_KEY_SWITCHER, sigc::mem_fun(this, &UnityScreen::OnLauncherStartKeyNav)); ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_NAV, sigc::mem_fun(this, &UnityScreen::OnLauncherEndKeyNav)); - ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_SWTICHER, + ubus_manager_.RegisterInterest(UBUS_LAUNCHER_END_KEY_SWITCHER, sigc::mem_fun(this, &UnityScreen::OnLauncherEndKeyNav)); ubus_manager_.RegisterInterest(UBUS_SWITCHER_START, @@ -362,7 +393,7 @@ UnityScreen::UnityScreen(CompScreen* screen) auto init_plugins_cb = sigc::mem_fun(this, &UnityScreen::initPluginActions); sources_.Add(std::make_shared<glib::Idle>(init_plugins_cb, glib::Source::Priority::DEFAULT)); - geis_adapter_.Run(); + InitGesturesSupport(); CompString name(PKGDATADIR"/panel-shadow.png"); CompString pname("unityshell"); @@ -390,6 +421,10 @@ UnityScreen::UnityScreen(CompScreen* screen) } panel::Style::Instance().changed.connect(sigc::mem_fun(this, &UnityScreen::OnPanelStyleChanged)); + + minimize_speed_controller->DurationChanged.connect( + sigc::mem_fun(this, &UnityScreen::OnMinimizeDurationChanged) + ); } UnityScreen::~UnityScreen() @@ -482,7 +517,7 @@ void UnityScreen::CreateSuperNewAction(char shortcut, impl::ActionModifiers flag void UnityScreen::nuxPrologue() { -#ifndef USE_MODERN_COMPIZ_GL +#ifndef USE_GLES /* Vertex lighting isn't used in Unity, we disable that state as it could have * been leaked by another plugin. That should theoretically be switched off * right after PushAttrib since ENABLE_BIT is meant to restore the LIGHTING @@ -499,6 +534,17 @@ void UnityScreen::nuxPrologue() glMatrixMode(GL_MODELVIEW); glPushMatrix(); + +#ifndef USE_MODERN_COMPIZ_GL + /* This is needed to Fix a crash in glDrawArrays with the NVIDIA driver + * see bugs #1031554 and #982626. + * The NVIDIA driver looks to see if the legacy GL_VERTEX_ARRAY, + * GL_TEXTURE_COORDINATES_ARRAY and other such client states are enabled + * first before checking if a vertex buffer is bound and will prefer the + * client buffers over the the vertex buffer object. */ + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +#endif #endif glGetError(); @@ -506,8 +552,10 @@ void UnityScreen::nuxPrologue() void UnityScreen::nuxEpilogue() { +#ifndef USE_GLES #ifndef USE_MODERN_COMPIZ_GL (*GL::bindFramebuffer)(GL_FRAMEBUFFER_EXT, _active_fbo); +#endif glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -528,6 +576,13 @@ void UnityScreen::nuxEpilogue() glReadBuffer(GL_BACK); glPopAttrib(); + +#ifndef USE_MODERN_COMPIZ_GL + /* Re-enable the client states that have been disabled in nuxPrologue, for + * NVIDIA compatibility reasons */ + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +#endif #else #ifdef USE_GLES glDepthRangef(0, 1); @@ -1202,6 +1257,11 @@ void UnityWindow::handleEvent (XEvent *event) } } +CompRect UnityWindow::closeButtonArea () +{ + return close_button_area_; +} + bool UnityScreen::shellCouldBeHidden(CompOutput const& output) { std::vector<Window> const& nuxwins(nux::XInputWindow::NativeHandleList()); @@ -1210,7 +1270,7 @@ bool UnityScreen::shellCouldBeHidden(CompOutput const& output) CompWindowList const& wins = screen->windows(); for ( CompWindowList::const_reverse_iterator r = wins.rbegin() ; r != wins.rend() - ; r++ + ; ++r ) { CompWindow* w = *r; @@ -1292,41 +1352,19 @@ bool UnityScreen::glPaintOutput(const GLScreenPaintAttrib& attrib, /* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */ ret = gScreen->glPaintOutput(attrib, transform, region, output, mask); -#ifndef USE_MODERN_COMPIZ_GL if (doShellRepaint && !force && fullscreenRegion.contains(*output)) doShellRepaint = false; if (doShellRepaint) +#ifdef USE_MODERN_COMPIZ_GL + paintDisplay(); +#else paintDisplay(region, transform, mask); #endif return ret; } -#ifdef USE_MODERN_COMPIZ_GL -void UnityScreen::glPaintCompositedOutput (const CompRegion ®ion, - ::GLFramebufferObject *fbo, - unsigned int mask) -{ - bool useFbo = false; - - if (doShellRepaint) - { - oldFbo = fbo->bind (); - useFbo = fbo->checkStatus () && fbo->tex (); - if (!useFbo) { - printf ("bailing from UnityScreen::glPaintCompositedOutput"); - ::GLFramebufferObject::rebind (oldFbo); - return; - } - paintDisplay(); - ::GLFramebufferObject::rebind (oldFbo); - } - - gScreen->glPaintCompositedOutput(region, fbo, mask); -} -#endif - /* called whenever a plugin needs to paint the entire scene * transformed */ @@ -1345,10 +1383,16 @@ void UnityScreen::preparePaint(int ms) { cScreen->preparePaint(ms); + // Emit the current time throught the tick_source. This moves any running + // animations along their path. + tick_source_.tick(g_get_monotonic_time()); + for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows) wi->HandleAnimations (ms); +#ifndef USE_MODERN_COMPIZ_GL compizDamageNux(cScreen->currentDamage()); +#endif didShellRepaint = false; firstWindowAboveShell = NULL; @@ -1412,31 +1456,48 @@ void UnityScreen::compizDamageNux(CompRegion const& damage) } } - auto launchers = launcher_controller_->launchers(); - for (auto launcher : launchers) + auto const& launchers = launcher_controller_->launchers(); + for (auto const& launcher : launchers) { if (!launcher->Hidden()) { - nux::Geometry geo = launcher->GetAbsoluteGeometry(); + nux::Geometry const& geo = launcher->GetAbsoluteGeometry(); CompRegion launcher_region(geo.x, geo.y, geo.width, geo.height); + if (damage.intersects(launcher_region)) launcher->QueueDraw(); - nux::ObjectPtr<nux::View> tooltip = launcher->GetActiveTooltip(); - if (!tooltip.IsNull()) + + nux::ObjectPtr<nux::View> const& tooltip = launcher->GetActiveTooltip(); + + if (tooltip) { - nux::Geometry tip = tooltip->GetAbsoluteGeometry(); - CompRegion tip_region(tip.x, tip.y, tip.width, tip.height); + nux::Geometry const& g = tooltip->GetAbsoluteGeometry(); + CompRegion tip_region(g.x, g.y, g.width, g.height); + if (damage.intersects(tip_region)) tooltip->QueueDraw(); } + + nux::ObjectPtr<LauncherDragWindow> const& dragged_icon = launcher->GetDraggedIcon(); + + if (dragged_icon) + { + nux::Geometry const& g = dragged_icon->GetAbsoluteGeometry(); + CompRegion icon_region(g.x, g.y, g.width, g.height); + + if (damage.intersects(icon_region)) + dragged_icon->QueueDraw(); + } } } std::vector<nux::View*> const& panels(panel_controller_->GetPanelViews()); for (nux::View* view : panels) { - nux::Geometry geo = view->GetAbsoluteGeometry(); + nux::Geometry const& geo = view->GetAbsoluteGeometry(); + CompRegion panel_region(geo.x, geo.y, geo.width, geo.height); + if (damage.intersects(panel_region)) view->QueueDraw(); } @@ -1447,8 +1508,9 @@ void UnityScreen::compizDamageNux(CompRegion const& damage) QuicklistView* view = qm->Current(); if (view) { - nux::Geometry geo = view->GetAbsoluteGeometry(); + nux::Geometry const& geo = view->GetAbsoluteGeometry(); CompRegion quicklist_region(geo.x, geo.y, geo.width, geo.height); + if (damage.intersects(quicklist_region)) view->QueueDraw(); } @@ -1458,6 +1520,29 @@ void UnityScreen::compizDamageNux(CompRegion const& damage) /* Grab changed nux regions and add damage rects for them */ void UnityScreen::nuxDamageCompiz() { +#ifdef USE_MODERN_COMPIZ_GL + /* + * If Nux is going to redraw anything then we have to tell Compiz to + * redraw everything. This is because Nux has a bad habit (bug??) of drawing + * more than just the regions of its DrawList. (LP: #1036519) + * + * Forunately, this does not happen on most frames. Only when the Unity + * Shell needs to redraw something. + * + * TODO: Try to figure out why redrawing the panel makes the launcher also + * redraw even though the launcher's geometry is not in DrawList, and + * stop it. Then maybe we can revert back to the old code below #else. + */ + std::vector<nux::Geometry> const& dirty = wt->GetDrawList(); + if (!dirty.empty()) + { + cScreen->damageRegionSetEnabled(this, false); + cScreen->damageScreen(); + cScreen->damageRegionSetEnabled(this, true); + } + +#else + /* * WARNING: Nux bug LP: #1014610 (unbounded DrawList growth) will cause * this code to be called far too often in some cases and @@ -1471,7 +1556,8 @@ void UnityScreen::nuxDamageCompiz() CompRegion nux_damage; std::vector<nux::Geometry> const& dirty = wt->GetDrawList(); - for (auto geo : dirty) + + for (auto const& geo : dirty) nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height); if (launcher_controller_->IsOverlayOpen()) @@ -1481,23 +1567,33 @@ void UnityScreen::nuxDamageCompiz() nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height); } - auto launchers = launcher_controller_->launchers(); - for (auto launcher : launchers) + auto const& launchers = launcher_controller_->launchers(); + for (auto const& launcher : launchers) { if (!launcher->Hidden()) { nux::ObjectPtr<nux::View> tooltip = launcher->GetActiveTooltip(); - if (!tooltip.IsNull()) + + if (tooltip) { nux::Geometry const& g = tooltip->GetAbsoluteGeometry(); nux_damage += CompRegion(g.x, g.y, g.width, g.height); } + + nux::ObjectPtr<LauncherDragWindow> const& dragged_icon = launcher->GetDraggedIcon(); + + if (dragged_icon) + { + nux::Geometry const& g = dragged_icon->GetAbsoluteGeometry(); + nux_damage += CompRegion(g.x, g.y, g.width, g.height); + } } } cScreen->damageRegionSetEnabled(this, false); cScreen->damageRegion(nux_damage); cScreen->damageRegionSetEnabled(this, true); +#endif } /* handle X Events */ @@ -1533,6 +1629,24 @@ void UnityScreen::handleEvent(XEvent* event) launcher_controller_->KeyNavTerminate(false); EnableCancelAction(CancelActionTarget::LAUNCHER_SWITCHER, false); } + if (PluginAdapter::Default()->IsScaleActive() && + event->xbutton.button == Button1 && + highlighted_window_ != 0) + { + CompWindow *w = screen->findWindow (highlighted_window_); + if (w) + { + UnityWindow *uw = UnityWindow::get (w); + CompPoint pointer (pointerX, pointerY); + if (uw->closeButtonArea ().contains (pointer)) + { + w->close (0); + skip_other_plugins = true; + } + } + + } + break; case ButtonRelease: if (switcher_controller_ && switcher_controller_->Visible()) @@ -1857,6 +1971,21 @@ bool UnityScreen::altTabInitiateCommon(CompAction* action, switcher::ShowMode sh screen->addAction(&scroll_up); screen->addAction(&scroll_down); + if (!optionGetAltTabBiasViewport()) + { + if (show_mode == switcher::ShowMode::CURRENT_VIEWPORT) + show_mode = switcher::ShowMode::ALL; + else + show_mode = switcher::ShowMode::CURRENT_VIEWPORT; + } + + SetUpAndShowSwitcher(show_mode); + + return true; +} + +void UnityScreen::SetUpAndShowSwitcher(switcher::ShowMode show_mode) +{ // maybe check launcher position/hide state? WindowManager *wm = WindowManager::Default(); @@ -1868,22 +1997,13 @@ bool UnityScreen::altTabInitiateCommon(CompAction* action, switcher::ShowMode sh monitor_geo.height -= 200; switcher_controller_->SetWorkspace(monitor_geo, monitor); - if (!optionGetAltTabBiasViewport()) - { - if (show_mode == switcher::ShowMode::CURRENT_VIEWPORT) - show_mode = switcher::ShowMode::ALL; - else - show_mode = switcher::ShowMode::CURRENT_VIEWPORT; - } - RaiseInputWindows(); - auto results = launcher_controller_->GetAltTabIcons(show_mode == switcher::ShowMode::CURRENT_VIEWPORT); + auto results = launcher_controller_->GetAltTabIcons(show_mode == switcher::ShowMode::CURRENT_VIEWPORT, + switcher_controller_->IsShowDesktopDisabled()); - if (!(results.size() == 1 && results[0]->GetIconType() == AbstractLauncherIcon::IconType::TYPE_DESKTOP)) + if (switcher_controller_->CanShowSwitcher(results)) switcher_controller_->Show(show_mode, switcher::SortMode::FOCUS_ORDER, false, results); - - return true; } bool UnityScreen::altTabTerminateCommon(CompAction* action, @@ -1934,7 +2054,9 @@ bool UnityScreen::altTabForwardAllInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options) { - if (switcher_controller_->Visible()) + if (WindowManager::Default()->IsWallActive()) + return false; + else if (switcher_controller_->Visible()) switcher_controller_->Next(); else altTabInitiateCommon(action, switcher::ShowMode::ALL); @@ -1992,7 +2114,7 @@ bool UnityScreen::altTabNextWindowInitiate(CompAction* action, CompAction::State if (!switcher_controller_->Visible()) { altTabInitiateCommon(action, switcher::ShowMode::CURRENT_VIEWPORT); - switcher_controller_->Select(1); // always select the current application + switcher_controller_->Select((switcher_controller_->StartIndex())); // always select the current application } switcher_controller_->NextDetail(); @@ -2165,10 +2287,9 @@ bool UnityScreen::ShowHudInitiate(CompAction* action, { // Look to see if there is a keycode. If there is, then this isn't a // modifier only keybinding. - int key_code = 0; if (options[6].type() != CompOption::TypeUnset) { - key_code = options[6].value().i(); + int key_code = options[6].value().i(); LOG_DEBUG(logger) << "HUD initiate key code: " << key_code; // show it now, no timings or terminate needed. return ShowHud(); @@ -2319,7 +2440,7 @@ bool isNuxWindow (CompWindow* value) auto id = value->id(); // iterate loop by hand rather than use std::find as this is considerably faster - // we care about performance here becuase of the high frequency in which this function is + // we care about performance here because of the high frequency in which this function is // called (nearly every frame) unsigned int size = xwns.size(); for (unsigned int i = 0; i < size; ++i) @@ -2483,6 +2604,40 @@ bool UnityWindow::glDraw(const GLMatrix& matrix, } void +UnityScreen::OnMinimizeDurationChanged () +{ + /* Update the compiz plugin setting with the new computed speed so that it + * will be used in the following minimizations */ + CompPlugin *p = CompPlugin::find("animation"); + if (p) + { + CompOption::Vector &opts = p->vTable->getOptions(); + + for (CompOption &o : opts) + { + if (o.name () == std::string ("minimize_durations")) + { + /* minimize_durations is a list value, but minimize applies only to + * normal windows, so there's always one value */ + CompOption::Value& value = o.value(); + CompOption::Value::Vector& list = value.list(); + CompOption::Value::Vector::iterator i = list.begin(); + if (i != list.end()) { + i->set(minimize_speed_controller->getDuration()); + } + value.set(list); + screen->setOptionForPlugin(p->vTable->name().c_str(), + o.name().c_str(), value); + break; + } + } + } + else { + LOG_WARN(logger) << "Animation plugin not found. Can't set minimize speed."; + } +} + +void UnityWindow::minimize () { if (!window->managed ()) @@ -2595,6 +2750,14 @@ void UnityWindow::windowNotify(CompWindowNotify n) window->minimizedSetEnabled (this, false); } break; + case CompWindowNotifyBeforeDestroy: + being_destroyed.emit(); + break; + case CompWindowNotifyMinimize: + /* Updating the count in dconf will trigger a "changed" signal to which + * the method setting the new animation speed is attached */ + UnityScreen::get(screen)->minimize_speed_controller->UpdateCount(); + break; default: break; } @@ -2863,14 +3026,14 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num) case UnityshellOptions::AutomaximizeValue: PluginAdapter::Default()->SetCoverageAreaBeforeAutomaximize(optionGetAutomaximizeValue() / 100.0f); break; - case UnityshellOptions::DevicesOption: - unity::DevicesSettings::GetDefault().SetDevicesOption((unity::DevicesSettings::DevicesOption) optionGetDevicesOption()); - break; case UnityshellOptions::AltTabTimeout: switcher_controller_->detail_on_timeout = optionGetAltTabTimeout(); case UnityshellOptions::AltTabBiasViewport: PluginAdapter::Default()->bias_active_to_viewport = optionGetAltTabBiasViewport(); break; + case UnityshellOptions::DisableShowDesktop: + switcher_controller_->SetShowDesktopDisabled(optionGetDisableShowDesktop()); + break; case UnityshellOptions::ShowMinimizedWindows: compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>::setFunctions (optionGetShowMinimizedWindows ()); screen->enterShowDesktopModeSetEnabled (this, optionGetShowMinimizedWindows ()); @@ -2894,9 +3057,13 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num) break; case UnityshellOptions::RevealPressure: launcher_options->edge_reveal_pressure = optionGetRevealPressure() * 100; + break; case UnityshellOptions::EdgeResponsiveness: launcher_options->edge_responsiveness = optionGetEdgeResponsiveness(); break; + case UnityshellOptions::EdgePassedDisabledMs: + launcher_options->edge_passed_disabled_ms = optionGetEdgePassedDisabledMs(); + break; default: break; } @@ -3037,6 +3204,16 @@ void UnityScreen::initLauncher() ScheduleRelayout(0); } +switcher::Controller::Ptr UnityScreen::switcher_controller() +{ + return switcher_controller_; +} + +launcher::Controller::Ptr UnityScreen::launcher_controller() +{ + return launcher_controller_; +} + void UnityScreen::InitHints() { // TODO move category text into a vector... @@ -3044,58 +3221,243 @@ void UnityScreen::InitHints() // Launcher... std::string const launcher(_("Launcher")); - hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", _(" (Press)"), _("Open Launcher, displays shortcuts."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher" )); - hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", "", _("Open Launcher keyboard navigation mode."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "keyboard_focus")); - hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", "", _("Switch applications via Launcher."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "launcher_switcher_forward")); - hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", _(" + 1 to 9"), _("Same as clicking on a Launcher icon."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher")); - hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", _(" + Shift + 1 to 9"), _("Open new window of the app."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher")); - hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", " + T", _("Open the Trash."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher")); + hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", _(" (Hold)"), + _("Opens the Launcher, displays shortcuts."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_launcher" )); + + hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", "", + _("Opens Launcher keyboard navigation mode."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "keyboard_focus")); + + hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", "", + _("Switches applications via the Launcher."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "launcher_switcher_forward")); + + hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", _(" + 1 to 9"), + _("Same as clicking on a Launcher icon."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_launcher")); + + hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", _(" + Shift + 1 to 9"), + _("Opens a new window in the app."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_launcher")); + + hints_.push_back(std::make_shared<shortcut::Hint>(launcher, "", " + T", + _("Opens the Trash."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_launcher")); + // Dash... std::string const dash( _("Dash")); - hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", _(" (Tap)"), _("Open the Dash Home."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher")); - hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + A", _("Open the Dash App Lens."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher")); - hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + F", _("Open the Dash Files Lens."), shortcut::COMPIZ_KEY_OPTION,"unityshell", "show_launcher")); - hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + M", _("Open the Dash Music Lens."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_launcher")); - hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", "", _("Switches between Lenses."), shortcut::HARDCODED_OPTION, _("Ctrl + Tab"))); - hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", "", _("Moves the focus."), shortcut::HARDCODED_OPTION, _("Cursor Keys"))); - hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", "", _("Open currently focused item."), shortcut::HARDCODED_OPTION, _("Enter & Return"))); + hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", _(" (Tap)"), + _("Opens the Dash Home."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_launcher")); + + hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + A", + _("Opens the Dash App Lens."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_launcher")); + + hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + F", + _("Opens the Dash Files Lens."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_launcher")); + + hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + M", + _("Opens the Dash Music Lens."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_launcher")); + + hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", " + V", + _("Opens the Dash Video Lens."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_launcher")); + + hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", "", + _("Switches between Lenses."), + shortcut::HARDCODED_OPTION, + _("Ctrl + Tab"))); + + hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", "", + _("Moves the focus."), + shortcut::HARDCODED_OPTION, + _("Arrow Keys"))); + + hints_.push_back(std::make_shared<shortcut::Hint>(dash, "", "", + _("Opens the currently focused item."), + shortcut::HARDCODED_OPTION, + _("Enter"))); // Menu Bar std::string const menubar(_("HUD & Menu Bar")); - hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", _(" (Tap)"), _("Open the HUD."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "show_hud")); - hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", _(" (Press)"), _("Reveals application menu."), shortcut::HARDCODED_OPTION, "Alt")); - hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", "", _("Opens the indicator menu."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "panel_first_menu")); - hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", "", _("Moves focus between indicators."), shortcut::HARDCODED_OPTION, _("Cursor Left or Right"))); + hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", _(" (Tap)"), + _("Opens the HUD."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "show_hud")); + + hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", " (Hold)", + _("Reveals the application menu."), + shortcut::HARDCODED_OPTION, + "Alt")); + + hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", "", + _("Opens the indicator menu."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "panel_first_menu")); + + hints_.push_back(std::make_shared<shortcut::Hint>(menubar, "", "", + _("Moves focus between indicators."), + shortcut::HARDCODED_OPTION, + _("Cursor Left or Right"))); // Switching std::string const switching(_("Switching")); - hints_.push_back(std::make_shared<shortcut::Hint>(switching, "", "", _("Switch between applications."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "alt_tab_forward")); - hints_.push_back(std::make_shared<shortcut::Hint>(switching, "", "", _("Switch windows of current application."), shortcut::COMPIZ_KEY_OPTION, "unityshell", "alt_tab_next_window")); - hints_.push_back(std::make_shared<shortcut::Hint>(switching, "", "", _("Moves the focus."), shortcut::HARDCODED_OPTION, _("Cursor Left or Right"))); + hints_.push_back(std::make_shared<shortcut::Hint>(switching, "", "", + _("Switches between applications."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "alt_tab_forward")); + + hints_.push_back(std::make_shared<shortcut::Hint>(switching, "", "", + _("Switches windows of current applications."), + shortcut::COMPIZ_KEY_OPTION, + "unityshell", + "alt_tab_next_window")); + + hints_.push_back(std::make_shared<shortcut::Hint>(switching, "", "", + _("Moves the focus."), + shortcut::HARDCODED_OPTION, + _("Cursor Left or Right"))); // Workspaces std::string const workspaces(_("Workspaces")); - hints_.push_back(std::make_shared<shortcut::Hint>(workspaces, "", "", _("Spread workspaces."), shortcut::COMPIZ_KEY_OPTION, "expo", "expo_key")); - hints_.push_back(std::make_shared<shortcut::Hint>(workspaces, "", _(" + Cursor Keys"), _("Switch workspaces."), shortcut::COMPIZ_METAKEY_OPTION, "wall", "left_key")); - hints_.push_back(std::make_shared<shortcut::Hint>(workspaces, "", _(" + Cursor Keys"), _("Move focused window to different workspace."), shortcut::COMPIZ_METAKEY_OPTION, "wall", "left_window_key")); + hints_.push_back(std::make_shared<shortcut::Hint>(workspaces, "", "", + _("Switches between workspaces."), + shortcut::COMPIZ_KEY_OPTION, + "expo", + "expo_key")); + + hints_.push_back(std::make_shared<shortcut::Hint>(workspaces, "", _(" + Arrow Keys"), + _("Switches workspaces."), + shortcut::COMPIZ_METAKEY_OPTION, + "wall", + "left_key")); + + hints_.push_back(std::make_shared<shortcut::Hint>(workspaces, "", _(" + Arrow Keys"), + _("Moves focused window to another workspace."), + shortcut::COMPIZ_METAKEY_OPTION, + "wall", + "left_window_key")); + // Windows std::string const windows(_("Windows")); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Spreads all windows in the current workspace."), shortcut::COMPIZ_KEY_OPTION, "scale", "initiate_all_key")); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Minimises all windows."), shortcut::COMPIZ_KEY_OPTION, "core", "show_desktop_key")); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Maximises the current window."), shortcut::COMPIZ_KEY_OPTION, "core", "maximize_window_key")); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Restores or minimises current window."), shortcut::COMPIZ_KEY_OPTION, "core", "unmaximize_window_key")); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" or Right"), _("Semi-maximises current window."), shortcut::COMPIZ_KEY_OPTION, "grid", "put_left_key")); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Closes current window."), shortcut::COMPIZ_KEY_OPTION, "core", "close_window_key")); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Opens window accessibility menu."), shortcut::HARDCODED_OPTION, _("Alt + Space"))); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", _("Places window in corresponding positions."), shortcut::HARDCODED_OPTION, _("Ctrl + Alt + Num"))); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" Drag"), _("Move window."), shortcut::COMPIZ_MOUSE_OPTION, "move", "initiate_button")); - hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" Drag"), _("Resize window."), shortcut::COMPIZ_MOUSE_OPTION, "resize", "initiate_button")); + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", + _("Spreads all windows in the current workspace."), + shortcut::COMPIZ_KEY_OPTION, + "scale", + "initiate_all_key")); + + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", + _("Minimises all windows."), + shortcut::COMPIZ_KEY_OPTION, + "core", + "show_desktop_key")); + + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", + _("Maximises the current window."), + shortcut::COMPIZ_KEY_OPTION, + "core", + "maximize_window_key")); + + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", + _("Restores or minimises the current window."), + shortcut::COMPIZ_KEY_OPTION, + "core", + "unmaximize_window_key")); + + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" or Right"), + _("Semi-maximise the current window."), + shortcut::COMPIZ_KEY_OPTION, + "grid", + "put_left_key")); + + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", + _("Closes the current window."), + shortcut::COMPIZ_KEY_OPTION, + "core", + "close_window_key")); + + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", + _("Opens the window accessibility menu."), + shortcut::HARDCODED_OPTION, + _("Alt + Space"))); + + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", "", + _("Places the window in corresponding position."), + shortcut::HARDCODED_OPTION, + _("Ctrl + Alt + Num"))); + + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" Drag"), + _("Moves the window."), + shortcut::COMPIZ_MOUSE_OPTION, + "move", + "initiate_button")); + + hints_.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" Drag"), + _("Resizes the window."), + shortcut::COMPIZ_MOUSE_OPTION, + "resize", + "initiate_button")); +} + +void UnityScreen::InitGesturesSupport() +{ + std::unique_ptr<nux::GestureBroker> gesture_broker(new UnityGestureBroker); + wt->GetWindowCompositor().SetGestureBroker(std::move(gesture_broker)); + + gestures_sub_launcher_.reset(new nux::GesturesSubscription); + gestures_sub_launcher_->SetGestureClasses(nux::DRAG_GESTURE); + gestures_sub_launcher_->SetNumTouches(4); + gestures_sub_launcher_->SetWindowId(GDK_ROOT_WINDOW()); + gestures_sub_launcher_->Activate(); + + gestures_sub_dash_.reset(new nux::GesturesSubscription); + gestures_sub_dash_->SetGestureClasses(nux::TAP_GESTURE); + gestures_sub_dash_->SetNumTouches(4); + gestures_sub_dash_->SetWindowId(GDK_ROOT_WINDOW()); + gestures_sub_dash_->Activate(); + + gestures_sub_windows_.reset(new nux::GesturesSubscription); + gestures_sub_windows_->SetGestureClasses(nux::TOUCH_GESTURE + | nux::DRAG_GESTURE + | nux::PINCH_GESTURE); + gestures_sub_windows_->SetNumTouches(3); + gestures_sub_windows_->SetWindowId(GDK_ROOT_WINDOW()); + gestures_sub_windows_->Activate(); } /* Window init */ @@ -3106,9 +3468,11 @@ UnityWindow::UnityWindow(CompWindow* window) , gWindow(GLWindow::get(window)) , mMinimizeHandler() , mShowdesktopHandler(nullptr) + , window_header_style_(0) { WindowInterface::setHandler(window); GLWindowInterface::setHandler(gWindow); + ScaleWindowInterface::setHandler (ScaleWindow::get (window)); if (UnityScreen::get (screen)->optionGetShowMinimizedWindows () && window->mapNum ()) @@ -3153,6 +3517,292 @@ UnityWindow::UnityWindow(CompWindow* window) } } +void UnityWindow::DrawTexture (GLTexture* icon, + const GLWindowPaintAttrib& attrib, + const GLMatrix& transform, + unsigned int mask, + float x, float y, + int &maxWidth, int &maxHeight) +{ + if (icon) + { + int width, height; + width = icon->width (); + height = icon->height (); + + if (height > maxHeight) + maxHeight = height; + + if (width > maxWidth) + maxWidth = width; + + CompRegion iconReg (0, 0, width, height); + GLTexture::MatrixList ml (1); + + ml[0] = icon->matrix (); + gWindow->vertexBuffer ()->begin (); + if (width && height) + gWindow->glAddGeometry (ml, iconReg, iconReg); + + if (gWindow->vertexBuffer ()->end ()) + { + GLMatrix wTransform (transform); + + wTransform.translate (x, y, 0.0f); + + gWindow->glDrawTexture (icon, wTransform, attrib, mask); + } + } +} + +WindowCairoContext* UnityWindow::CreateCairoContext (float width, float height) +{ + XRenderPictFormat *format; + Screen *xScreen; + WindowCairoContext *context = new WindowCairoContext(); + + xScreen = ScreenOfDisplay (screen->dpy (), screen->screenNum ()); + + format = XRenderFindStandardFormat (screen->dpy (), PictStandardARGB32); + context->pixmap_ = XCreatePixmap (screen->dpy (), + screen->root (), + width, height, 32); + + context->texture_ = GLTexture::bindPixmapToTexture (context->pixmap_, + width, height, + 32); + if (context->texture_.empty ()) + { + delete context; + return 0; + } + + context->surface_ = cairo_xlib_surface_create_with_xrender_format (screen->dpy (), + context->pixmap_, + xScreen, + format, + width, + height); + context->cr_ = cairo_create (context->surface_); + + // clear + cairo_save (context->cr_); + cairo_set_operator (context->cr_, CAIRO_OPERATOR_CLEAR); + cairo_paint (context->cr_); + cairo_restore (context->cr_); + + return context; +} + +void UnityWindow::RenderText (WindowCairoContext *context, + float x, float y, + float maxWidth, float maxHeight) +{ + PangoFontDescription* font = pango_font_description_new (); + pango_font_description_set_family (font, "sans"); + pango_font_description_set_absolute_size (font, 12 * PANGO_SCALE); + pango_font_description_set_style (font, PANGO_STYLE_NORMAL); + pango_font_description_set_weight (font, PANGO_WEIGHT_BOLD); + + PangoLayout* layout = pango_cairo_create_layout (context->cr_); + pango_layout_set_font_description (layout, font); + pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); + pango_layout_set_height (layout, maxHeight); + + pango_layout_set_auto_dir (layout, false); + pango_layout_set_text (layout, + GetWindowName (window->id ()).c_str (), + -1); + + /* update the size of the pango layout */ + pango_layout_set_width (layout, maxWidth * PANGO_SCALE); + pango_cairo_update_layout (context->cr_, layout); + + cairo_set_operator (context->cr_, CAIRO_OPERATOR_OVER); + + cairo_set_source_rgba (context->cr_, + 1.0, + 1.0, + 1.0, + 1.0); + + // alignment + int lWidth, lHeight; + pango_layout_get_pixel_size (layout, &lWidth, &lHeight); + + y = ((maxHeight - lHeight) / 2.0) + y; + cairo_translate (context->cr_, x, y); + pango_cairo_show_layout (context->cr_, layout); +} + +void UnityWindow::DrawWindowTitle (const GLWindowPaintAttrib& attrib, + const GLMatrix& transform, + unsigned int mask, + float x, float y, float x2, float y2) +{ + const float width = x2 - x; + + // Paint a fake window decoration + WindowCairoContext *context = CreateCairoContext (width, SCALE_WINDOW_TITLE_SIZE); + + cairo_save (context->cr_); + cairo_push_group (context->cr_); + + // Round window decoration top border + const double height = SCALE_WINDOW_TITLE_SIZE; + const double aspect = 1.0; + const double corner_radius = height / 10.0; + const double radius = corner_radius / aspect; + const double degrees = M_PI / 180.0; + + cairo_new_sub_path (context->cr_); + + cairo_arc (context->cr_, radius, radius, radius, 180 * degrees, 270 * degrees); + cairo_arc (context->cr_, width - radius, radius, radius, -90 * degrees, 0 * degrees); + cairo_line_to (context->cr_, width, height); + cairo_line_to (context->cr_, 0, height); + + cairo_close_path (context->cr_); + cairo_clip (context->cr_); + + // Draw window decoration abased on gtk style + gtk_render_background (window_header_style_, context->cr_, 0, 0, width, SCALE_WINDOW_TITLE_SIZE); + gtk_render_frame (window_header_style_, context->cr_, 0, 0, width, SCALE_WINDOW_TITLE_SIZE); + + cairo_pop_group_to_source (context->cr_); + + cairo_paint_with_alpha (context->cr_, 1.0); + cairo_restore (context->cr_); + + // Draw windows title + RenderText (context, + CLOSE_ICON_SPACE * 2 + CLOSE_ICON_SIZE, + 0.0, + width, SCALE_WINDOW_TITLE_SIZE); + + mask |= PAINT_WINDOW_BLEND_MASK; + int maxWidth, maxHeight; + foreach(GLTexture *icon, context->texture_) + { + DrawTexture (icon, attrib, transform, mask, + x, y, + maxWidth , maxHeight); + } + + delete context; +} + +void UnityWindow::scalePaintDecoration (const GLWindowPaintAttrib& attrib, + const GLMatrix& transform, + const CompRegion& region, + unsigned int mask) +{ + ScaleWindow *sWindow = ScaleWindow::get (window); + if (!sWindow) + return; + + sWindow->scalePaintDecoration (attrib, transform, region, mask); + + if (!sWindow->hasSlot()) // animation not finished + return; + + if (!window_header_style_) + { + GtkWidgetPath* widget_path = gtk_widget_path_new (); + gint pos = gtk_widget_path_append_type (widget_path, GTK_TYPE_WINDOW); + gtk_widget_path_iter_set_name (widget_path, pos, "UnityPanelWidget"); + + window_header_style_ = gtk_style_context_new (); + gtk_style_context_set_path (window_header_style_, widget_path); + gtk_style_context_add_class (window_header_style_, "gnome-panel-menu-bar"); + gtk_style_context_add_class (window_header_style_, "unity-panel"); + + // get close button + panel::Style& style = panel::Style::Instance(); + + std::vector<std::string> files = style.GetWindowButtonFileNames (panel::WindowButtonType::CLOSE, + panel::WindowState::NORMAL); + + CompString pName ("unityshell"); + foreach (std::string file, files) + { + CompString fileName (file.c_str ()); + CompSize size (CLOSE_ICON_SIZE, CLOSE_ICON_SIZE); + close_icon_ = GLTexture::readImageToTexture (fileName, + pName, + size); + if (close_icon_.size () != 0) + break; + } + + if (close_icon_.size () == 0) + { + CompString fileName (PKGDATADIR"/close_dash.png"); + CompSize size (CLOSE_ICON_SIZE, CLOSE_ICON_SIZE); + close_icon_ = GLTexture::readImageToTexture (fileName, + pName, + size); + } + } + + // Make the windows header opaque to override the original + GLWindowPaintAttrib sAttrib (attrib); + sAttrib.opacity = OPAQUE; + + ScalePosition pos = sWindow->getCurrentPosition (); + int maxHeight, maxWidth; + // Use "2" as margin to make sure to cover all originial decoration + const float width = (window->width () + 4) * pos.scale; + const float x = pos.x () + window->x () - (2 * pos.scale); + const float y = pos.y () + window->y () - SCALE_WINDOW_TITLE_SIZE; + const float iconX = x + CLOSE_ICON_SPACE; + const float iconY = y + ((SCALE_WINDOW_TITLE_SIZE - CLOSE_ICON_SIZE) / 2.0); + + maxHeight = maxWidth = 0; + + DrawWindowTitle (sAttrib, + transform, + mask, + x, y, + x + width, y + SCALE_WINDOW_TITLE_SIZE); + + mask |= PAINT_WINDOW_BLEND_MASK; + foreach(GLTexture *icon, close_icon_) + { + DrawTexture (icon, sAttrib, transform, mask, + iconX, iconY, + maxWidth , maxHeight); + } + + close_button_area_ = CompRect (iconX, iconY, maxWidth, maxHeight); +} + +void UnityWindow::scaleSelectWindow () +{ + UnityScreen* us = UnityScreen::get(screen); + + if (us->highlighted_window_ != window->id ()) + { + CompositeWindow *cWindow = CompositeWindow::get (window); + if (cWindow) + cWindow->addDamage (); + + cWindow = 0; + CompWindow *old_window = screen->findWindow (us->highlighted_window_); + if (old_window) + cWindow = CompositeWindow::get (old_window); + + if (cWindow) + cWindow->addDamage (); + + us->highlighted_window_ = window->id (); + } + + ScaleWindow *sWindow = ScaleWindow::get (window); + if (sWindow) + sWindow->scaleSelectWindow (); +} + UnityWindow::~UnityWindow() { UnityScreen* us = UnityScreen::get(screen); @@ -3171,6 +3821,9 @@ UnityWindow::~UnityWindow() window->minimize (); } + if (window_header_style_) + g_object_unref (window_header_style_); + ShowdesktopHandler::animating_windows.remove (static_cast <ShowdesktopHandlerWindowInterface *> (this)); if (mShowdesktopHandler) @@ -3210,6 +3863,84 @@ bool UnityPluginVTable::init() return true; } +CompString UnityWindow::GetUtf8Property (Window id, + Atom atom) +{ + Atom type; + int result, format; + unsigned long nItems, bytesAfter; + char *val; + CompString retval; + Atom utf8StringAtom; + + utf8StringAtom = XInternAtom (screen->dpy (), "UTF8_STRING", 0); + result = XGetWindowProperty (screen->dpy (), id, atom, 0L, 65536, False, + utf8StringAtom, &type, &format, &nItems, + &bytesAfter, (unsigned char **) &val); + + if (result != Success) + return retval; + + if (type == utf8StringAtom && format == 8 && val && nItems > 0) + { + char valueString[nItems + 1]; + strncpy (valueString, val, nItems); + valueString[nItems] = 0; + retval = valueString; + } + if (val) + XFree (val); + + return retval; +} + +CompString UnityWindow::GetTextProperty (Window id, + Atom atom) +{ + XTextProperty text; + CompString retval; + + text.nitems = 0; + if (XGetTextProperty (screen->dpy (), id, &text, atom)) + { + if (text.value) + { + char valueString[text.nitems + 1]; + + strncpy (valueString, (char *) text.value, text.nitems); + valueString[text.nitems] = 0; + + retval = valueString; + + XFree (text.value); + } + } + + return retval; +} + + +CompString UnityWindow::GetWindowName (Window id) +{ + CompString name; + Atom visibleNameAtom; + + visibleNameAtom = XInternAtom (screen->dpy (), "_NET_WM_VISIBLE_NAME", 0); + name = GetUtf8Property (id, visibleNameAtom); + if (name.empty ()) + { + Atom wmNameAtom = XInternAtom (screen->dpy (), "_NET_WM_NAME", 0); + name = GetUtf8Property (id, wmNameAtom); + } + + + if (name.empty ()) + name = GetTextProperty (id, XA_WM_NAME); + + return name; +} + + namespace { diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h index 34e29975e..b9bea314a 100644 --- a/plugins/unityshell/src/unityshell.h +++ b/plugins/unityshell/src/unityshell.h @@ -22,11 +22,14 @@ #ifndef UNITYSHELL_H #define UNITYSHELL_H +#include <NuxCore/AnimationController.h> +#include <Nux/GesturesSubscription.h> #include <Nux/WindowThread.h> #include <NuxCore/Property.h> #include <sigc++/sigc++.h> #include <boost/shared_ptr.hpp> +#include <scale/scale.h> #include <core/core.h> #include <core/pluginclasshandler.h> #include <composite/composite.h> @@ -46,12 +49,12 @@ #include "PanelController.h" #include "PanelStyle.h" #include "UScreen.h" -#include "GestureEngine.h" #include "DebugDBusInterface.h" #include "SwitcherController.h" #include "UBusWrapper.h" #include "UnityshellPrivate.h" #include "UnityShowdesktopHandler.h" +#include "ThumbnailGenerator.h" #ifndef USE_MODERN_COMPIZ_GL #include "ScreenEffectFramebufferObject.h" #endif @@ -62,10 +65,14 @@ #include <dlfcn.h> #include "HudController.h" +#include "ThumbnailGenerator.h" +#include "WindowMinimizeSpeedController.h" namespace unity { +class WindowCairoContext; + /* base screen class */ class UnityScreen : public unity::debug::Introspectable, @@ -122,11 +129,6 @@ public: const CompRegion&, CompOutput*, unsigned int); -#ifdef USE_MODERN_COMPIZ_GL - void glPaintCompositedOutput (const CompRegion ®ion, - ::GLFramebufferObject *fbo, - unsigned int mask); -#endif /* paint in the special case that the output is transformed */ void glPaintTransformedOutput(const GLScreenPaintAttrib&, @@ -190,6 +192,13 @@ public: bool forcePaintOnTop (); + void SetUpAndShowSwitcher(switcher::ShowMode show_mode = switcher::ShowMode::CURRENT_VIEWPORT); + + void OnMinimizeDurationChanged(); + + switcher::Controller::Ptr switcher_controller(); + launcher::Controller::Ptr launcher_controller(); + protected: std::string GetName() const; void AddProperties(GVariantBuilder* builder); @@ -239,12 +248,17 @@ private: void OnPanelStyleChanged(); + void InitGesturesSupport(); + + nux::animation::TickSource tick_source_; + nux::animation::AnimationController animation_controller_; + Settings dash_settings_; dash::Style dash_style_; panel::Style panel_style_; FontSettings font_settings_; - GeisAdapter geis_adapter_; internal::FavoriteStoreGSettings favorite_store_; + ThumbnailGenerator thumbnail_generator_; /* The window thread should be the last thing removed, as c++ does it in reverse order */ std::unique_ptr<nux::WindowThread> wt; @@ -261,7 +275,15 @@ private: std::list<shortcut::AbstractHint::Ptr> hints_; bool enable_shortcut_overlay_; - GestureEngine gesture_engine_; + /* Subscription for gestures that manipulate Unity launcher */ + std::unique_ptr<nux::GesturesSubscription> gestures_sub_launcher_; + + /* Subscription for gestures that manipulate Unity dash */ + std::unique_ptr<nux::GesturesSubscription> gestures_sub_dash_; + + /* Subscription for gestures that manipulate windows. */ + std::unique_ptr<nux::GesturesSubscription> gestures_sub_windows_; + bool needsRelayout; bool _in_paint; bool super_keypressed_; @@ -323,7 +345,11 @@ private: UBusManager ubus_manager_; glib::SourceManager sources_; + unity::ThumbnailGenerator thumb_generator; + Window highlighted_window_; + + WindowMinimizeSpeedController* minimize_speed_controller; friend class UnityWindow; }; @@ -332,6 +358,7 @@ class UnityWindow : public GLWindowInterface, public ShowdesktopHandlerWindowInterface, public compiz::WindowInputRemoverLockAcquireInterface, + public WrapableHandler<ScaleWindowInterface, 4>, public BaseSwitchWindow, public PluginClassHandler <UnityWindow, CompWindow> { @@ -392,12 +419,23 @@ public: void handleEvent (XEvent *event); + CompRect closeButtonArea (); + typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow> UnityMinimizedHandler; std::unique_ptr <UnityMinimizedHandler> mMinimizeHandler; ShowdesktopHandler *mShowdesktopHandler; + //! Emited when CompWindowNotifyBeforeDestroy is received + sigc::signal<void> being_destroyed; + + void scaleSelectWindow (); + void scalePaintDecoration (const GLWindowPaintAttrib &, + const GLMatrix &, + const CompRegion &, + unsigned int); + private: void DoEnableFocus (); void DoDisableFocus (); @@ -429,8 +467,32 @@ private: compiz::WindowInputRemoverLock::Ptr GetInputRemover (); + void DrawWindowTitle (const GLWindowPaintAttrib& attrib, + const GLMatrix& transform, + unsigned int mask, + float x, float y, float x2, float y2); + void DrawTexture (GLTexture *icon, + const GLWindowPaintAttrib& attrib, + const GLMatrix& transform, + unsigned int mask, + float x, float y, + int &maxWidth, int &maxHeight); + void RenderText (WindowCairoContext *context, + float x, float y, + float maxWidth, float maxHeight); + WindowCairoContext* CreateCairoContext (float width, float height); + + // based on compiz text plugin + CompString GetWindowName (Window id); + CompString GetUtf8Property (Window id, Atom atom); + CompString GetTextProperty (Window id, Atom atom); + compiz::WindowInputRemoverLock::Weak input_remover_; glib::Source::UniquePtr focus_desktop_timeout_; + + GLTexture::List close_icon_; + CompRect close_button_area_; + GtkStyleContext* window_header_style_; }; |
