Back to index

unity  6.0.0
PointerBarrier.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003 * Copyright (C) 2011 Canonical Ltd
00004 *
00005 * This program is free software: you can redistribute it and/or modify
00006 * it under the terms of the GNU General Public License version 3 as
00007 * published by the Free Software Foundation.
00008 *
00009 * This program is distributed in the hope that it will be useful,
00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 * GNU General Public License for more details.
00013 *
00014 * You should have received a copy of the GNU General Public License
00015 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 */
00017 
00018 #include <unistd.h>
00019 #include <stdlib.h>
00020 #include <stdio.h>
00021 #include <X11/extensions/Xfixes.h>
00022 
00023 #include "PointerBarrier.h"
00024 
00025 namespace unity
00026 {
00027 namespace ui
00028 {
00029 
00030 namespace local
00031 {
00032 namespace
00033 {
00034   bool is_selected_for = false;
00035 }
00036 }
00037 
00038 PointerBarrierWrapper::PointerBarrierWrapper()
00039   : active(false)
00040   , smoothing(75)
00041   , max_velocity_multiplier(1.0f)
00042   , direction(BOTH)
00043   , last_event_(0)
00044   , last_x_(0)
00045   , last_y_(0)
00046   , smoothing_count_(0)
00047   , smoothing_accum_(0)
00048 {}
00049 
00050 PointerBarrierWrapper::~PointerBarrierWrapper()
00051 {
00052   DestroyBarrier();
00053 }
00054 
00055 void PointerBarrierWrapper::ConstructBarrier()
00056 {
00057   if (active)
00058     return;
00059 
00060   Display *dpy = nux::GetGraphicsDisplay()->GetX11Display();
00061 
00062   XFixesQueryExtension(dpy, &event_base_, &error_base_);
00063 
00064   int maj,min;
00065   XFixesQueryVersion(dpy, &maj, &min);
00066 
00067   barrier = XFixesCreatePointerBarrierVelocity(dpy,
00068                                                DefaultRootWindow(dpy),
00069                                                x1, y1,
00070                                                x2, y2,
00071                                                (int) direction,
00072                                                threshold,
00073                                                0,
00074                                                NULL);
00075 
00076   if (!local::is_selected_for)
00077   {
00078     XFixesSelectBarrierInput(dpy, DefaultRootWindow(dpy), 0xdeadbeef);
00079     local::is_selected_for = true;
00080   }
00081 
00082   active = true;
00083 
00084   nux::GraphicsDisplay::EventFilterArg event_filter;
00085   event_filter.filter = &PointerBarrierWrapper::HandleEventWrapper;
00086   event_filter.data = this;
00087 
00088   nux::GetGraphicsDisplay()->AddEventFilter(event_filter);
00089 }
00090 
00091 void PointerBarrierWrapper::DestroyBarrier()
00092 {
00093   if (!active)
00094     return;
00095 
00096   active = false;
00097 
00098   Display *dpy = nux::GetGraphicsDisplay()->GetX11Display();
00099   XFixesDestroyPointerBarrier(dpy, barrier);
00100 
00101   nux::GetGraphicsDisplay()->RemoveEventFilter(this);
00102 }
00103 
00104 void PointerBarrierWrapper::ReleaseBarrier(int event_id)
00105 {
00106   XFixesBarrierReleasePointer (nux::GetGraphicsDisplay()->GetX11Display(), barrier, event_id);
00107 }
00108 
00109 void PointerBarrierWrapper::EmitCurrentData()
00110 {
00111   if (smoothing_count_ <= 0)
00112     return;
00113 
00114   BarrierEvent::Ptr event (new BarrierEvent());
00115   event->x = last_x_;
00116   event->y = last_y_;
00117   event->velocity = std::min<int> (600 * max_velocity_multiplier, smoothing_accum_ / smoothing_count_);
00118   event->event_id = last_event_;
00119 
00120   barrier_event.emit(this, event);
00121 
00122   smoothing_accum_ = 0;
00123   smoothing_count_ = 0;
00124 }
00125 
00126 bool PointerBarrierWrapper::HandleEvent(XEvent xevent)
00127 {
00128   if(xevent.type - event_base_ == XFixesBarrierNotify)
00129   {
00130     XFixesBarrierNotifyEvent *notify_event = (XFixesBarrierNotifyEvent *)&xevent;
00131 
00132     if (notify_event->barrier == barrier && notify_event->subtype == XFixesBarrierHitNotify)
00133     {
00134       last_x_ = notify_event->x;
00135       last_y_ = notify_event->y;
00136       last_event_ = notify_event->event_id;
00137       smoothing_accum_ += notify_event->velocity;
00138       smoothing_count_++;
00139 
00140       if (!smoothing_timeout_)
00141       {
00142         auto smoothing_cb = [&] ()
00143         {
00144           EmitCurrentData();
00145 
00146           smoothing_timeout_.reset();
00147           return false;
00148         };
00149 
00150         smoothing_timeout_.reset(new glib::Timeout(smoothing(), smoothing_cb));
00151       }
00152 
00153     }
00154 
00155     return notify_event->barrier == barrier;
00156   }
00157 
00158   return false;
00159 }
00160 
00161 bool PointerBarrierWrapper::HandleEventWrapper(XEvent event, void* data)
00162 {
00163   PointerBarrierWrapper* wrapper = (PointerBarrierWrapper*)data;
00164   return wrapper->HandleEvent(event);
00165 }
00166 
00167 }
00168 }