mirror of
https://gitee.com/houstudio/Cdroid.git
synced 2024-12-01 19:58:14 +08:00
remaking looper impl,remove MessageListener
This commit is contained in:
parent
6bfddb7370
commit
ee104a0285
6
apps/samples/animation.cc
Normal file → Executable file
6
apps/samples/animation.cc
Normal file → Executable file
@ -21,7 +21,7 @@ public :
|
||||
canvas.stroke();
|
||||
}
|
||||
|
||||
virtual bool onMessage(DWORD msg,DWORD wp,ULONG lp)override{
|
||||
/*virtual bool onMessage(DWORD msg,DWORD wp,ULONG lp)override{
|
||||
if(msg==1000){
|
||||
matrix.scale(cx,cx);cx+=0.01f;
|
||||
matrix.rotate(cx);
|
||||
@ -30,7 +30,7 @@ public :
|
||||
return true;
|
||||
}
|
||||
return Window::onMessage(msg,wp,lp);;
|
||||
}
|
||||
}*/
|
||||
};
|
||||
|
||||
int main(int argc,const char*argv[]){
|
||||
@ -40,7 +40,7 @@ int main(int argc,const char*argv[]){
|
||||
|
||||
w->addView(new TextView("HelloWorld",400,80));
|
||||
|
||||
w->sendMessage(1000,0,0,500);
|
||||
//w->sendMessage(1000,0,0,500);
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
|
@ -75,12 +75,12 @@ public:
|
||||
canvas->fill();
|
||||
mDegrees=0;
|
||||
}
|
||||
bool onMessage(DWORD msg,DWORD wp,ULONG lp)override{
|
||||
/*bool onMessage(DWORD msg,DWORD wp,ULONG lp)override{
|
||||
if(msg==1000){
|
||||
invalidate(nullptr);
|
||||
}
|
||||
return Window::onMessage(msg,wp,lp);
|
||||
}
|
||||
}*/
|
||||
};
|
||||
int main(int argc,const char*argv[]){
|
||||
App app(argc,argv);
|
||||
|
@ -1,26 +0,0 @@
|
||||
#include<netinet/in.h>
|
||||
#include<arpa/inet.h>
|
||||
#include<unistd.h>
|
||||
#include<fcntl.h>
|
||||
#include<sys/stat.h>
|
||||
#include<sys/types.h>
|
||||
#include<sys/socket.h>
|
||||
#include<windows.h>
|
||||
#include<asynsource.h>
|
||||
#include<iostream>
|
||||
|
||||
int main(int argc,const char*argv[]){
|
||||
App app(argc,argv);
|
||||
AsyncEventSource*as=new AsyncEventSource();
|
||||
Looper::getDefault()->add_event_source(as,[](EventSource&){return true;});
|
||||
for(int i=0;i<10;i++){
|
||||
std::future<int> res=as->enqueue([i](int a)->int{
|
||||
usleep((a+500)*1000);
|
||||
std::cout<<i<<" 'sresult:="<<a<<std::endl;
|
||||
return a;
|
||||
},i);
|
||||
//std::cout<<i<<" 'sresult:="<<res.get()<<std::endl;
|
||||
}
|
||||
std::cout<<"before exec"<<std::endl;
|
||||
return app.exec();
|
||||
}
|
10
apps/samples/multiwindow.cc
Normal file → Executable file
10
apps/samples/multiwindow.cc
Normal file → Executable file
@ -12,7 +12,7 @@ public:
|
||||
MWindow(int x,int y,int w,int h):Window(x,y,w,h){dx=dy=50;}
|
||||
virtual bool onMessage(DWORD msgid,DWORD wp,ULONG lp){
|
||||
if(1000==msgid){
|
||||
sendMessage(msgid,wp,lp,lp);
|
||||
//sendMessage(msgid,wp,lp,lp);
|
||||
int x=getX();
|
||||
int y=getY();
|
||||
if(x+getWidth()>1280)dx*=-1;
|
||||
@ -22,7 +22,7 @@ public:
|
||||
setPos(x+dx,y+dy);
|
||||
return true;
|
||||
}
|
||||
return Window::onMessage(msgid,wp,lp);
|
||||
return true;//Window::onMessage(msgid,wp,lp);
|
||||
}
|
||||
void onDraw(Canvas&c)override{
|
||||
srand(time(nullptr)*(long)this);
|
||||
@ -52,9 +52,9 @@ int main(int argc,const char*argv[]){
|
||||
w2->addView(lv2).setId(0);
|
||||
|
||||
if(argc>5){
|
||||
w1->sendMessage(1000,0,2000,100);w1->setDir(50,40);
|
||||
w2->sendMessage(1000,0,1000,80);w2->setDir(66,53);
|
||||
w3->sendMessage(1000,0,200,85);w3->setDir(23,13);
|
||||
//w1->sendMessage(1000,0,2000,100);w1->setDir(50,40);
|
||||
//w2->sendMessage(1000,0,1000,80);w2->setDir(66,53);
|
||||
//w3->sendMessage(1000,0,200,85);w3->setDir(23,13);
|
||||
}
|
||||
return app.exec();
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ private:
|
||||
Spinner*mLevelSelector;
|
||||
Button*mStartButton;
|
||||
protected:
|
||||
bool onMessage(DWORD msgid,DWORD wp,ULONG lp)override;
|
||||
bool onMessage(DWORD msgid,DWORD wp,ULONG lp);
|
||||
void onDraw(Canvas&canvas)override;
|
||||
bool onKeyUp(int keyCode,KeyEvent&event)override;
|
||||
public:
|
||||
@ -241,7 +241,7 @@ void TetrisWindow::ResetBlock(){
|
||||
}
|
||||
|
||||
void TetrisWindow::StartGame(){
|
||||
sendMessage(WM_REFRESH,0,0,speed_ms);
|
||||
//sendMessage(WM_REFRESH,0,0,speed_ms);
|
||||
//产生初始下一个方块
|
||||
int block_id=rand()%7;
|
||||
CreateBlock(next_block,block_id);
|
||||
@ -279,9 +279,9 @@ bool TetrisWindow::onMessage(DWORD msgid,DWORD wp,ULONG lp){
|
||||
if((msgid==WM_REFRESH)&&(!mGameIsOver)){
|
||||
BlockMove(DOWN);
|
||||
invalidate(nullptr);
|
||||
sendMessage(msgid,wp,lp,speed_ms);
|
||||
//sendMessage(msgid,wp,lp,speed_ms);
|
||||
}else
|
||||
return Window::onMessage(msgid,wp,lp);
|
||||
return true;//Window::onMessage(msgid,wp,lp);
|
||||
}
|
||||
|
||||
void TetrisWindow::GameOver(){
|
||||
|
@ -10,7 +10,7 @@ protected:
|
||||
TextView*tv3;
|
||||
public:
|
||||
TestWindow(int w,int h);
|
||||
bool onMessage(DWORD msg,DWORD wp,ULONG lp)override;
|
||||
bool onMessage(DWORD msg,DWORD wp,ULONG lp);
|
||||
};
|
||||
|
||||
TestWindow::TestWindow(int w,int h):Window(0,0,w,h){
|
||||
@ -78,16 +78,16 @@ bool TestWindow::onMessage(DWORD msg,DWORD wp,ULONG lp){
|
||||
if(flag>0){lvl+=200;if(lvl>=10000)flag=-1;}
|
||||
if(flag<0){lvl-=200;if(lvl<=0)flag=1;}
|
||||
tv3->getForeground()->setLevel(lvl);
|
||||
sendMessage(msg,wp,lp,200);
|
||||
//sendMessage(msg,wp,lp,200);
|
||||
}break;
|
||||
default:return Window::onMessage(msg,wp,lp);
|
||||
default:return true;//Window::onMessage(msg,wp,lp);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc,const char*argv[]){
|
||||
App app(argc,argv);
|
||||
Window*w=new TestWindow(1080,720);
|
||||
w->sendMessage(View::WM_TIMER,0,0,500);
|
||||
//w->sendMessage(View::WM_TIMER,0,0,500);
|
||||
app.exec();
|
||||
return 0;
|
||||
}
|
||||
|
6
apps/uidemo/lyrics.cc
Normal file → Executable file
6
apps/uidemo/lyrics.cc
Normal file → Executable file
@ -1,5 +1,5 @@
|
||||
#include <lyrics.h>
|
||||
#include <assets.h>
|
||||
#include <core/assets.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@ -14,8 +14,8 @@ using namespace tag;
|
||||
|
||||
#include <cdtypes.h>
|
||||
#include <cdlog.h>
|
||||
#include <iostreams.h>
|
||||
#include <textutils.h>
|
||||
#include <core/iostreams.h>
|
||||
#include <core/textutils.h>
|
||||
|
||||
|
||||
namespace priv{
|
||||
|
2
apps/uidemo/lyrics.h
Normal file → Executable file
2
apps/uidemo/lyrics.h
Normal file → Executable file
@ -1,6 +1,6 @@
|
||||
#ifndef __ID3_LYRICS__H__
|
||||
#define __ID3_LYRICS__H__
|
||||
#include <canvas.h>
|
||||
#include <core/canvas.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
1
apps/uidemo/lyricsview.cc
Normal file → Executable file
1
apps/uidemo/lyricsview.cc
Normal file → Executable file
@ -1,5 +1,4 @@
|
||||
#include <lyricsview.h>
|
||||
#include <assets.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
1
apps/uidemo/multimedia.cc
Normal file → Executable file
1
apps/uidemo/multimedia.cc
Normal file → Executable file
@ -6,7 +6,6 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <assets.h>
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include <lyricsview.h>
|
||||
|
4
src/3rdparty/libjpeg-turbo/CMakeLists.txt
vendored
Normal file → Executable file
4
src/3rdparty/libjpeg-turbo/CMakeLists.txt
vendored
Normal file → Executable file
@ -40,7 +40,7 @@ message(STATUS "VERSION = ${VERSION}, BUILD = ${BUILD}")
|
||||
|
||||
# Detect CPU type and whether we're building 64-bit or 32-bit code
|
||||
math(EXPR BITS "${CMAKE_SIZEOF_VOID_P} * 8")
|
||||
#string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} CMAKE_SYSTEM_PROCESSOR_LC)
|
||||
string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} CMAKE_SYSTEM_PROCESSOR_LC)
|
||||
if(CMAKE_SYSTEM_PROCESSOR_LC MATCHES "x86_64" OR
|
||||
CMAKE_SYSTEM_PROCESSOR_LC MATCHES "amd64" OR
|
||||
CMAKE_SYSTEM_PROCESSOR_LC MATCHES "i[0-9]86" OR
|
||||
@ -62,6 +62,8 @@ elseif(CMAKE_SYSTEM_PROCESSOR_LC MATCHES "arm*")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR_LC MATCHES "ppc*" OR
|
||||
CMAKE_SYSTEM_PROCESSOR_LC MATCHES "powerpc*")
|
||||
set(CPU_TYPE powerpc)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR_LC MATCHES "mips*")
|
||||
set(CPU_TYPE mipsel)
|
||||
else()
|
||||
set(CPU_TYPE ${CMAKE_SYSTEM_PROCESSOR_LC})
|
||||
endif()
|
||||
|
@ -9,7 +9,6 @@ aux_source_directory(widget SRCS_WIDGET)
|
||||
aux_source_directory(drawables SRCS_DRAWABLES)
|
||||
aux_source_directory(cairomm SRCS_CAIROMM)
|
||||
aux_source_directory(dialogs SRCS_DIALOG)
|
||||
aux_source_directory(looper SRCS_LOOP)
|
||||
aux_source_directory(animation SRCS_ANIMATION)
|
||||
|
||||
message("UI Lua script bindings is ${LUA_BINDINGS} guistatic=${GUI_STATIC}")
|
||||
@ -40,7 +39,7 @@ add_definitions(-DRAPIDJSON_HAS_STDSTRING)
|
||||
set(SOURCES_GUI ${SRCS_GUICORE} ${SRCS_VIEWS}
|
||||
${SRCS_WIDGET} ${SRCS_DRAWABLES}
|
||||
${SRCS_CAIROMM} ${SRCS_DIALOG}
|
||||
${SRCS_LOOP} ${SRCS_ANIMATION})
|
||||
${SRCS_ANIMATION})
|
||||
|
||||
add_library(gui_objs OBJECT ${SOURCES_GUI})
|
||||
add_library(gui_static STATIC $<TARGET_OBJECTS:gui_objs>)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#ifndef __ANIMATION_H__
|
||||
#define __ANIMATION_H__
|
||||
#include <context.h>
|
||||
#include <core/context.h>
|
||||
|
||||
#include <animation/transformation.h>
|
||||
|
||||
|
@ -96,6 +96,7 @@ void Animator::appendChangingConfigurations(int configs) {
|
||||
|
||||
void Animator::setupStartValues() {
|
||||
}
|
||||
|
||||
void Animator::setupEndValues() {
|
||||
}
|
||||
|
||||
@ -137,4 +138,5 @@ AnimatorListenerAdapter::AnimatorListenerAdapter(){
|
||||
onAnimationCancel=onAnimationRepeat=onAnimationPause=onAnimationResume=[](Animator&anim){};
|
||||
onAnimationEnd=onAnimationStart=[](Animator&aim,bool reverse){};
|
||||
}
|
||||
|
||||
}//endof namespace
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <interpolators.h>
|
||||
#include <animation/interpolators.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
|
2
src/gui/core/interpolators.cc → src/gui/animation/interpolators.cc
Normal file → Executable file
2
src/gui/core/interpolators.cc → src/gui/animation/interpolators.cc
Normal file → Executable file
@ -1,4 +1,4 @@
|
||||
#include <interpolators.h>
|
||||
#include <animation/interpolators.h>
|
||||
|
||||
namespace cdroid{
|
||||
#if 0
|
0
src/gui/core/interpolators.h → src/gui/animation/interpolators.h
Normal file → Executable file
0
src/gui/core/interpolators.h → src/gui/animation/interpolators.h
Normal file → Executable file
@ -3,7 +3,6 @@
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <widget/viewgroup.h>
|
||||
#include <interpolators.h>
|
||||
#include <animation/animator.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef __SCALEANIMATION_H__
|
||||
#define __SCALEANIMATION_H__
|
||||
#include <animation/animation.h>
|
||||
#include <typedvalue.h>
|
||||
#include <core/typedvalue.h>
|
||||
|
||||
namespace cdroid{
|
||||
class ScaleAnimation:public Animation{
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef __TRANSFORMATION_H__
|
||||
#define __TRANSFORMATION_H__
|
||||
#include <rect.h>
|
||||
#include <core/rect.h>
|
||||
#include <cairomm/matrix.h>
|
||||
#include <interpolators.h>
|
||||
#include <attributeset.h>
|
||||
#include <animation/interpolators.h>
|
||||
#include <core/attributeset.h>
|
||||
|
||||
typedef Cairo::Matrix Matrix;
|
||||
namespace cdroid{
|
||||
|
@ -1,57 +0,0 @@
|
||||
#include <alooper.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <cdtypes.h>
|
||||
#include <cdlog.h>
|
||||
#include <limits.h>
|
||||
|
||||
namespace alooper{
|
||||
|
||||
static constexpr int EPOLL_SIZE_HINT = 8;
|
||||
// Maximum number of file descriptors for which to retrieve poll events each iteration.
|
||||
static constexpr int EPOLL_MAX_EVENTS = 16;
|
||||
|
||||
void Looper::Looper::Request::initEventItem(struct epoll_event* eventItem) const{
|
||||
}
|
||||
|
||||
Looper::Looper(bool allowNonCallbacks) :
|
||||
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
|
||||
mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
|
||||
mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LONG_MAX) {
|
||||
//mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
//LOGE_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",strerror(errno));
|
||||
//AutoMutex _l(mLock);
|
||||
rebuildEpollLocked();
|
||||
}
|
||||
|
||||
void Looper::rebuildEpollLocked() {
|
||||
// Close old epoll instance if we have one.
|
||||
if (mEpollFd >= 0) {
|
||||
LOGV("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
|
||||
close(mEpollFd);
|
||||
}
|
||||
|
||||
// Allocate the new epoll instance and register the wake pipe.
|
||||
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
|
||||
LOGE_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
|
||||
|
||||
struct epoll_event eventItem;
|
||||
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
|
||||
eventItem.events = EPOLLIN;
|
||||
eventItem.data.fd = mWakeEventFd;
|
||||
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
|
||||
LOGE_IF(result != 0, "Could not add wake event fd to epoll instance: %s",strerror(errno));
|
||||
|
||||
for (auto it=mRequests.begin();it!=mRequests.end(); it++) {
|
||||
const Request& request = it->second;
|
||||
struct epoll_event eventItem;
|
||||
request.initEventItem(&eventItem);
|
||||
|
||||
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
|
||||
if (epollResult < 0) {
|
||||
LOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",request.fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@
|
||||
#include <cdinput.h>
|
||||
#include <inputeventsource.h>
|
||||
#include <uieventsource.h>
|
||||
#include <looper/GenericSignalSource.h>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
@ -76,13 +75,10 @@ App::App(int argc,const char*argv[],const struct option*extoptions){
|
||||
|
||||
setOpacity(getArgAsInt("alpha",255));
|
||||
InputEventSource*inputsource=new InputEventSource(getArg("record",""));
|
||||
addEventSource(inputsource,[](EventSource&s){
|
||||
((InputEventSource&)s).processKey();
|
||||
return true;
|
||||
});
|
||||
addEventHandler(inputsource);
|
||||
inputsource->playback(getArg("monkey",""));
|
||||
|
||||
SignalSource*sigsource=new GenericSignalSource(false);
|
||||
/*SignalSource*sigsource=new GenericSignalSource(false);
|
||||
addEventSource(sigsource,[this](EventSource&s){
|
||||
LOGI("Sig interrupt %d",((SignalSource&)s).signo);
|
||||
this->exit(((SignalSource&)s).signo);
|
||||
@ -91,7 +87,7 @@ App::App(int argc,const char*argv[],const struct option*extoptions){
|
||||
sigsource->add(SIGABRT);
|
||||
sigsource->add(SIGINT);
|
||||
sigsource->add(SIGTERM);
|
||||
sigsource->add(SIGKILL);
|
||||
sigsource->add(SIGKILL);*/
|
||||
}
|
||||
|
||||
App::~App(){
|
||||
@ -157,20 +153,20 @@ const std::string App::getAssetsPath(){
|
||||
return path;
|
||||
}
|
||||
|
||||
int App::addEventSource(EventSource *source, EventHandler handler){
|
||||
return Looper::getDefault()->add_event_source(source,handler);
|
||||
void App::addEventHandler(const EventHandler*handler){
|
||||
Looper::getDefault()->addEventHandler(handler);
|
||||
}
|
||||
|
||||
int App::removeEventSource(EventSource*source){
|
||||
return Looper::getDefault()->remove_event_source(source);
|
||||
void App::removeEventHandler(const EventHandler*handler){
|
||||
//Looper::getDefault()->remove_event_source(source);
|
||||
}
|
||||
|
||||
int App::exec(){
|
||||
return Looper::getDefault()->run();
|
||||
while(1)Looper::getDefault()->pollAll(5);
|
||||
}
|
||||
|
||||
void App::exit(int code){
|
||||
Looper::getDefault()->quit(code);
|
||||
//Looper::getDefault()->quit(code);
|
||||
}
|
||||
|
||||
void App::setName(const std::string&appname){
|
||||
|
10
src/gui/core/app.h
Normal file → Executable file
10
src/gui/core/app.h
Normal file → Executable file
@ -4,9 +4,9 @@
|
||||
#include <map>
|
||||
#include <istream>
|
||||
#include <cairomm/surface.h>
|
||||
#include <looper/looper.h>
|
||||
#include <context.h>
|
||||
#include <assets.h>
|
||||
#include <core/looper.h>
|
||||
#include <core/context.h>
|
||||
#include <core/assets.h>
|
||||
struct option;
|
||||
using namespace Cairo;
|
||||
|
||||
@ -32,8 +32,8 @@ public:
|
||||
virtual const std::string&getArg(const std::string&key,const std::string&def="")const;
|
||||
|
||||
virtual int getArgAsInt(const std::string&key,int def)const;
|
||||
virtual int addEventSource(EventSource *source, EventHandler handler);
|
||||
virtual int removeEventSource(EventSource*source);
|
||||
virtual void addEventHandler(const EventHandler* handler);
|
||||
virtual void removeEventHandler(const EventHandler*handler);
|
||||
virtual int exec();
|
||||
virtual void exit(int code=0);
|
||||
};
|
||||
|
1
src/gui/core/assets.h
Normal file → Executable file
1
src/gui/core/assets.h
Normal file → Executable file
@ -1,6 +1,5 @@
|
||||
#ifndef __ASSETS_H__
|
||||
#define __ASSETS_H__
|
||||
#include <context.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -1,73 +0,0 @@
|
||||
#include <asynsource.h>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <functional>
|
||||
|
||||
namespace cdroid {
|
||||
|
||||
AsyncEventSource::AsyncEventSource(){
|
||||
int threads=std::thread::hardware_concurrency();
|
||||
for(size_t i = 0; i<threads; ++i)
|
||||
workers.emplace_back(
|
||||
[this] {
|
||||
for(;;) {
|
||||
std::function<void()> task;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||
this->condition.wait(lock,
|
||||
[this] { return this->stop || !this->tasks.empty(); });
|
||||
if(this->stop && this->tasks.empty())
|
||||
return;
|
||||
task = std::move(this->tasks.front());
|
||||
this->tasks.pop();
|
||||
}
|
||||
task();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
AsyncEventSource::~AsyncEventSource() {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
stop = true;
|
||||
}
|
||||
condition.notify_all();
|
||||
for(std::thread &worker: workers)
|
||||
worker.join();
|
||||
}
|
||||
|
||||
bool AsyncEventSource::prepare(int& max_timeout) {
|
||||
return tasks.size();
|
||||
}
|
||||
|
||||
bool AsyncEventSource::check(){
|
||||
return tasks.size()>0;
|
||||
}
|
||||
#if 0
|
||||
template<class F, class... Args>
|
||||
auto AsyncEventSource::enqueue(F&& f, Args&&... args)-> std::future<typename std::result_of<F(Args...)>::type>{
|
||||
using return_type = typename std::result_of<F(Args...)>::type;
|
||||
auto task = std::make_shared< std::packaged_task<return_type()> >(
|
||||
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
|
||||
);
|
||||
std::future<return_type> res = task->get_future();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
if(stop)// don't allow enqueueing after stopping the pool
|
||||
throw std::runtime_error("enqueue on stopped ThreadPool");
|
||||
tasks.emplace([task]() {
|
||||
(*task)();
|
||||
});
|
||||
}
|
||||
condition.notify_one();
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
bool AsyncEventSource::dispatch(EventHandler &func) { return func(*this); }
|
||||
|
||||
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
#ifndef __ASYNC_SOURCE_H__
|
||||
#define __ASYNC_SOURCE_H__
|
||||
#include <cdinput.h>
|
||||
#include <looper/looper.h>
|
||||
#include <widget/view.h>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
namespace cdroid{
|
||||
|
||||
DECLARE_UIEVENT(void,AsyncEvent,void);
|
||||
|
||||
//template<class F, class... Args>
|
||||
class AsyncEventSource:public EventSource{
|
||||
protected:
|
||||
std::vector< std::thread > workers;
|
||||
// the task queue
|
||||
std::queue< std::function<void()> > tasks;
|
||||
// synchronization
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable condition;
|
||||
bool stop;
|
||||
public:
|
||||
AsyncEventSource();
|
||||
~AsyncEventSource();
|
||||
bool prepare(int& max_timeout);
|
||||
bool check();
|
||||
bool dispatch(EventHandler &func);
|
||||
bool is_file_source() const override final { return false; }
|
||||
template<class F, class... Args>
|
||||
auto enqueue(F&& f, Args&&... args)-> std::future<typename std::result_of<F(Args...)>::type>{
|
||||
using return_type = typename std::result_of<F(Args...)>::type;
|
||||
auto task = std::make_shared< std::packaged_task<return_type()> >(
|
||||
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
|
||||
);
|
||||
std::future<return_type> res = task->get_future();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
if(stop)// don't allow enqueueing after stopping the pool
|
||||
throw std::runtime_error("enqueue on stopped ThreadPool");
|
||||
tasks.emplace([task]() {
|
||||
(*task)();
|
||||
});
|
||||
}
|
||||
condition.notify_one();
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
@ -4,7 +4,7 @@
|
||||
#include <cdgraph.h>
|
||||
#include <cairomm/context.h>
|
||||
#include <cairomm/region.h>
|
||||
#include <graph_device.h>
|
||||
#include <core/graph_device.h>
|
||||
#include <gui/gui_features.h>
|
||||
using namespace Cairo;
|
||||
|
||||
|
@ -85,7 +85,7 @@ namespace cdroid{
|
||||
CallbackRecord* predecessor = nullptr;
|
||||
for (CallbackRecord* callback = mHead; callback != nullptr;) {
|
||||
CallbackRecord* next = callback->next;
|
||||
if ((action == nullptr || addr_of(callback->action) == addr_of(action))
|
||||
if ((/*action == nullptr ||*/ callback->action.ID == action.ID)
|
||||
&& (token == 0 || callback->token == token)) {
|
||||
if (predecessor != nullptr) {
|
||||
predecessor->next = next;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#ifndef __CHOREO_GRAPHER_H__
|
||||
#define __CHOREO_GRAPHER_H__
|
||||
#include <looper/looper.h>
|
||||
#include <core/looper.h>
|
||||
#include <drawables/drawable.h>
|
||||
namespace cdroid{
|
||||
class Choreographer{
|
||||
|
@ -9,7 +9,35 @@
|
||||
using namespace Cairo;
|
||||
|
||||
namespace cdroid{
|
||||
typedef std::function<void()>Runnable;
|
||||
class Runnable{
|
||||
public:
|
||||
int ID;
|
||||
std::function<void()>run;
|
||||
Runnable(){
|
||||
run=nullptr;
|
||||
}
|
||||
Runnable(const std::function<void()>&f){
|
||||
run=f;
|
||||
}
|
||||
void operator=(const std::function<void()>&f){
|
||||
run=f;
|
||||
}
|
||||
void operator=(nullptr_t){
|
||||
run=nullptr;
|
||||
}
|
||||
bool operator==(nullptr_t)const{
|
||||
return run==nullptr;
|
||||
}
|
||||
bool operator!=(nullptr_t)const{
|
||||
return run!=nullptr;
|
||||
}
|
||||
explicit operator bool()const{
|
||||
return run!=nullptr;
|
||||
}
|
||||
void operator()(){
|
||||
run();
|
||||
}
|
||||
};
|
||||
class Drawable;
|
||||
class ColorStateList;
|
||||
class Context{
|
||||
|
2
src/gui/core/eventcodes.h
Normal file → Executable file
2
src/gui/core/eventcodes.h
Normal file → Executable file
@ -14,7 +14,7 @@
|
||||
*/
|
||||
#ifndef _INPUT_EVENT_CODES_H
|
||||
#define _INPUT_EVENT_CODES_H
|
||||
#include <keycodes.h>
|
||||
#include <core/keycodes.h>
|
||||
/*
|
||||
* Device properties and quirks
|
||||
*/
|
||||
|
2
src/gui/core/graph_device.h
Normal file → Executable file
2
src/gui/core/graph_device.h
Normal file → Executable file
@ -1,6 +1,6 @@
|
||||
#ifndef __GRAPH_DEVICE_H__
|
||||
#define __GRAPH_DEVICE_H__
|
||||
#include <rect.h>
|
||||
#include <core/rect.h>
|
||||
#include <cairomm/context.h>
|
||||
#include <map>
|
||||
|
||||
|
2
src/gui/core/gravity.h
Normal file → Executable file
2
src/gui/core/gravity.h
Normal file → Executable file
@ -1,6 +1,6 @@
|
||||
#ifndef __GRAVITY_H__
|
||||
#define __GRAVITY_H__
|
||||
#include <rect.h>
|
||||
#include <core/rect.h>
|
||||
#include <string>
|
||||
|
||||
namespace cdroid{
|
||||
|
2
src/gui/core/inputeventlabels.h
Normal file → Executable file
2
src/gui/core/inputeventlabels.h
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
#ifndef __INPUT_EVENT_LABE_H__
|
||||
#define __INPUT_EVENT_LABE_H__
|
||||
//#include <input.h>
|
||||
#include <keycodes.h>
|
||||
#include <core/keycodes.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#define DEFINE_KEYCODE(key) { #key, KEY_##key }
|
||||
|
@ -69,29 +69,15 @@ std::shared_ptr<InputDevice>InputEventSource::getdevice(int fd){
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
bool InputEventSource::prepare(int& max_timeout){
|
||||
int InputEventSource::checkEvents(){
|
||||
INPUTEVENT es[32];
|
||||
if(events.size()>0)return TRUE;
|
||||
int count=InputGetEvents(es,32,1);
|
||||
process(es,count);
|
||||
return count>0;
|
||||
return count;
|
||||
}
|
||||
|
||||
int InputEventSource::process(const INPUTEVENT*inevents,int count){
|
||||
LOGV_IF(count,"%p recv %d events ",this,count);
|
||||
for(int i=0;i<count;i++){
|
||||
const INPUTEVENT*e=inevents+i;
|
||||
std::shared_ptr<InputDevice>dev=getdevice(e->device);
|
||||
if(dev==nullptr){
|
||||
LOGD("%d,%d,%d device=%d ",e->type,e->code,e->value,e->device);
|
||||
continue;
|
||||
}
|
||||
dev->putrawdata(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool InputEventSource::processKey(){
|
||||
int InputEventSource::handleEvents(){
|
||||
std::lock_guard<std::mutex> lock(mtxEvents);
|
||||
if(events.size()==0)return false;
|
||||
while(events.size()){
|
||||
@ -109,8 +95,23 @@ bool InputEventSource::processKey(){
|
||||
e->recycle();
|
||||
events.pop();
|
||||
}
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int InputEventSource::process(const INPUTEVENT*inevents,int count){
|
||||
LOGV_IF(count,"%p recv %d events ",this,count);
|
||||
for(int i=0;i<count;i++){
|
||||
const INPUTEVENT*e=inevents+i;
|
||||
std::shared_ptr<InputDevice>dev=getdevice(e->device);
|
||||
if(dev==nullptr){
|
||||
LOGD("%d,%d,%d device=%d ",e->type,e->code,e->value,e->device);
|
||||
continue;
|
||||
}
|
||||
dev->putrawdata(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int InputEventSource::pushEvent(InputEvent*evt){
|
||||
std::lock_guard<std::mutex> lock(mtxEvents);
|
||||
events.push(evt);
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef __INPUT_EVENT_SOURCE_H__
|
||||
#define __INPUT_EVENT_SOURCE_H__
|
||||
#include <cdinput.h>
|
||||
#include <looper/looper.h>
|
||||
#include <core/looper.h>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
@ -18,7 +18,7 @@ namespace GRT{
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
class InputEventSource:public EventSource{
|
||||
class InputEventSource:public EventHandler{
|
||||
protected:
|
||||
std::mutex mtxEvents;
|
||||
bool isplayback;
|
||||
@ -36,12 +36,9 @@ public:
|
||||
~InputEventSource();
|
||||
bool initGesture(const std::string&fname);
|
||||
void playback(const std::string&fname);
|
||||
bool prepare(int& max_timeout);
|
||||
bool check(){return events.size()>0;}
|
||||
bool dispatch(EventHandler &func) { return func(*this); }
|
||||
bool is_file_source() const override final { return false; }
|
||||
int checkEvents()override;
|
||||
int handleEvents()override;
|
||||
int process(const INPUTEVENT*es,int count);
|
||||
bool processKey();
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
2
src/gui/core/layout.h
Normal file → Executable file
2
src/gui/core/layout.h
Normal file → Executable file
@ -1,6 +1,6 @@
|
||||
#ifndef __LAYOUT_H__
|
||||
#define __LAYOUT_H__
|
||||
#include <canvas.h>
|
||||
#include <core/canvas.h>
|
||||
namespace cdroid{
|
||||
class Layout{
|
||||
private:
|
||||
|
582
src/gui/core/looper.cc
Executable file
582
src/gui/core/looper.cc
Executable file
@ -0,0 +1,582 @@
|
||||
#include <looper.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <cdtypes.h>
|
||||
#include <cdlog.h>
|
||||
#include <limits.h>
|
||||
#include <systemclock.h>
|
||||
|
||||
#define DEBUG_POLL_AND_WAKE 0
|
||||
#define DEBUG_CALLBACKS 0
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
static constexpr int EPOLL_SIZE_HINT = 8;
|
||||
// Maximum number of file descriptors for which to retrieve poll events each iteration.
|
||||
static constexpr int EPOLL_MAX_EVENTS = 16;
|
||||
#define toMillisecondTimeoutDelay(n,p) ((n)-(p))
|
||||
|
||||
template<class T>
|
||||
static const void * addr_of(T &&obj) noexcept{
|
||||
struct A {};
|
||||
return &reinterpret_cast<const A &>(obj);
|
||||
}
|
||||
|
||||
void Looper::Looper::Request::initEventItem(struct epoll_event* eventItem) const{
|
||||
int epollEvents = 0;
|
||||
if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
|
||||
if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;
|
||||
|
||||
memset(eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
|
||||
eventItem->events = epollEvents;
|
||||
eventItem->data.fd = fd;
|
||||
}
|
||||
|
||||
Looper::Looper(bool allowNonCallbacks) :
|
||||
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
|
||||
mPolling(false), mEpollFd(-1), mEpollRebuildRequired(false),
|
||||
mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LONG_MAX) {
|
||||
mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
LOGE_IF(mWakeEventFd < 0, "Could not make wake event fd: %s",strerror(errno));
|
||||
std::lock_guard<std::mutex>_l(mLock);
|
||||
rebuildEpollLocked();
|
||||
}
|
||||
|
||||
Looper::~Looper() {
|
||||
close(mWakeEventFd);
|
||||
mWakeEventFd = -1;
|
||||
if (mEpollFd >= 0) {
|
||||
close(mEpollFd);
|
||||
}
|
||||
}
|
||||
Looper*Looper::mInst=nullptr;
|
||||
Looper*Looper::getDefault(){
|
||||
if(mInst==nullptr)mInst=new Looper(false);
|
||||
return mInst;
|
||||
}
|
||||
|
||||
bool Looper::getAllowNonCallbacks() const {
|
||||
return mAllowNonCallbacks;
|
||||
}
|
||||
|
||||
void Looper::rebuildEpollLocked() {
|
||||
// Close old epoll instance if we have one.
|
||||
if (mEpollFd >= 0) {
|
||||
LOGV("%p ~ rebuildEpollLocked - rebuilding epoll set", this);
|
||||
close(mEpollFd);
|
||||
}
|
||||
|
||||
// Allocate the new epoll instance and register the wake pipe.
|
||||
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
|
||||
LOGE_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
|
||||
|
||||
struct epoll_event eventItem;
|
||||
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
|
||||
eventItem.events = EPOLLIN;
|
||||
eventItem.data.fd = mWakeEventFd;
|
||||
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
|
||||
LOGE_IF(result != 0, "Could not add wake event fd to epoll instance: %s",strerror(errno));
|
||||
|
||||
for (auto it=mRequests.begin();it!=mRequests.end(); it++) {
|
||||
const Request& request = it->second;
|
||||
struct epoll_event eventItem;
|
||||
request.initEventItem(&eventItem);
|
||||
|
||||
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, request.fd, & eventItem);
|
||||
if (epollResult < 0) {
|
||||
LOGE("Error adding epoll events for fd %d while rebuilding epoll set: %s",request.fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Looper::scheduleEpollRebuildLocked() {
|
||||
if (!mEpollRebuildRequired) {
|
||||
LOGD_IF(DEBUG_CALLBACKS,"%p scheduleEpollRebuildLocked - scheduling epoll set rebuild", this);
|
||||
mEpollRebuildRequired = true;
|
||||
wake();
|
||||
}
|
||||
}
|
||||
|
||||
int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
|
||||
int result = 0;
|
||||
for (;;) {
|
||||
while (mResponseIndex < mResponses.size()) {
|
||||
const Response& response = mResponses.at(mResponseIndex++);
|
||||
int ident = response.request.ident;
|
||||
if (ident >= 0) {
|
||||
int fd = response.request.fd;
|
||||
int events = response.events;
|
||||
void* data = response.request.data;
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE,"%p pollOnce - returning signalled identifier %d: fd=%d, events=0x%x, data=%p", this, ident, fd, events, data);
|
||||
if (outFd != NULL) *outFd = fd;
|
||||
if (outEvents != NULL) *outEvents = events;
|
||||
if (outData != NULL) *outData = data;
|
||||
return ident;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE,"%p pollOnce - returning result %d", this, result);
|
||||
if (outFd != NULL) *outFd = 0;
|
||||
if (outEvents != NULL) *outEvents = 0;
|
||||
if (outData != NULL) *outData = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
result = pollInner(timeoutMillis);
|
||||
}
|
||||
}
|
||||
|
||||
int Looper::pollInner(int timeoutMillis) {
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE,"%p pollOnce - waiting: timeoutMillis=%d mNextMessageUptime=%lld", this, timeoutMillis,mNextMessageUptime);
|
||||
|
||||
// Adjust the timeout based on when the next message is due.
|
||||
if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
|
||||
nsecs_t now = SystemClock::uptimeMillis();//systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
|
||||
if (messageTimeoutMillis >= 0
|
||||
&& (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
|
||||
timeoutMillis = messageTimeoutMillis;
|
||||
}
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE,"%p pollOnce - next message in %lld ns, adjusted timeout: timeoutMillis=%d",this, mNextMessageUptime - now, timeoutMillis);
|
||||
}
|
||||
|
||||
// Poll.
|
||||
int result = POLL_WAKE;
|
||||
mResponses.clear();
|
||||
mResponseIndex = 0;
|
||||
|
||||
for(auto it=mEventHandlers.begin();it!=mEventHandlers.end();it++){
|
||||
EventHandler*es=(*it);
|
||||
if(es&&(es->mRemoved==0)&&(es->checkEvents()>0)){
|
||||
es->handleEvents();
|
||||
}
|
||||
}
|
||||
removeEventHandlers();
|
||||
// We are about to idle.
|
||||
mPolling = true;
|
||||
|
||||
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
|
||||
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
|
||||
|
||||
// No longer idling.
|
||||
mPolling = false;
|
||||
|
||||
// Acquire lock.
|
||||
mLock.lock();
|
||||
|
||||
// Rebuild epoll set if needed.
|
||||
if (mEpollRebuildRequired) {
|
||||
mEpollRebuildRequired = false;
|
||||
rebuildEpollLocked();
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// Check for poll error.
|
||||
if (eventCount < 0) {
|
||||
if (errno == EINTR) {
|
||||
goto Done;
|
||||
}
|
||||
LOGW("Poll failed with an unexpected error: %s", strerror(errno));
|
||||
result = POLL_ERROR;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// Check for poll timeout.
|
||||
if (eventCount == 0) {
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE,"%p pollOnce - timeout", this);
|
||||
result = POLL_TIMEOUT;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// Handle all events.
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE,"%p pollOnce - handling events from %d fds", this, eventCount);
|
||||
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
int fd = eventItems[i].data.fd;
|
||||
uint32_t epollEvents = eventItems[i].events;
|
||||
if (fd == mWakeEventFd) {
|
||||
if (epollEvents & EPOLLIN) {
|
||||
awoken();
|
||||
} else {
|
||||
LOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
|
||||
}
|
||||
} else {
|
||||
auto it= mRequests.find(fd);//indexOfKey(fd);
|
||||
if (it!=mRequests.end()){//requestIndex >= 0) {
|
||||
int events = 0;
|
||||
if (epollEvents & EPOLLIN) events |= EVENT_INPUT;
|
||||
if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;
|
||||
if (epollEvents & EPOLLERR) events |= EVENT_ERROR;
|
||||
if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;
|
||||
pushResponse(events, it->second);//mRequests.at(requestIndex));
|
||||
} else {
|
||||
LOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
|
||||
"no longer registered.", epollEvents, fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
Done: ;
|
||||
|
||||
// Invoke pending message callbacks.
|
||||
mNextMessageUptime = LLONG_MAX;
|
||||
LOGD_IF(DEBUG_CALLBACKS,"mMessageEnvelopes.size=%d",mMessageEnvelopes.size());
|
||||
while (mMessageEnvelopes.size() != 0) {
|
||||
nsecs_t now = SystemClock::uptimeMillis();//systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
const MessageEnvelope& messageEnvelope = mMessageEnvelopes.front();
|
||||
if (messageEnvelope.uptime <= now) {
|
||||
// Remove the envelope from the list.
|
||||
// We keep a strong reference to the handler until the call to handleMessage
|
||||
// finishes. Then we drop it so that the handler can be deleted *before*
|
||||
// we reacquire our lock.
|
||||
{ // obtain handler
|
||||
MessageHandler* handler = messageEnvelope.handler;
|
||||
Message message = messageEnvelope.message;
|
||||
mMessageEnvelopes.erase(mMessageEnvelopes.begin());//removeAt(0);
|
||||
mSendingMessage = true;
|
||||
mLock.unlock();
|
||||
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS,"%p pollOnce - sending message: handler=%p, what=%d", this, handler, message.what);
|
||||
handler->handleMessage(message);
|
||||
} // release handler
|
||||
|
||||
mLock.lock();
|
||||
mSendingMessage = false;
|
||||
result = POLL_CALLBACK;
|
||||
} else {
|
||||
// The last message left at the head of the queue determines the next wakeup time.
|
||||
mNextMessageUptime = messageEnvelope.uptime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Release lock.
|
||||
mLock.unlock();
|
||||
|
||||
// Invoke all response callbacks.
|
||||
for (size_t i = 0; i < mResponses.size(); i++) {
|
||||
Response& response = mResponses.at(i);
|
||||
if (response.request.ident == POLL_CALLBACK) {
|
||||
int fd = response.request.fd;
|
||||
int events = response.events;
|
||||
void* data = response.request.data;
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS,"%p pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
|
||||
this, response.request.callback, fd, events, data);
|
||||
|
||||
// Invoke the callback. Note that the file descriptor may be closed by
|
||||
// the callback (and potentially even reused) before the function returns so
|
||||
// we need to be a little careful when removing the file descriptor afterwards.
|
||||
int callbackResult = response.request.callback->handleEvent(fd, events, data);
|
||||
if (callbackResult == 0) {
|
||||
removeFd(fd, response.request.seq);
|
||||
}
|
||||
|
||||
// Clear the callback reference in the response structure promptly because we
|
||||
// will not clear the response vector itself until the next poll.
|
||||
//response.request.callback.clear();
|
||||
result = POLL_CALLBACK;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
|
||||
if (timeoutMillis <= 0) {
|
||||
int result;
|
||||
do {
|
||||
result = pollOnce(timeoutMillis, outFd, outEvents, outData);
|
||||
} while (result == POLL_CALLBACK);
|
||||
return result;
|
||||
} else {
|
||||
nsecs_t endTime =SystemClock::uptimeMillis()+timeoutMillis;// systemTime(SYSTEM_TIME_MONOTONIC) + milliseconds_to_nanoseconds(timeoutMillis);
|
||||
|
||||
for (;;) {
|
||||
int result = pollOnce(timeoutMillis, outFd, outEvents, outData);
|
||||
if (result != POLL_CALLBACK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
nsecs_t now = SystemClock::uptimeMillis();//systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
timeoutMillis = toMillisecondTimeoutDelay(now, endTime);
|
||||
if (timeoutMillis == 0) {
|
||||
return POLL_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//TEMP_FAILURE_RETRY defined in <unistd.h>
|
||||
void Looper::wake() {
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE,"%p wake", this);
|
||||
|
||||
uint64_t inc = 1;
|
||||
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
|
||||
if (nWrite != sizeof(uint64_t)) {
|
||||
LOGE_IF(errno!=EAGAIN,"Could not write wake signal to fd %d: %s",mWakeEventFd, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void Looper::awoken() {
|
||||
LOGD_IF(DEBUG_POLL_AND_WAKE,"%p awoken", this);
|
||||
|
||||
uint64_t counter;
|
||||
TEMP_FAILURE_RETRY(read(mWakeEventFd, &counter, sizeof(uint64_t)));
|
||||
}
|
||||
|
||||
void Looper::pushResponse(int events, const Request& request) {
|
||||
Response response;
|
||||
response.events = events;
|
||||
response.request = request;
|
||||
mResponses.push_back(response);
|
||||
}
|
||||
|
||||
int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
|
||||
return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
|
||||
}
|
||||
|
||||
int Looper::addFd(int fd, int ident, int events,const LooperCallback* callback, void* data) {
|
||||
LOGD_IF(DEBUG_CALLBACKS,"%p addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident, events, callback, data);
|
||||
|
||||
if (callback==nullptr) {
|
||||
if (! mAllowNonCallbacks) {
|
||||
LOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ident < 0) {
|
||||
LOGE("Invalid attempt to set NULL callback with ident < 0.");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
ident = POLL_CALLBACK;
|
||||
}
|
||||
|
||||
{ // acquire lock
|
||||
std::lock_guard<std::mutex> _l(mLock);
|
||||
|
||||
Request request;
|
||||
request.fd = fd;
|
||||
request.ident = ident;
|
||||
request.events = events;
|
||||
request.seq = mNextRequestSeq++;
|
||||
request.callback = (LooperCallback*)callback;
|
||||
request.data = data;
|
||||
if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1
|
||||
|
||||
struct epoll_event eventItem;
|
||||
request.initEventItem(&eventItem);
|
||||
|
||||
auto itfd = mRequests.find(fd);//indexOfKey(fd);
|
||||
if (itfd==mRequests.end()) {
|
||||
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
|
||||
if (epollResult < 0) {
|
||||
LOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
mRequests[fd]=request;//.add(fd, request);
|
||||
} else {
|
||||
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
|
||||
if (epollResult < 0) {
|
||||
if (errno == ENOENT) {
|
||||
// Tolerate ENOENT because it means that an older file descriptor was
|
||||
// closed before its callback was unregistered and meanwhile a new
|
||||
// file descriptor with the same number has been created and is now
|
||||
// being registered for the first time. This error may occur naturally
|
||||
// when a callback has the side-effect of closing the file descriptor
|
||||
// before returning and unregistering itself. Callback sequence number
|
||||
// checks further ensure that the race is benign.
|
||||
//
|
||||
// Unfortunately due to kernel limitations we need to rebuild the epoll
|
||||
// set from scratch because it may contain an old file handle that we are
|
||||
// now unable to remove since its file descriptor is no longer valid.
|
||||
// No such problem would have occurred if we were using the poll system
|
||||
// call instead, but that approach carries others disadvantages.
|
||||
LOGD_IF(DEBUG_CALLBACKS,"%p addFd - EPOLL_CTL_MOD failed due to file descriptor "
|
||||
"being recycled, falling back on EPOLL_CTL_ADD: %s", this, strerror(errno));
|
||||
epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
|
||||
if (epollResult < 0) {
|
||||
LOGE("Error modifying or adding epoll events for fd %d: %s", fd, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
scheduleEpollRebuildLocked();
|
||||
} else {
|
||||
LOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
itfd->second=request;//mRequests.replaceValueAt(requestIndex, request);
|
||||
}
|
||||
} // release lock
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Looper::removeFd(int fd) {
|
||||
return removeFd(fd, -1);
|
||||
}
|
||||
|
||||
int Looper::removeFd(int fd, int seq) {
|
||||
LOGD_IF(DEBUG_CALLBACKS,"%p removeFd - fd=%d, seq=%d", this, fd, seq);
|
||||
|
||||
{ // acquire lock
|
||||
std::lock_guard<std::mutex> _l(mLock);
|
||||
auto itr= mRequests.find(fd);//indexOfKey(fd);
|
||||
if (itr==mRequests.end()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check the sequence number if one was given.
|
||||
if (seq != -1 && itr->second.seq != seq) {
|
||||
LOGD_IF(DEBUG_CALLBACKS,"%p removeFd - sequence number mismatch, oldSeq=%d", this, itr->second.seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Always remove the FD from the request map even if an error occurs while
|
||||
// updating the epoll set so that we avoid accidentally leaking callbacks.
|
||||
mRequests.erase(itr);//removeItemsAt(requestIndex);
|
||||
|
||||
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
|
||||
if (epollResult < 0) {
|
||||
if (seq != -1 && (errno == EBADF || errno == ENOENT)) {
|
||||
// Tolerate EBADF or ENOENT when the sequence number is known because it
|
||||
// means that the file descriptor was closed before its callback was
|
||||
// unregistered. This error may occur naturally when a callback has the
|
||||
// side-effect of closing the file descriptor before returning and
|
||||
// unregistering itself.
|
||||
//
|
||||
// Unfortunately due to kernel limitations we need to rebuild the epoll
|
||||
// set from scratch because it may contain an old file handle that we are
|
||||
// now unable to remove since its file descriptor is no longer valid.
|
||||
// No such problem would have occurred if we were using the poll system
|
||||
// call instead, but that approach carries others disadvantages.
|
||||
LOGD_IF(DEBUG_CALLBACKS,"%p removeFd - EPOLL_CTL_DEL failed due to file descriptor "
|
||||
"being closed: %s", this, strerror(errno));
|
||||
scheduleEpollRebuildLocked();
|
||||
} else {
|
||||
// Some other error occurred. This is really weird because it means
|
||||
// our list of callbacks got out of sync with the epoll set somehow.
|
||||
// We defensively rebuild the epoll set to avoid getting spurious
|
||||
// notifications with nowhere to go.
|
||||
LOGE("Error removing epoll events for fd %d: %s", fd, strerror(errno));
|
||||
scheduleEpollRebuildLocked();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} // release lock
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Looper::sendMessage(const MessageHandler* handler, const Message& message) {
|
||||
nsecs_t now = SystemClock::uptimeMillis();//systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
sendMessageAtTime(now, handler, message);
|
||||
}
|
||||
|
||||
void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const MessageHandler* handler,
|
||||
const Message& message) {
|
||||
nsecs_t now = SystemClock::uptimeMillis();//systemTime(SYSTEM_TIME_MONOTONIC);
|
||||
sendMessageAtTime(now + uptimeDelay, handler, message);
|
||||
}
|
||||
|
||||
void Looper::sendMessageAtTime(nsecs_t uptime, const MessageHandler* handler,
|
||||
const Message& message) {
|
||||
LOGD_IF(DEBUG_CALLBACKS,"%p sendMessageAtTime - uptime=%lld, handler=%p, what=%d", this, uptime, handler, message.what);
|
||||
|
||||
size_t i = 0;
|
||||
{ // acquire lock
|
||||
std::lock_guard<std::mutex> _l(mLock);
|
||||
|
||||
std::list<MessageEnvelope>::iterator it;
|
||||
for(it=mMessageEnvelopes.begin();it!=mMessageEnvelopes.end();it++){
|
||||
if(uptime>=it->uptime)break;
|
||||
i+=1;
|
||||
}
|
||||
|
||||
MessageEnvelope messageEnvelope(uptime,(MessageHandler*)handler, message);
|
||||
mMessageEnvelopes.insert(it,messageEnvelope);
|
||||
|
||||
// Optimization: If the Looper is currently sending a message, then we can skip
|
||||
// the call to wake() because the next thing the Looper will do after processing
|
||||
// messages is to decide when the next wakeup time should be. In fact, it does
|
||||
// not even matter whether this code is running on the Looper thread.
|
||||
if (mSendingMessage) return;
|
||||
} // release lock
|
||||
|
||||
// Wake the poll loop only when we enqueue a new message at the head.
|
||||
if (i == 0) wake();
|
||||
}
|
||||
|
||||
void Looper::addEventHandler(const EventHandler*handler){
|
||||
mEventHandlers.insert(mEventHandlers.begin(),(EventHandler*)handler);
|
||||
}
|
||||
|
||||
void Looper::removeEventHandler(const EventHandler*handler){
|
||||
for(auto it=mEventHandlers.begin();it!=mEventHandlers.end();it++){
|
||||
if((*it)==handler){
|
||||
(*it)->mRemoved=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Looper::removeEventHandlers(){
|
||||
for(auto it=mEventHandlers.begin();it!=mEventHandlers.end();it++){
|
||||
if((*it)->mRemoved){
|
||||
EventHandler*handler=(*it);
|
||||
it=mEventHandlers.erase(it);
|
||||
LOGD(" %p",(*it));
|
||||
delete handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Looper::removeMessages(const MessageHandler* handler) {
|
||||
LOGD_IF(DEBUG_CALLBACKS,"%p removeMessages - handler=%p", this, handler);
|
||||
|
||||
{ // acquire lock
|
||||
std::lock_guard<std::mutex>_l(mLock);
|
||||
|
||||
for( auto it=mMessageEnvelopes.begin();it!=mMessageEnvelopes.end();it++){
|
||||
if(it->handler==handler)
|
||||
it=mMessageEnvelopes.erase(it);
|
||||
}
|
||||
} // release lock
|
||||
}
|
||||
|
||||
void Looper::removeMessages(const MessageHandler* handler, int what) {
|
||||
LOGD_IF(DEBUG_CALLBACKS,"%p removeMessages - handler=%p, what=%d size=%d", this, handler, what,mMessageEnvelopes.size());
|
||||
|
||||
{ // acquire lock
|
||||
std::lock_guard<std::mutex>_l(mLock);
|
||||
for( auto it=mMessageEnvelopes.begin();it!=mMessageEnvelopes.end();it++){
|
||||
LOGD("addr=%p,%p what=%d,%d",addr_of(it->handler),addr_of(handler),it->message.what,what);
|
||||
if((it->handler==handler) && (it->message.what==what)){
|
||||
it=mMessageEnvelopes.erase(it);
|
||||
}
|
||||
}
|
||||
} // release lock
|
||||
}
|
||||
|
||||
bool Looper::isPolling() const {
|
||||
return mPolling;
|
||||
}
|
||||
|
||||
LooperCallback::~LooperCallback(){
|
||||
}
|
||||
|
||||
SimpleLooperCallback::SimpleLooperCallback(Looper_callbackFunc callback) :
|
||||
mCallback(callback) {
|
||||
}
|
||||
|
||||
SimpleLooperCallback::~SimpleLooperCallback() {
|
||||
}
|
||||
|
||||
int SimpleLooperCallback::handleEvent(int fd, int events, void* data) {
|
||||
return mCallback(fd, events, data);
|
||||
}
|
||||
|
||||
MessageHandler::~MessageHandler(){
|
||||
}
|
||||
|
||||
EventHandler::~EventHandler(){
|
||||
}
|
||||
|
||||
}
|
@ -4,10 +4,13 @@
|
||||
#include <sys/epoll.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
namespace alooper{
|
||||
#include <mutex>
|
||||
#include <list>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
typedef int64_t nsecs_t;
|
||||
typedef std::function<int(int fd, int events, void* data)>LooperCallback;
|
||||
|
||||
struct Message {
|
||||
Message() : what(0) { }
|
||||
Message(int w) : what(w) { }
|
||||
@ -16,15 +19,42 @@ struct Message {
|
||||
int what;
|
||||
};
|
||||
|
||||
typedef int (*Looper_callbackFunc)(int fd, int events, void* data);
|
||||
|
||||
class LooperCallback{
|
||||
protected:
|
||||
virtual ~LooperCallback();
|
||||
public:
|
||||
virtual int handleEvent(int fd, int events, void* data) = 0;
|
||||
};
|
||||
|
||||
class SimpleLooperCallback : public LooperCallback {
|
||||
protected:
|
||||
virtual ~SimpleLooperCallback();
|
||||
public:
|
||||
SimpleLooperCallback(Looper_callbackFunc callback);
|
||||
virtual int handleEvent(int fd, int events, void* data);
|
||||
private:
|
||||
Looper_callbackFunc mCallback;
|
||||
};
|
||||
|
||||
class MessageHandler{
|
||||
protected:
|
||||
virtual ~MessageHandler();
|
||||
|
||||
public:
|
||||
/* Handles a message. */
|
||||
virtual void handleMessage(const Message& message) = 0;
|
||||
virtual void handleMessage(const Message& message)=0;
|
||||
};
|
||||
|
||||
class EventHandler{
|
||||
private:
|
||||
int mRemoved=0;
|
||||
friend class Looper;
|
||||
protected:
|
||||
virtual ~EventHandler();
|
||||
public:
|
||||
virtual int checkEvents()=0;
|
||||
virtual int handleEvents()=0;
|
||||
};
|
||||
class Looper{
|
||||
private:
|
||||
struct Request {
|
||||
@ -32,7 +62,7 @@ private:
|
||||
int ident;
|
||||
int events;
|
||||
int seq;
|
||||
LooperCallback callback;
|
||||
LooperCallback* callback;
|
||||
void* data;
|
||||
void initEventItem(struct epoll_event* eventItem) const;
|
||||
};
|
||||
@ -54,10 +84,11 @@ private:
|
||||
bool mAllowNonCallbacks; // immutable
|
||||
|
||||
int mWakeEventFd; // immutable
|
||||
//Mutex mLock;
|
||||
std::mutex mLock;
|
||||
|
||||
std::vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
|
||||
std::list<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
|
||||
bool mSendingMessage; // guarded by mLock
|
||||
std::list<EventHandler*> mEventHandlers;
|
||||
|
||||
// Whether we are currently waiting for work. Not protected by a lock,
|
||||
// any use of it is racy anyway.
|
||||
@ -75,14 +106,16 @@ private:
|
||||
std::vector<Response> mResponses;
|
||||
size_t mResponseIndex;
|
||||
nsecs_t mNextMessageUptime;
|
||||
static Looper*mInst;
|
||||
private:
|
||||
int pollInner(int timeoutMillis);
|
||||
int removeFd(int fd, int seq);
|
||||
void awoken();
|
||||
void pushResponse(int events, const Request& request);
|
||||
void rebuildEpollLocked();
|
||||
void scheduleEpollRebuildLocked();
|
||||
void removeEventHandlers();
|
||||
protected:
|
||||
virtual ~Looper(){};
|
||||
public:
|
||||
enum {
|
||||
POLL_WAKE = -1,
|
||||
@ -103,6 +136,8 @@ public:
|
||||
};
|
||||
public:
|
||||
Looper(bool allowNonCallbacks=false);
|
||||
virtual ~Looper();
|
||||
static Looper*getDefault();
|
||||
bool getAllowNonCallbacks() const;
|
||||
int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData);
|
||||
inline int pollOnce(int timeoutMillis) {
|
||||
@ -113,13 +148,16 @@ public:
|
||||
return pollAll(timeoutMillis, NULL, NULL, NULL);
|
||||
}
|
||||
void wake();
|
||||
int addFd(int fd, int ident, int events, LooperCallback callback, void* data);
|
||||
int addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data);
|
||||
int addFd(int fd, int ident, int events,const LooperCallback* callback, void* data);
|
||||
int removeFd(int fd);
|
||||
void sendMessage(MessageHandler& handler, const Message& message);
|
||||
void sendMessageDelayed(nsecs_t uptimeDelay, const MessageHandler& handler,const Message& message);
|
||||
void sendMessageAtTime(nsecs_t uptime, const MessageHandler& handler,const Message& message);
|
||||
void removeMessages(const MessageHandler& handler);
|
||||
void removeMessages(const MessageHandler& handler, int what);
|
||||
void sendMessage(const MessageHandler* handler, const Message& message);
|
||||
void sendMessageDelayed(nsecs_t uptimeDelay, const MessageHandler* handler,const Message& message);
|
||||
void sendMessageAtTime(nsecs_t uptime, const MessageHandler* handler,const Message& message);
|
||||
void removeMessages(const MessageHandler* handler);
|
||||
void removeMessages(const MessageHandler* handler, int what);
|
||||
void addEventHandler(const EventHandler*handler);
|
||||
void removeEventHandler(const EventHandler*handler);
|
||||
bool isPolling() const;
|
||||
|
||||
};
|
14
src/gui/core/scheduler.cc
Normal file → Executable file
14
src/gui/core/scheduler.cc
Normal file → Executable file
@ -1,6 +1,6 @@
|
||||
#include<scheduler.h>
|
||||
#include<cdtypes.h>
|
||||
#include<cdlog.h>
|
||||
#include <core/scheduler.h>
|
||||
#include <cdtypes.h>
|
||||
#include <cdlog.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
@ -15,10 +15,6 @@ static void Repeat2(Scheduler* s, Scheduler::Function f,system_clock::time_point
|
||||
s->schedule(std::bind(&Repeat2,s,f,t,deltaSeconds),t);
|
||||
}
|
||||
|
||||
bool Scheduler::dispatch(EventHandler &func){
|
||||
/*check(),check will be called by looper*/;
|
||||
return func(*this);
|
||||
}
|
||||
|
||||
void Scheduler::schedule(Function f,system_clock::time_point t){
|
||||
if(t>system_clock::now())
|
||||
@ -63,6 +59,9 @@ void Scheduler::remove(system_clock::time_point t){
|
||||
taskQueue.erase(it);
|
||||
}
|
||||
|
||||
void Scheduler::handleMessage(const Message&){
|
||||
}
|
||||
#if 0
|
||||
bool Scheduler::check(){
|
||||
auto task=taskQueue.begin();
|
||||
if(taskQueue.size()==0)return 0;
|
||||
@ -76,5 +75,6 @@ bool Scheduler::check(){
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}/*namespace cdroid*/
|
||||
|
14
src/gui/core/scheduler.h
Normal file → Executable file
14
src/gui/core/scheduler.h
Normal file → Executable file
@ -1,14 +1,14 @@
|
||||
#ifndef __SHCEDULE_H__
|
||||
#define __SHCEDULE_H__
|
||||
#include<chrono>
|
||||
#include<functional>
|
||||
#include<map>
|
||||
#include <looper/looper.h>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <core/looper.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
namespace cdroid{
|
||||
|
||||
class Scheduler:public EventSource{
|
||||
class Scheduler:public MessageHandler{
|
||||
public:
|
||||
typedef std::function<void(void)> Function;
|
||||
private:
|
||||
@ -22,10 +22,8 @@ public:
|
||||
void scheduleDaily(Function f,system_clock::time_point t);
|
||||
void scheduleWeekly(Function f,system_clock::time_point t);
|
||||
void scheduleMonthly(Function f,system_clock::time_point t);/*TODO*/
|
||||
|
||||
virtual void remove(system_clock::time_point t);
|
||||
bool dispatch(EventHandler &func)override;
|
||||
bool check()override;/*check schedulered item*/
|
||||
void handleMessage(const Message&)override;
|
||||
};
|
||||
|
||||
}
|
||||
|
4
src/gui/core/scroller.h
Normal file → Executable file
4
src/gui/core/scroller.h
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
#ifndef __SCROLLER_H__
|
||||
#define __SCROLLER_H__
|
||||
#include <interpolators.h>
|
||||
#include <context.h>
|
||||
#include <animation/interpolators.h>
|
||||
#include <core/context.h>
|
||||
namespace cdroid{
|
||||
|
||||
class Scroller {
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef __NGL_UIEVENTS_H__
|
||||
#define __NGL_UIEVENTS_H__
|
||||
#include <string>
|
||||
#include <eventcodes.h>
|
||||
#include <sparsearray.h>
|
||||
#include <bitset.h>
|
||||
#include <core/eventcodes.h>
|
||||
#include <core/sparsearray.h>
|
||||
#include <core/bitset.h>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
144
src/gui/core/uieventsource.cc
Normal file → Executable file
144
src/gui/core/uieventsource.cc
Normal file → Executable file
@ -8,135 +8,59 @@
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
bool operator>(const UIMSG&m1,const UIMSG m2){
|
||||
return m1.time>m2.time;
|
||||
}
|
||||
|
||||
bool operator==(const UIMSG&m1,const UIMSG m2){
|
||||
return m1.msgid==m2.msgid;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static const void * addr_of(T &&obj) noexcept{
|
||||
struct A {};
|
||||
return &reinterpret_cast<const A &>(obj);
|
||||
}
|
||||
|
||||
UIEventSource::UIEventSource(View*v){
|
||||
mAttachedView=v;
|
||||
mID=0;
|
||||
}
|
||||
|
||||
UIEventSource::~UIEventSource(){
|
||||
}
|
||||
|
||||
int UIEventSource::getEvents(){
|
||||
return normal_msgs.size()||hasDelayedMessage()||(mAttachedView&&mAttachedView->isDirty())||GraphDevice::getInstance().needCompose();
|
||||
}
|
||||
|
||||
bool UIEventSource::processEvents(){
|
||||
bool rc=popMessage();//called by Dispatch,return false the source will be killed
|
||||
if(GraphDevice::getInstance().needCompose())
|
||||
GraphDevice::getInstance().ComposeSurfaces();
|
||||
int UIEventSource::checkEvents(){
|
||||
int rc= hasDelayedRunners()+(mAttachedView&&mAttachedView->isDirty())+GraphDevice::getInstance().needCompose();
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool UIEventSource::dispatch(EventHandler &func){
|
||||
if(func)return func(*this);
|
||||
return processEvents();
|
||||
}
|
||||
|
||||
void UIEventSource::reset(){
|
||||
while(!delayed_msgs.empty())delayed_msgs.pop_front();
|
||||
while(!normal_msgs.empty())normal_msgs.pop_front();
|
||||
}
|
||||
|
||||
void UIEventSource::sendMessage(View*v,DWORD msgid,DWORD wp,ULONG lp,DWORD delayedtime){
|
||||
postMessage(v,msgid,wp,lp,nullptr,delayedtime);
|
||||
}
|
||||
|
||||
void UIEventSource::postMessage(View*v,DWORD msgid,DWORD wp,ULONG lp,const Runnable action,DWORD delayedtime){
|
||||
UIMSG msg;
|
||||
msg.view=v;
|
||||
msg.msgid=msgid;
|
||||
msg.wParam=wp;
|
||||
msg.lParam=lp;
|
||||
msg.runnable=action;
|
||||
if(delayedtime!=0||action!=nullptr){
|
||||
msg.time=SystemClock::uptimeMillis()+delayedtime;
|
||||
for(auto itr=delayed_msgs.begin();itr!=delayed_msgs.end();itr++){
|
||||
if(msg.time<itr->time){
|
||||
delayed_msgs.insert(itr,msg);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
delayed_msgs.push_back(msg);
|
||||
return;
|
||||
}
|
||||
normal_msgs.push_back(msg);
|
||||
}
|
||||
|
||||
void UIEventSource::post(View*v,const Runnable run,DWORD delayedtime){
|
||||
postMessage(v,0,0,0,run,delayedtime);
|
||||
}
|
||||
|
||||
void UIEventSource::removeCallbacks(const Runnable what){
|
||||
normal_msgs.remove_if([&](const UIMSG & m)->bool{
|
||||
return (m.msgid==0) && (addr_of(m.runnable)==addr_of(what));
|
||||
});
|
||||
delayed_msgs.remove_if([&](const UIMSG& m)->bool{
|
||||
return (m.msgid==0) && (addr_of(m.runnable)==addr_of(what));
|
||||
});
|
||||
}
|
||||
|
||||
bool UIEventSource::hasDelayedMessage(){
|
||||
UIMSG msg;
|
||||
if(delayed_msgs.empty())return false;
|
||||
ULONGLONG nowms=SystemClock::uptimeMillis();
|
||||
msg=delayed_msgs.front();
|
||||
return msg.time<nowms;
|
||||
}
|
||||
|
||||
bool UIEventSource::popMessage(){
|
||||
UIMSG msg={0};
|
||||
if(normal_msgs.size()){
|
||||
msg=normal_msgs.front();
|
||||
normal_msgs.pop_front();
|
||||
}else if(hasDelayedMessage()){
|
||||
msg=delayed_msgs.front();
|
||||
delayed_msgs.pop_front();
|
||||
}
|
||||
int UIEventSource::handleEvents(){
|
||||
if (mAttachedView && mAttachedView->isDirty()){
|
||||
mAttachedView->draw();
|
||||
GraphDevice::getInstance().flip();
|
||||
}
|
||||
if(msg.view){
|
||||
msg.view->onMessage(msg.msgid,msg.wParam,msg.lParam);
|
||||
if(GraphDevice::getInstance().needCompose())
|
||||
GraphDevice::getInstance().ComposeSurfaces();
|
||||
if(hasDelayedRunners()){
|
||||
size_t old=mRunnables.size();
|
||||
RUNNER runner=mRunnables.front();
|
||||
runner.run();
|
||||
mRunnables.erase(mRunnables.begin());
|
||||
}
|
||||
switch(msg.msgid){
|
||||
case View::WM_DESTROY:
|
||||
WindowManager::getInstance().removeWindow(static_cast<Window*>(msg.view));
|
||||
return false;//return false to tell Eventsource::Dispath,and EventLooper will remove the source.
|
||||
case View::WM_ACTIVE:
|
||||
if(msg.wParam)dynamic_cast<Window*>(msg.view)->onActive();
|
||||
else dynamic_cast<Window*>(msg.view)->onDeactive();
|
||||
break;
|
||||
case 0:
|
||||
if(msg.runnable)msg.runnable();
|
||||
}
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool UIEventSource::hasMessage(const View*v,DWORD msgid){
|
||||
const UIMSG msg={(View*)v,msgid};
|
||||
return delayed_msgs.end()==std::find(delayed_msgs.begin(),delayed_msgs.end(),msg);
|
||||
void UIEventSource::post(Runnable& run,DWORD delayedtime){
|
||||
RUNNER runner;
|
||||
runner.time=SystemClock::uptimeMillis()+delayedtime;
|
||||
runner.run.ID=mID++;
|
||||
runner.run=run;
|
||||
for(auto itr=mRunnables.begin();itr!=mRunnables.end();itr++){
|
||||
if(runner.time<itr->time){
|
||||
mRunnables.insert(itr,runner);
|
||||
return;
|
||||
}
|
||||
}
|
||||
mRunnables.push_back(runner);
|
||||
}
|
||||
|
||||
void UIEventSource::removeMessage(const View*v,DWORD msgid){
|
||||
normal_msgs.remove_if([&](const UIMSG& m)->bool{
|
||||
return (m.msgid==msgid)&&(m.view==v);
|
||||
});
|
||||
delayed_msgs.remove_if([&](const UIMSG& m)->bool{
|
||||
return m.msgid==msgid&&m.view==v;
|
||||
bool UIEventSource::hasDelayedRunners()const{
|
||||
if(mRunnables.empty())return false;
|
||||
nsecs_t nowms=SystemClock::uptimeMillis();
|
||||
RUNNER runner=mRunnables.front();
|
||||
return runner.time<nowms;
|
||||
}
|
||||
|
||||
void UIEventSource::removeCallbacks(const Runnable& what){
|
||||
mRunnables.remove_if([&](const RUNNER& m)->bool{
|
||||
return (m.run.ID==what.ID);
|
||||
});
|
||||
}
|
||||
|
||||
|
42
src/gui/core/uieventsource.h
Normal file → Executable file
42
src/gui/core/uieventsource.h
Normal file → Executable file
@ -1,43 +1,29 @@
|
||||
#ifndef __UIEVENT_SOURCE_H__
|
||||
#define __UIEVENT_SOURCE_H__
|
||||
#include <looper/looper.h>
|
||||
#include <core/looper.h>
|
||||
#include <list>
|
||||
#include <unordered_set>
|
||||
#include <widget/view.h>
|
||||
namespace cdroid{
|
||||
class View;
|
||||
typedef struct{
|
||||
View*view;
|
||||
DWORD msgid;
|
||||
DWORD wParam;
|
||||
ULONG lParam;
|
||||
Runnable runnable;
|
||||
ULONG time;
|
||||
}UIMSG;
|
||||
class UIEventSource:public EventSource{
|
||||
|
||||
class UIEventSource:public EventHandler{
|
||||
private:
|
||||
std::list<UIMSG> normal_msgs;
|
||||
std::list<UIMSG> delayed_msgs;
|
||||
bool hasDelayedMessage();
|
||||
int mID;
|
||||
typedef struct{
|
||||
nsecs_t time;
|
||||
Runnable run;
|
||||
}RUNNER;
|
||||
std::list<RUNNER>mRunnables;
|
||||
View*mAttachedView;
|
||||
bool popMessage();
|
||||
void postMessage(View*,DWORD msgid,DWORD wp,ULONG lp,const Runnable action,DWORD delayedtime=0);
|
||||
bool hasDelayedRunners()const;
|
||||
public:
|
||||
UIEventSource(View*);
|
||||
~UIEventSource();
|
||||
void reset();
|
||||
int getEvents();
|
||||
bool prepare(int&) override { return getEvents();}
|
||||
bool check(){
|
||||
return getEvents();
|
||||
}
|
||||
bool dispatch(EventHandler &func)override;
|
||||
bool processEvents();
|
||||
bool hasMessage(const View*,DWORD msgid);
|
||||
void removeMessage(const View*,DWORD msgid);
|
||||
void sendMessage(View*,DWORD msgid,DWORD wp,ULONG lp,DWORD delayedtime=0);
|
||||
void post(View*v,const Runnable run,DWORD delay=0);
|
||||
void removeCallbacks(const Runnable what);
|
||||
int checkEvents()override;
|
||||
int handleEvents()override;
|
||||
void post(Runnable& run,DWORD delay=0);
|
||||
void removeCallbacks(const Runnable& what);
|
||||
};
|
||||
|
||||
}//end namespace
|
||||
|
2
src/gui/core/velocitytracker.h
Normal file → Executable file
2
src/gui/core/velocitytracker.h
Normal file → Executable file
@ -1,8 +1,8 @@
|
||||
#ifndef __VELOCITY_TRACKER_H__
|
||||
#define __VELOCITY_TRACKER_H__
|
||||
|
||||
#include <uievents.h>
|
||||
#include <queue>
|
||||
#include <core/uievents.h>
|
||||
namespace cdroid{
|
||||
typedef int64_t nsecs_t;
|
||||
class VelocityTrackerStrategy;
|
||||
|
@ -58,12 +58,15 @@ void WindowManager::addWindow(Window*win){
|
||||
w->mLayer=w->window_type*10000+(idx-type_idx)*5;
|
||||
LOGV("%p window %p[%s] type=%d layer=%d",win,w,w->getText().c_str(),w->window_type,w->mLayer);
|
||||
}
|
||||
if(activeWindow)activeWindow->source->sendMessage(activeWindow,View::WM_ACTIVE,0,0);
|
||||
win->source->sendMessage(win,View::WM_ACTIVE,1,0);
|
||||
Runnable onact;
|
||||
if(activeWindow){
|
||||
onact=std::bind(&Window::onDeactive,activeWindow);
|
||||
activeWindow->post(onact);
|
||||
}
|
||||
onact=std::bind(&Window::onActive,win);
|
||||
win->post(onact);
|
||||
activeWindow=win;
|
||||
Looper::getDefault()->add_event_source(win->source,[](EventSource&e)->bool{
|
||||
return ((UIEventSource&)e).processEvents();
|
||||
});
|
||||
Looper::getDefault()->addEventHandler(win->source);
|
||||
resetVisibleRegion();
|
||||
LOGV("win=%p source=%p windows.size=%d",win,win->source,windows.size());
|
||||
}
|
||||
@ -76,13 +79,14 @@ void WindowManager::removeWindow(Window*w){
|
||||
const RECT wrect=w->getBound();
|
||||
windows.erase(itw);
|
||||
resetVisibleRegion();
|
||||
for(auto itr=windows.begin();itr!=windows.end();itr++){//!=windows.end()){
|
||||
for(auto itr=windows.begin();itr!=windows.end();itr++){
|
||||
Window*w1=(*itr);
|
||||
RECT rc=w1->getBound();
|
||||
rc.intersect(wrect);
|
||||
rc.offset(-w1->getX(),-w1->getY());
|
||||
w1->invalidate(&rc);
|
||||
}
|
||||
Looper::getDefault()->removeEventHandler(w->source);
|
||||
delete w;
|
||||
for(auto it=windows.rbegin();it!=windows.rend();it++){
|
||||
if((*it)->hasFlag(View::FOCUSABLE)&&(*it)->getVisibility()==View::VISIBLE){
|
||||
@ -116,7 +120,7 @@ void WindowManager::moveWindow(Window*w,int x,int y){
|
||||
|
||||
void WindowManager::broadcast(DWORD msgid,DWORD wParam,ULONG lParam){
|
||||
for(auto win:windows)
|
||||
win->sendMessage(msgid,wParam,lParam);
|
||||
;//win->sendMessage(msgid,wParam,lParam);
|
||||
}
|
||||
|
||||
int WindowManager::enumWindows(WNDENUMPROC cbk){
|
||||
|
2
src/gui/drawables/colorfilters.h
Normal file → Executable file
2
src/gui/drawables/colorfilters.h
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
#ifndef __COLOR_FILTERS_H__
|
||||
#define __COLOR_FILTERS_H__
|
||||
#include <drawables/colormatrix.h>
|
||||
#include <canvas.h>
|
||||
#include <core/canvas.h>
|
||||
namespace cdroid{
|
||||
enum TintMode{
|
||||
CLEAR =0,
|
||||
|
4
src/gui/drawables/colorstatelist.h
Normal file → Executable file
4
src/gui/drawables/colorstatelist.h
Normal file → Executable file
@ -2,8 +2,8 @@
|
||||
#define __COLOR_STATE_LIST_H__
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <context.h>
|
||||
#include <attributeset.h>
|
||||
#include <core/context.h>
|
||||
#include <core/attributeset.h>
|
||||
|
||||
namespace cdroid{
|
||||
class ComplexColor{
|
||||
|
@ -1,13 +1,13 @@
|
||||
#ifndef __DRAWABLE_H__
|
||||
#define __DRAWABLE_H__
|
||||
#include <canvas.h>
|
||||
#include <core/canvas.h>
|
||||
#include <drawables/stateset.h>
|
||||
#include <drawables/colorstatelist.h>
|
||||
#include <drawables/colorfilters.h>
|
||||
#include <attributeset.h>
|
||||
#include <context.h>
|
||||
#include <gravity.h>
|
||||
#include <rect.h>
|
||||
#include <core/attributeset.h>
|
||||
#include <core/context.h>
|
||||
#include <core/gravity.h>
|
||||
#include <core/rect.h>
|
||||
#include <vector>
|
||||
|
||||
namespace cdroid{
|
||||
|
3
src/gui/drawables/shape.h
Normal file → Executable file
3
src/gui/drawables/shape.h
Normal file → Executable file
@ -1,7 +1,6 @@
|
||||
#ifndef __SHAPE_H__
|
||||
#define __SHAPE_H__
|
||||
#include <rect.h>
|
||||
#include <canvas.h>
|
||||
#include <core/canvas.h>
|
||||
namespace cdroid{
|
||||
|
||||
class Shape{
|
||||
|
2
src/gui/drawables/stateset.h
Normal file → Executable file
2
src/gui/drawables/stateset.h
Normal file → Executable file
@ -2,7 +2,7 @@
|
||||
#define __STATESET_H__
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <attributeset.h>
|
||||
#include <core/attributeset.h>
|
||||
namespace cdroid{
|
||||
class StateSet{
|
||||
private:
|
||||
|
@ -1,227 +0,0 @@
|
||||
//
|
||||
// Looper.cpp - This file is part of the Looper library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#include <looper/EventLoop.h>
|
||||
#include <looper/EventSource.h>
|
||||
#include <looper/FileSource.h>
|
||||
#include <looper/IdleSource.h>
|
||||
#include <looper/TimeoutSource.h>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
#include <poll.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <iostream>
|
||||
#include <cdtypes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace cdroid {
|
||||
|
||||
struct Looper::Private {
|
||||
bool quit;
|
||||
int exit_code;
|
||||
int epoolfd;
|
||||
uint64_t time_last;
|
||||
vector<EventSource*> sources;
|
||||
vector<EventSource*> remove_sources;
|
||||
vector<FileSource*> pollable_sources;
|
||||
vector<struct pollfd> poll_fds;
|
||||
unordered_set<EventSource*> source_set;
|
||||
vector<IdleSource*> idle_sources;
|
||||
vector<TimeoutSource*> timeout_sources;
|
||||
|
||||
Private() : quit(false), exit_code(0) {
|
||||
epoolfd=epoll_create(128);
|
||||
}
|
||||
void add_event_source(EventSource*source) {
|
||||
sources.emplace_back(source);
|
||||
source_set.emplace(source);
|
||||
if (source->is_idle_source())
|
||||
idle_sources.emplace_back(dynamic_cast<IdleSource*>(source));
|
||||
else if (source->is_timeout_source())
|
||||
timeout_sources.emplace_back(dynamic_cast<TimeoutSource*>(source));
|
||||
else if (source->is_file_source())
|
||||
pollable_sources.emplace_back(dynamic_cast<FileSource*>(source));
|
||||
}
|
||||
void remove_event_source(EventSource*source) {
|
||||
if (source->is_idle_source()) {
|
||||
idle_sources.erase(remove(begin(idle_sources),end(idle_sources), source), end(idle_sources));
|
||||
} else if (source->is_timeout_source()) {
|
||||
timeout_sources.erase(remove(begin(timeout_sources),end(timeout_sources), source),end(timeout_sources));
|
||||
} else if (source->is_file_source()) {
|
||||
pollable_sources.erase(remove(begin(pollable_sources),end(pollable_sources), source),end(pollable_sources));
|
||||
}
|
||||
sources.erase(remove(begin(sources),end(sources), source), end(sources));
|
||||
source_set.erase(source);
|
||||
}
|
||||
~Private() {
|
||||
for (auto source : sources)
|
||||
delete source;
|
||||
close(epoolfd);
|
||||
}
|
||||
};
|
||||
|
||||
Looper*Looper::mInst=nullptr;
|
||||
Looper*Looper::getDefault(){
|
||||
if(mInst==nullptr)
|
||||
mInst=new Looper();
|
||||
return mInst;
|
||||
}
|
||||
|
||||
Looper::Looper()
|
||||
: impl(make_shared<Private>()) {
|
||||
}
|
||||
|
||||
void Looper::iteration() {
|
||||
int max_timeout =10;//-1;
|
||||
int n_ready = 0;
|
||||
// prepare and check for already ready event sources
|
||||
for (auto source : impl->sources) {
|
||||
if (source->is_idle_source())
|
||||
continue;
|
||||
|
||||
int source_timeout = -1;
|
||||
|
||||
if (source->prepare(source_timeout)) {
|
||||
source->loop_data.ready = true;
|
||||
n_ready++;
|
||||
} else if (source_timeout > 0 && (max_timeout == -1 || source_timeout < max_timeout)) {
|
||||
max_timeout = source_timeout;
|
||||
}
|
||||
}
|
||||
|
||||
// poll all of the pollable event sources
|
||||
impl->poll_fds.resize(impl->pollable_sources.size());
|
||||
for (size_t i = 0; i < impl->pollable_sources.size(); i++) {
|
||||
if (! impl->pollable_sources[i]->loop_data.ready && impl->pollable_sources[i]->fd >= 0) {
|
||||
impl->poll_fds[i].fd = impl->pollable_sources[i]->fd;
|
||||
impl->poll_fds[i].events = static_cast<int>(impl->pollable_sources[i]->events);
|
||||
impl->poll_fds[i].revents = impl->pollable_sources[i]->revents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// if there's nothing else ready and there are idle event sources, make
|
||||
// poll() return immediately.
|
||||
if (n_ready < 1 && impl->idle_sources.size() > 0)
|
||||
max_timeout = 0;
|
||||
|
||||
if (::poll(impl->poll_fds.data(), impl->poll_fds.size(), max_timeout) >0) {
|
||||
for (size_t i = 0; i < impl->pollable_sources.size(); i++)
|
||||
impl->pollable_sources[i]->revents = impl->poll_fds[i].revents;
|
||||
}
|
||||
|
||||
// now check if any more sources are ready after polling
|
||||
for (auto source : impl->sources) {
|
||||
if (source->is_idle_source())
|
||||
continue;
|
||||
if (! source->loop_data.ready) {
|
||||
if (source->check()) {
|
||||
source->loop_data.ready = true;
|
||||
n_ready++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl->remove_sources.clear();
|
||||
if (n_ready > 0) {
|
||||
// dispatch all ready event sources
|
||||
for (int i=0; i<impl->sources.size(); i++) {
|
||||
EventSource *source=impl->sources[i];
|
||||
if (! source->is_idle_source() && source->loop_data.ready &&
|
||||
source->loop_data.handler) {
|
||||
if (! source->dispatch(source->loop_data.handler))
|
||||
impl->remove_sources.emplace_back(source);
|
||||
source->loop_data.ready = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// nothing else ready, dispatch idle event sources
|
||||
for (auto source : impl->idle_sources) {
|
||||
if (source->loop_data.handler &&
|
||||
! source->dispatch(source->loop_data.handler)) {
|
||||
impl->remove_sources.emplace_back(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prune event sources which requested to be removed
|
||||
for (auto source : impl->remove_sources)
|
||||
remove_event_source(source);
|
||||
}
|
||||
|
||||
bool Looper::contains_source(EventSource *source) const {
|
||||
return (impl->source_set.count(source) > 0);
|
||||
}
|
||||
|
||||
int Looper::run() {
|
||||
impl->quit = false;
|
||||
impl->exit_code = 0;
|
||||
while (! impl->quit)
|
||||
iteration();
|
||||
return impl->exit_code;
|
||||
}
|
||||
|
||||
void Looper::quit(int exit_code) {
|
||||
impl->exit_code = exit_code;
|
||||
impl->quit = true;
|
||||
}
|
||||
|
||||
bool Looper::add_event_source(EventSource *source, EventHandler handler) {
|
||||
if (contains_source(source))
|
||||
return false;
|
||||
|
||||
source->loop_data.ready = false;
|
||||
source->loop_data.handler = handler ? move(handler) : nullptr;
|
||||
|
||||
impl->add_event_source(source);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Looper::set_source_handler(EventSource *source, EventHandler handler) {
|
||||
if (contains_source(source))
|
||||
source->loop_data.handler = handler;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Looper::remove_event_source(EventSource *source) {
|
||||
if (! contains_source(source))
|
||||
return false;
|
||||
impl->remove_event_source(source);
|
||||
delete source;
|
||||
return true;
|
||||
}
|
||||
|
||||
EventSource *Looper::add_file(int fd, FileEvents events, EventHandler handler) {
|
||||
auto source = new FileSource(fd, events);
|
||||
if (! add_event_source(source, handler)) {
|
||||
delete source;
|
||||
return nullptr;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
EventSource *Looper::add_idle(EventHandler handler) {
|
||||
auto source = new IdleSource;
|
||||
if (! add_event_source(source, handler)) {
|
||||
delete source;
|
||||
return nullptr;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
EventSource *Looper::add_timeout(int timeout_ms, EventHandler handler) {
|
||||
auto source = new TimeoutSource(timeout_ms);
|
||||
if (! add_event_source(source, handler)) {
|
||||
delete source;
|
||||
return nullptr;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
} // namespace Looper
|
@ -1,61 +0,0 @@
|
||||
//
|
||||
// Looper.h - This file is part of the Grinder library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOPER_EVENTLOOP_H
|
||||
#define LOOPER_EVENTLOOP_H
|
||||
|
||||
#include <looper/EventSource.h>
|
||||
#include <looper/FileSource.h>
|
||||
#include <looper/IdleSource.h>
|
||||
#include <looper/TimeoutSource.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
class Looper
|
||||
{
|
||||
public:
|
||||
Looper();
|
||||
int run();
|
||||
void quit(int exit_code=0);
|
||||
|
||||
template< class T, class... Args >
|
||||
T *emplace_event_source(Args&&... args){
|
||||
auto source = new T(std::forward<Args&&>(args)...);
|
||||
if (! add_event_source(source)) {
|
||||
delete source;
|
||||
return nullptr;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
static Looper*getDefault();
|
||||
|
||||
bool add_event_source(EventSource *source, EventHandler handler=nullptr);
|
||||
bool set_source_handler(EventSource *source, EventHandler handler);
|
||||
bool remove_event_source(EventSource *source);
|
||||
bool clear_source_handler(EventSource *source){
|
||||
return set_source_handler(source, nullptr);
|
||||
}
|
||||
|
||||
EventSource *add_file(int fd, FileEvents events, EventHandler handler=nullptr);
|
||||
EventSource *add_idle(EventHandler handler=nullptr);
|
||||
EventSource *add_timeout(int timeout_ms, EventHandler handler=nullptr);
|
||||
private:
|
||||
static Looper*mInst;
|
||||
struct Private;
|
||||
std::shared_ptr<Private> impl;
|
||||
void iteration();
|
||||
bool contains_source(EventSource *source) const;
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOP_EVENTLOOP_H
|
@ -1,55 +0,0 @@
|
||||
//
|
||||
// EventSource.h - This file is part of the Grinder library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOPER_EVENTSOURCE_H
|
||||
#define LOOPER_EVENTSOURCE_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
class Looper;
|
||||
class EventSource;
|
||||
|
||||
typedef std::function<bool(EventSource&)> EventHandler;
|
||||
|
||||
class EventSource
|
||||
{
|
||||
public:
|
||||
virtual ~EventSource() {}
|
||||
virtual bool prepare(int& max_timeout)
|
||||
{
|
||||
max_timeout = -1;
|
||||
return false;
|
||||
}
|
||||
virtual bool check() = 0;
|
||||
virtual bool dispatch(EventHandler& func) = 0;
|
||||
virtual bool is_file_source() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool is_timeout_source() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool is_idle_source() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Looper;
|
||||
struct {
|
||||
bool ready;
|
||||
EventHandler handler;
|
||||
} loop_data;
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOPER_EVENTSOURCE_H
|
@ -1,43 +0,0 @@
|
||||
//
|
||||
// FileEvents.h - This file is part of the UI library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOP_FILEEVENTS_H
|
||||
#define LOOP_FILEEVENTS_H
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
enum class FileEvents {
|
||||
NONE = 0,
|
||||
INPUT = POLLIN,
|
||||
OUTPUT = POLLOUT,
|
||||
PRIORITY = POLLPRI,
|
||||
ERROR = POLLERR,
|
||||
HANGUP = POLLHUP,
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
static inline int operator&(cdroid::FileEvents ev1, cdroid::FileEvents ev2)
|
||||
{
|
||||
return static_cast<int>(ev1) & static_cast<int>(ev2);
|
||||
}
|
||||
|
||||
static inline int operator&(int ev1, cdroid::FileEvents ev2)
|
||||
{
|
||||
return ev1 & static_cast<int>(ev2);
|
||||
}
|
||||
|
||||
static inline cdroid::FileEvents operator|(cdroid::FileEvents ev1, cdroid::FileEvents ev2)
|
||||
{
|
||||
return static_cast<cdroid::FileEvents>(static_cast<int>(ev1) | static_cast<int>(ev2));
|
||||
}
|
||||
|
||||
#endif // LOOP_FILEEVENTS_H
|
||||
|
@ -1,58 +0,0 @@
|
||||
//
|
||||
// FileSource.h - This file is part of the Grinder library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOP_FILESOURCE_H
|
||||
#define LOOP_FILESOURCE_H
|
||||
|
||||
#include <looper/EventSource.h>
|
||||
#include <looper/FileEvents.h>
|
||||
#include <string>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
class FileSource : public EventSource
|
||||
{
|
||||
public:
|
||||
int fd, revents;
|
||||
FileEvents events;
|
||||
FileSource(int fd, FileEvents events=FileEvents::NONE)
|
||||
: fd(fd), revents(0), events(events) {}
|
||||
|
||||
bool prepare(int&) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check() override
|
||||
{
|
||||
if (events == FileEvents::NONE || revents == 0)
|
||||
return false;
|
||||
if (((revents & FileEvents::INPUT) && (events & FileEvents::INPUT)) ||
|
||||
((revents & FileEvents::OUTPUT) && (events & FileEvents::OUTPUT)) ||
|
||||
((revents & FileEvents::PRIORITY) && (events & FileEvents::PRIORITY)) ||
|
||||
((revents & FileEvents::ERROR) && (events & FileEvents::ERROR)) ||
|
||||
((revents & FileEvents::HANGUP) && (events & FileEvents::HANGUP))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dispatch(EventHandler &func)
|
||||
{
|
||||
return func(*this);
|
||||
}
|
||||
|
||||
bool is_file_source() const override final
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOPER_FILESOURCE_H
|
@ -1,81 +0,0 @@
|
||||
#include <looper/GenericSignalSource.h>
|
||||
#include <looper/FileSource.h>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
static const int SIG_MAX = 128;
|
||||
static const int PIPE_READ = 0;
|
||||
static const int PIPE_WRITE = 1;
|
||||
static int pipe_fds[2] = { -1, -1 };
|
||||
|
||||
static void signal_handler(int signo)
|
||||
{
|
||||
uint32_t usigno = signo;
|
||||
::write(pipe_fds[PIPE_WRITE], &usigno, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
GenericSignalSource::GenericSignalSource(bool manage_proc_mask)
|
||||
: GenericSignalSource(nullptr, manage_proc_mask)
|
||||
{
|
||||
}
|
||||
|
||||
GenericSignalSource::GenericSignalSource(const sigset_t *sigs, bool manage_proc_mask)
|
||||
: SignalSource(sigs, manage_proc_mask)
|
||||
{
|
||||
if (pipe_fds[0] == -1 && pipe_fds[1] == -1) {
|
||||
pipe(pipe_fds);
|
||||
fd = pipe_fds[PIPE_READ];
|
||||
}
|
||||
|
||||
if (manage_proc_mask)
|
||||
sigprocmask(SIG_UNBLOCK, sigs, nullptr);
|
||||
}
|
||||
|
||||
GenericSignalSource::~GenericSignalSource()
|
||||
{
|
||||
::close(pipe_fds[0]);
|
||||
::close(pipe_fds[1]);
|
||||
pipe_fds[0] = pipe_fds[1] = -1;
|
||||
|
||||
sigset_t fullset;
|
||||
sigfillset(&fullset);
|
||||
for (int i = 0; i < SIG_MAX; i++) {
|
||||
int res = sigismember(&fullset, i);
|
||||
if (res > 0)
|
||||
signal(i, SIG_DFL);
|
||||
}
|
||||
}
|
||||
|
||||
bool GenericSignalSource::dispatch(EventHandler &func)
|
||||
{
|
||||
uint32_t sig = 0;
|
||||
if (::read(fd, &sig, sizeof(uint32_t)) == sizeof(uint32_t)) {
|
||||
signo = sig;
|
||||
return FileSource::dispatch(func);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GenericSignalSource::update_signals(const sigset_t *sigs, bool manage_proc_mask)
|
||||
{
|
||||
for (int i = 0; i < SIG_MAX; i++) {
|
||||
int res = sigismember(sigs, i);
|
||||
if (res > 0)
|
||||
signal(i, signal_handler);
|
||||
else if (res == 0)
|
||||
signal(i, SIG_DFL);
|
||||
}
|
||||
|
||||
if (manage_proc_mask)
|
||||
sigprocmask(SIG_UNBLOCK, sigs, nullptr);
|
||||
}
|
||||
|
||||
} // namespace cdroid
|
@ -1,23 +0,0 @@
|
||||
#ifndef LOOP_GENERICSIGNALSOURCE_H
|
||||
#define LOOP_GENERICSIGNALSOURCE_H
|
||||
|
||||
#include <looper/SignalSource.h>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
class GenericSignalSource : public SignalSource
|
||||
{
|
||||
public:
|
||||
GenericSignalSource(bool manage_proc_mask=false);
|
||||
GenericSignalSource(const sigset_t *sigs=nullptr, bool manage_proc_mask=false);
|
||||
~GenericSignalSource();
|
||||
bool dispatch(EventHandler &func) override;
|
||||
|
||||
protected:
|
||||
void update_signals(const sigset_t *sigs, bool manage_proc_mask);
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOPER_GENERICSIGNALSOURCE_H
|
@ -1,39 +0,0 @@
|
||||
//
|
||||
// IdleSource.h - This file is part of the UI library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOPIDLESOURCE_H
|
||||
#define LOOPIDLESOURCE_H
|
||||
|
||||
#include <looper/EventSource.h>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
class IdleSource : public EventSource
|
||||
{
|
||||
public:
|
||||
bool prepare(int&) override final
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool check() override final
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool dispatch(EventHandler &func) override
|
||||
{
|
||||
return func(*this);
|
||||
}
|
||||
bool is_idle_source() const override final
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOPER_IDLESOURCE_H
|
@ -1,9 +0,0 @@
|
||||
#ifndef LOOPER_PLATFORM_H
|
||||
#define LOOPER_PLATFORM_H
|
||||
|
||||
#if defined(__linux) || defined(__linux__)
|
||||
# define LOOPER_LINUX 1
|
||||
#endif
|
||||
|
||||
#endif // LOOPER_PLATFORM_H
|
||||
|
@ -1,53 +0,0 @@
|
||||
//
|
||||
// SignalFD.cpp - This file is part of the Grinder library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#include <looper/SignalFD.h>
|
||||
|
||||
#ifdef LOOPER_LINUX
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
SignalFD::SignalFD(bool manage_proc_mask)
|
||||
: SignalFD(nullptr, manage_proc_mask)
|
||||
{
|
||||
}
|
||||
|
||||
SignalFD::SignalFD(const sigset_t *sigs, bool manage_proc_mask)
|
||||
: SignalSource(sigs, manage_proc_mask)
|
||||
{
|
||||
if (sigs && manage_proc_mask)
|
||||
sigprocmask(SIG_BLOCK, sigs, nullptr);
|
||||
}
|
||||
|
||||
bool SignalFD::dispatch(EventHandler &func)
|
||||
{
|
||||
signalfd_siginfo info;
|
||||
if (read(fd, &info, sizeof(signalfd_siginfo)) == sizeof(signalfd_siginfo)) {
|
||||
signo = info.ssi_signo;
|
||||
return FileSource::dispatch(func);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SignalFD::update_signals(const sigset_t *sigs, bool manage_proc_mask)
|
||||
{
|
||||
fd = signalfd(fd, sigs, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
if (manage_proc_mask) {
|
||||
sigset_t allset;
|
||||
::sigfillset(&allset);
|
||||
::sigprocmask(SIG_UNBLOCK, &allset, nullptr);
|
||||
::sigprocmask(SIG_BLOCK, sigs, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOPER_LINUX
|
@ -1,35 +0,0 @@
|
||||
//
|
||||
// SignalFD.h - This file is part of the Grinder library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOPER_LINUX_SIGNALFD_H
|
||||
#define LOOPER_LINUX_SIGNALFD_H
|
||||
|
||||
#include <looper/Platform.h>
|
||||
#ifdef LOOPER_LINUX
|
||||
|
||||
#include <looper/SignalSource.h>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
class SignalFD : public SignalSource
|
||||
{
|
||||
public:
|
||||
SignalFD(bool manage_proc_mask=false);
|
||||
SignalFD(const sigset_t *sigs, bool manage_proc_mask=false);
|
||||
|
||||
bool dispatch(EventHandler &func) override;
|
||||
|
||||
protected:
|
||||
void update_signals(const sigset_t *sigs, bool manage_proc_mask);
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOPER_LINUX
|
||||
|
||||
#endif // LOOPER_LINUX_SIGNALFD_H
|
@ -1,66 +0,0 @@
|
||||
#include <looper/SignalSource.h>
|
||||
#include <looper/Platform.h>
|
||||
#ifdef LOOPER_LINUX
|
||||
# include <looper/SignalFD.h>
|
||||
#else
|
||||
# include <looper/GenericSignalSource.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
SignalSource::SignalSource(bool manage_proc_mask)
|
||||
: FileSource(-1, FileEvents::INPUT),
|
||||
m_manage_proc_mask(manage_proc_mask)
|
||||
{
|
||||
sigemptyset(&m_sigs);
|
||||
if (m_manage_proc_mask)
|
||||
sigprocmask(SIG_BLOCK, nullptr, &m_old_sigs);
|
||||
}
|
||||
|
||||
SignalSource::SignalSource(const sigset_t *sigs, bool manage_proc_mask)
|
||||
: FileSource(-1, FileEvents::INPUT),
|
||||
m_manage_proc_mask(manage_proc_mask)
|
||||
{
|
||||
if (sigs)
|
||||
m_sigs = *sigs;
|
||||
else
|
||||
sigemptyset(&m_sigs);
|
||||
if (m_manage_proc_mask)
|
||||
sigprocmask(SIG_BLOCK, nullptr, &m_old_sigs);
|
||||
}
|
||||
|
||||
SignalSource::~SignalSource()
|
||||
{
|
||||
try {
|
||||
if (m_manage_proc_mask) {
|
||||
sigset_t ss;
|
||||
sigfillset(&ss);
|
||||
sigprocmask(SIG_UNBLOCK, &ss, nullptr);
|
||||
sigprocmask(SIG_BLOCK, &m_old_sigs, nullptr);
|
||||
}
|
||||
close(fd);
|
||||
} catch (...) {
|
||||
/* pass */
|
||||
}
|
||||
}
|
||||
|
||||
void SignalSource::add(int signo)
|
||||
{
|
||||
sigaddset(&m_sigs, signo);
|
||||
update();
|
||||
}
|
||||
|
||||
void SignalSource::remove(int signo)
|
||||
{
|
||||
sigdelset(&m_sigs, signo);
|
||||
update();
|
||||
}
|
||||
|
||||
void SignalSource::update()
|
||||
{
|
||||
update_signals(&m_sigs, m_manage_proc_mask);
|
||||
}
|
||||
|
||||
} // namespace cdroid
|
@ -1,43 +0,0 @@
|
||||
//
|
||||
// SignalSource.h - This file is part of the UI library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOP_SIGNALSOURCE_H
|
||||
#define LOOP_SIGNALSOURCE_H
|
||||
|
||||
#include <looper/FileSource.h>
|
||||
#include <signal.h>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
class SignalSource : public FileSource
|
||||
{
|
||||
public:
|
||||
int signo; // when event is dispatched, contains the signal number
|
||||
virtual ~SignalSource();
|
||||
void add(int signo);
|
||||
void remove(int signo);
|
||||
bool check() override
|
||||
{
|
||||
return (revents & FileEvents::INPUT);
|
||||
}
|
||||
void update();
|
||||
|
||||
protected:
|
||||
SignalSource(bool manage_proc_mask=false);
|
||||
SignalSource(const sigset_t *sigs, bool manage_proc_mask=false);
|
||||
virtual void update_signals(const sigset_t *sigs, bool manage_proc_mask) = 0;
|
||||
|
||||
private:
|
||||
sigset_t m_sigs;
|
||||
sigset_t m_old_sigs;
|
||||
bool m_manage_proc_mask;
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOP_SIGNALSOURCE_H
|
@ -1,46 +0,0 @@
|
||||
//
|
||||
// TimeoutSource.cpp - This file is part of the UI library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#include <looper/TimeoutSource.h>
|
||||
#include <looper/Utility.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
TimeoutSource::TimeoutSource(int timeout)
|
||||
: m_timeout(timeout),
|
||||
m_next_expiry(time_now() + timeout)
|
||||
{
|
||||
}
|
||||
|
||||
bool TimeoutSource::is_ready(int &max_timeout)
|
||||
{
|
||||
uint64_t now = time_now();
|
||||
if (now >= m_next_expiry) {
|
||||
m_next_expiry = (now + m_timeout) - (now - m_next_expiry);
|
||||
return true;
|
||||
} else {
|
||||
max_timeout = m_next_expiry - now;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TimeoutSource::prepare(int &max_timeout)
|
||||
{
|
||||
return is_ready(max_timeout);
|
||||
}
|
||||
|
||||
bool TimeoutSource::check()
|
||||
{
|
||||
int unused = 0;
|
||||
return is_ready(unused);
|
||||
}
|
||||
|
||||
} // namespace cdroid
|
@ -1,40 +0,0 @@
|
||||
//
|
||||
// TimeoutSource.h - This file is part of the UI library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOP_TIMEOUTSOURCE_H
|
||||
#define LOOP_TIMEOUTSOURCE_H
|
||||
|
||||
#include <looper/EventSource.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
class TimeoutSource : public EventSource
|
||||
{
|
||||
public:
|
||||
TimeoutSource(int timeout=-1);
|
||||
bool prepare(int &max_timeout) override;
|
||||
bool check() override;
|
||||
bool dispatch(EventHandler &func) override
|
||||
{
|
||||
return func(*this);
|
||||
}
|
||||
bool is_timeout_source() const override final
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_timeout;
|
||||
std::uint64_t m_next_expiry;
|
||||
bool is_ready(int& max_timeout);
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOP_TIMEOUTSOURCE_H
|
@ -1,78 +0,0 @@
|
||||
//
|
||||
// TimerFD.cpp - This file is part of the Grinder library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#include <looper/TimerFD.h>
|
||||
|
||||
#ifdef LOOPER_LINUX
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
TimerFD::TimerFD(int timeout_ms, bool one_shot)
|
||||
: FileSource(::timerfd_create(CLOCK_MONOTONIC,
|
||||
TFD_NONBLOCK | TFD_CLOEXEC),
|
||||
FileEvents::INPUT),
|
||||
m_timeout(timeout_ms),
|
||||
m_one_shot(one_shot)
|
||||
{
|
||||
arm();
|
||||
}
|
||||
|
||||
TimerFD::~TimerFD()
|
||||
{
|
||||
if (fd >= 0)
|
||||
::close(fd);
|
||||
}
|
||||
|
||||
static inline void ms_to_timespec(int ms, struct timespec *ts)
|
||||
{
|
||||
ts->tv_sec = ms / 1000;
|
||||
ts->tv_nsec = (ms % 1000) * 1000000;
|
||||
}
|
||||
|
||||
void TimerFD::arm(int timeout)
|
||||
{
|
||||
if (timeout >= 0)
|
||||
m_timeout = timeout;
|
||||
itimerspec its {{0,0},{0,0}};
|
||||
ms_to_timespec(m_timeout, &its.it_value);
|
||||
if (! m_one_shot) {
|
||||
its.it_interval.tv_sec = its.it_value.tv_sec;
|
||||
its.it_interval.tv_nsec = its.it_value.tv_nsec;
|
||||
}
|
||||
::timerfd_settime(fd, 0, &its, nullptr);
|
||||
}
|
||||
|
||||
void TimerFD::disarm()
|
||||
{
|
||||
itimerspec its {{0,0},{0,0}};
|
||||
::timerfd_settime(fd, 0, &its, nullptr);
|
||||
}
|
||||
|
||||
bool TimerFD::check()
|
||||
{
|
||||
return (revents & FileEvents::INPUT);
|
||||
}
|
||||
|
||||
bool TimerFD::dispatch(EventHandler &func)
|
||||
{
|
||||
uint64_t count = 0;
|
||||
if (::read(fd, &count, sizeof(uint64_t)) == sizeof(uint64_t))
|
||||
return FileSource::dispatch(func);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOPER_LINUX
|
@ -1,62 +0,0 @@
|
||||
//
|
||||
// TimerFD.h - This file is part of the Grinder library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOPER_LINUX_TIMERFD_H
|
||||
#define LOOPER_LINUX_TIMERFD_H
|
||||
|
||||
#include <looper/Platform.h>
|
||||
#ifdef LOOPER_LINUX
|
||||
|
||||
#include <looper/FileSource.h>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
class TimerFD : public FileSource
|
||||
{
|
||||
public:
|
||||
TimerFD(int timeout_ms, bool one_shot=false);
|
||||
~TimerFD();
|
||||
|
||||
void arm(int timeout=-1);
|
||||
void disarm();
|
||||
|
||||
bool one_shot() const
|
||||
{
|
||||
return m_one_shot;
|
||||
}
|
||||
void set_one_shot(bool one_shot)
|
||||
{
|
||||
disarm();
|
||||
m_one_shot = one_shot;
|
||||
arm();
|
||||
}
|
||||
|
||||
int timeout() const
|
||||
{
|
||||
return m_timeout;
|
||||
}
|
||||
void set_timeout(int timeout_ms)
|
||||
{
|
||||
disarm();
|
||||
m_timeout = timeout_ms;
|
||||
arm();
|
||||
}
|
||||
|
||||
bool check() override;
|
||||
bool dispatch(EventHandler &func) override;
|
||||
|
||||
private:
|
||||
int m_timeout;
|
||||
bool m_one_shot;
|
||||
};
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOPER_LINUX
|
||||
|
||||
#endif // LOOPER_LINUX_TIMERFD_H
|
@ -1,26 +0,0 @@
|
||||
//
|
||||
// Utility.h - This file is part of the Grinder library
|
||||
//
|
||||
// Copyright (c) 2015 Matthew Brush <mbrush@codebrainz.ca>
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LOOPER_UTILITY_H
|
||||
#define LOOPER_UTILITY_H
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
namespace cdroid
|
||||
{
|
||||
|
||||
static inline std::uint64_t time_now()
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
} // namespace cdroid
|
||||
|
||||
#endif // LOOPER_UTILITY_H
|
||||
|
@ -1,20 +0,0 @@
|
||||
#ifndef __LOOPER_HEADER__
|
||||
#define __LOOPER_HEADER__
|
||||
|
||||
#include <looper/EventLoop.h>
|
||||
#include <looper/EventSource.h>
|
||||
#include <looper/FileEvents.h>
|
||||
#include <looper/FileSource.h>
|
||||
#include <looper/GenericSignalSource.h>
|
||||
#include <looper/IdleSource.h>
|
||||
#include <looper/Platform.h>
|
||||
#include <looper/SignalSource.h>
|
||||
#include <looper/TimeoutSource.h>
|
||||
#include <looper/Utility.h>
|
||||
|
||||
#ifdef LOOPER_LINUX
|
||||
# include <looper/SignalFD.h>
|
||||
# include <looper/TimerFD.h>
|
||||
#endif
|
||||
|
||||
#endif // LOOPER_HEADER__
|
6
src/gui/views/toastwindow.cc
Normal file → Executable file
6
src/gui/views/toastwindow.cc
Normal file → Executable file
@ -11,7 +11,7 @@ ToastWindow::ToastWindow(int w,int h):Window(0,0,w,h,TYPE_TOAST){
|
||||
timeout_=-1;
|
||||
time_elapsed=0;
|
||||
setFocusable(false);
|
||||
sendMessage((DWORD)WM_TIMER,(DWORD)TIMER_ID,0,500);
|
||||
//sendMessage((DWORD)WM_TIMER,(DWORD)TIMER_ID,0,500);
|
||||
toasts_.push_back(this);
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ ToastWindow::~ToastWindow(){
|
||||
toasts_.erase(std::find(toasts_.begin(),toasts_.end(),this));
|
||||
}
|
||||
|
||||
bool ToastWindow::onMessage(DWORD msg,DWORD wp,ULONG lp){
|
||||
/*bool ToastWindow::onMessage(DWORD msg,DWORD wp,ULONG lp){
|
||||
if(msg==WM_TIMER && wp==TIMER_ID){
|
||||
time_elapsed+=500;
|
||||
if(time_elapsed>=timeout_){
|
||||
@ -30,7 +30,7 @@ bool ToastWindow::onMessage(DWORD msg,DWORD wp,ULONG lp){
|
||||
return true;
|
||||
}
|
||||
return Window::onMessage(msg,wp,lp);
|
||||
}
|
||||
}*/
|
||||
|
||||
bool ToastWindow::onKeyUp(int keyCode,KeyEvent&evt){
|
||||
time_elapsed=0;
|
||||
|
1
src/gui/views/toastwindow.h
Normal file → Executable file
1
src/gui/views/toastwindow.h
Normal file → Executable file
@ -13,7 +13,6 @@ DECLARE_UIEVENT(ToastWindow*,OnCreateContentListener);
|
||||
public:
|
||||
ToastWindow(int w,int h);
|
||||
~ToastWindow();
|
||||
virtual bool onMessage(DWORD msg,DWORD wp,ULONG lp)override;
|
||||
virtual bool onKeyUp(int,KeyEvent&event)override;
|
||||
static ToastWindow*makeWindow(OnCreateContentListener oncreate,UINT timeout=LENGTH_SHORT);
|
||||
static ToastWindow*makeText(const std::string&txt,UINT timeout=LENGTH_SHORT);
|
||||
|
@ -1246,7 +1246,8 @@ void AbsListView::keyPressed() {
|
||||
}
|
||||
}
|
||||
if (longClickable && !mDataChanged) {
|
||||
postDelayed(std::bind(&AbsListView::CheckForKeyLongPress,this),ViewConfiguration::getLongPressTimeout());
|
||||
Runnable mr(std::bind(&AbsListView::CheckForKeyLongPress,this));
|
||||
postDelayed(mr,ViewConfiguration::getLongPressTimeout());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
#ifndef __ABS_LISTVIEW_H__
|
||||
#define __ABS_LISTVIEW_H__
|
||||
#include <sparsearray.h>
|
||||
#include <core/sparsearray.h>
|
||||
#include <widget/adapterview.h>
|
||||
#include <widget/recyclebin.h>
|
||||
#include <widget/overscroller.h>
|
||||
#include <widget/edgeeffect.h>
|
||||
#include <velocitytracker.h>
|
||||
namespace cdroid{
|
||||
|
||||
#define OVERSCROLL_LIMIT_DIVISOR 3
|
||||
|
2
src/gui/widget/absspinner.h
Normal file → Executable file
2
src/gui/widget/absspinner.h
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
#ifndef __ABS_SPINNER_H__
|
||||
#define __ABS_SPINNER_H__
|
||||
#include <widget/adapterview.h>
|
||||
#include <sparsearray.h>
|
||||
#include <core/sparsearray.h>
|
||||
namespace cdroid{
|
||||
class AbsSpinner:public AdapterView{
|
||||
protected:
|
||||
|
6
src/gui/widget/adapter.cc
Normal file → Executable file
6
src/gui/widget/adapter.cc
Normal file → Executable file
@ -58,8 +58,8 @@ bool Adapter::isEmpty()const{
|
||||
return getCount() == 0;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PagerAdapter::startUpdate(ViewGroup* container){
|
||||
startUpdate((View*)container);
|
||||
}
|
||||
@ -68,10 +68,12 @@ void PagerAdapter::startUpdate(View*container){
|
||||
}
|
||||
|
||||
void*PagerAdapter::instantiateItem(ViewGroup* container, int position){
|
||||
instantiateItem((View*)container,position);
|
||||
return instantiateItem((View*)container,position);
|
||||
}
|
||||
|
||||
void* PagerAdapter::instantiateItem(View* container, int position){
|
||||
throw "Required method instantiateItem was not overridden";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PagerAdapter::destroyItem(ViewGroup* container, int position, void* object){
|
||||
|
8
src/gui/widget/analogclock.cc
Normal file → Executable file
8
src/gui/widget/analogclock.cc
Normal file → Executable file
@ -54,9 +54,9 @@ Drawable*AnalogClock::getClockDrawable(int id){
|
||||
}
|
||||
|
||||
void AnalogClock::onAttached(){
|
||||
sendMessage(WM_TIMER,0,0,1000);
|
||||
//sendMessage(WM_TIMER,0,0,1000);
|
||||
}
|
||||
bool AnalogClock::onMessage(DWORD msg,DWORD wp,ULONG lp){
|
||||
/*bool AnalogClock::onMessage(DWORD msg,DWORD wp,ULONG lp){
|
||||
if(msg==WM_TIMER){
|
||||
std::time_t t = std::time(NULL);
|
||||
struct std::tm when= *std::localtime(&t);
|
||||
@ -64,12 +64,12 @@ bool AnalogClock::onMessage(DWORD msg,DWORD wp,ULONG lp){
|
||||
mHour=when.tm_hour;
|
||||
mMinutes=when.tm_min;
|
||||
mSeconds=when.tm_sec;
|
||||
sendMessage(msg,wp,lp,1000);
|
||||
//sendMessage(msg,wp,lp,1000);
|
||||
invalidate(nullptr);
|
||||
return true;
|
||||
}
|
||||
return View::onMessage(msg,wp,lp);
|
||||
}
|
||||
}*/
|
||||
|
||||
void AnalogClock::onDraw(Canvas&canvas){
|
||||
View::onDraw(canvas);
|
||||
|
2
src/gui/widget/analogclock.h
Normal file → Executable file
2
src/gui/widget/analogclock.h
Normal file → Executable file
@ -27,7 +27,7 @@ public:
|
||||
AnalogClock(int w,int h);
|
||||
void setClockDrawable(Drawable*d,int id);
|
||||
Drawable*getClockDrawable(int id);
|
||||
bool onMessage(DWORD msg,DWORD wp,ULONG lp);
|
||||
//bool onMessage(DWORD msg,DWORD wp,ULONG lp);
|
||||
};
|
||||
|
||||
}//namespace
|
||||
|
6
src/gui/widget/edgeeffect.h
Normal file → Executable file
6
src/gui/widget/edgeeffect.h
Normal file → Executable file
@ -1,8 +1,8 @@
|
||||
#ifndef __EDGE_EFFECT_H__
|
||||
#define __EDGE_EFFECT_H__
|
||||
#include <canvas.h>
|
||||
#include <context.h>
|
||||
#include <interpolators.h>
|
||||
#include <core/canvas.h>
|
||||
#include <core/context.h>
|
||||
#include <animation/interpolators.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
|
1
src/gui/widget/horizontalscrollview.h
Normal file → Executable file
1
src/gui/widget/horizontalscrollview.h
Normal file → Executable file
@ -3,7 +3,6 @@
|
||||
#include <widget/framelayout.h>
|
||||
#include <widget/overscroller.h>
|
||||
#include <widget/edgeeffect.h>
|
||||
#include <velocitytracker.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
|
4
src/gui/widget/imageview.cc
Normal file → Executable file
4
src/gui/widget/imageview.cc
Normal file → Executable file
@ -317,7 +317,7 @@ void ImageView::configureBounds(){
|
||||
|
||||
|
||||
const bool fits = (dwidth < 0 || vwidth == dwidth) && (dheight < 0 || vheight == dheight);
|
||||
LOGD("drawables.setBounds(%d,%d) fits=%d mScaleType=%d",vwidth,vheight,fits,mScaleType);
|
||||
LOGV("drawables.setBounds(%d,%d) fits=%d mScaleType=%d",vwidth,vheight,fits,mScaleType);
|
||||
|
||||
mDrawable->setBounds(0, 0, vwidth, vheight);
|
||||
|
||||
@ -387,7 +387,7 @@ void ImageView::configureBounds(){
|
||||
//mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
|
||||
}
|
||||
}
|
||||
LOGD("ScaleType=%d DrawMatrix=%.2f,%.2f, %.2f,%.2f, %.2f,%.2f",mScaleType,
|
||||
LOGV("ScaleType=%d DrawMatrix=%.2f,%.2f, %.2f,%.2f, %.2f,%.2f",mScaleType,
|
||||
mDrawMatrix.xx,mDrawMatrix.yx,mDrawMatrix.xy,mDrawMatrix.yy,mDrawMatrix.x0,mDrawMatrix.y0);
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <widget/view.h>
|
||||
#include <widget/edittext.h>
|
||||
#include <vector>
|
||||
#include <keyboard.h>
|
||||
#include <core/keyboard.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
|
4
src/gui/widget/layoutparams.h
Normal file → Executable file
4
src/gui/widget/layoutparams.h
Normal file → Executable file
@ -1,9 +1,9 @@
|
||||
#ifndef __LAYOUT_PARAMS_H__
|
||||
#define __LAYOUT_PARAMS_H__
|
||||
#include <string>
|
||||
#include <attributeset.h>
|
||||
#include <context.h>
|
||||
#include <limits.h>
|
||||
#include <core/attributeset.h>
|
||||
#include <core/context.h>
|
||||
|
||||
namespace cdroid{
|
||||
class View;
|
||||
|
1
src/gui/widget/numberpicker.cc
Normal file → Executable file
1
src/gui/widget/numberpicker.cc
Normal file → Executable file
@ -2,7 +2,6 @@
|
||||
#include <color.h>
|
||||
#include <textutils.h>
|
||||
#include <cdlog.h>
|
||||
#include <interpolators.h>
|
||||
|
||||
//https://gitee.com/awang/WheelView/blob/master/src/com/wangjie/wheelview/WheelView.java
|
||||
|
||||
|
5
src/gui/widget/numberpicker.h
Normal file → Executable file
5
src/gui/widget/numberpicker.h
Normal file → Executable file
@ -3,9 +3,8 @@
|
||||
#include <widget/linearlayout.h>
|
||||
#include <widget/imagebutton.h>
|
||||
#include <widget/edittext.h>
|
||||
#include <scroller.h>
|
||||
#include <velocitytracker.h>
|
||||
#include <sparsearray.h>
|
||||
#include <core/scroller.h>
|
||||
#include <core/sparsearray.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <widget/overscroller.h>
|
||||
#include <systemclock.h>
|
||||
#include <scroller.h>
|
||||
#include <core/systemclock.h>
|
||||
#include <core/scroller.h>
|
||||
#include <core/viewconfiguration.h>
|
||||
#include <cdlog.h>
|
||||
|
||||
|
||||
@ -53,6 +54,7 @@ OverScroller::SplineOverScroller::SplineOverScroller(Context* context) {
|
||||
* 39.37f // inch/meter
|
||||
* ppi
|
||||
* 0.84f; // look and feel tuning
|
||||
mFlingFriction = ViewConfiguration::getScrollFriction();
|
||||
}
|
||||
|
||||
void OverScroller::SplineOverScroller::startScroll(int start, int distance, int duration) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef __OVER_SCROLLER_H__
|
||||
#define __OVER_SCROLLER_H__
|
||||
#include <viewconfiguration.h>
|
||||
#include <interpolators.h>
|
||||
#include <core/context.h>
|
||||
#include <animation/interpolators.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
@ -47,7 +47,7 @@ public:
|
||||
// The allowed overshot distance before boundary is reached.
|
||||
int mOver;
|
||||
// Fling friction
|
||||
float mFlingFriction = ViewConfiguration::getScrollFriction();
|
||||
float mFlingFriction;
|
||||
// Current state of the animation.
|
||||
int mState = SPLINE;
|
||||
// A context-specific coefficient adjusted to physical values.
|
||||
|
@ -216,13 +216,15 @@ void ProgressBar::refreshProgress(int id, int progress, bool fromUser,bool anima
|
||||
if(!mRefreshIsPosted){
|
||||
LOGD("setprogress %d=%d bools=%d,%d",id,progress,mAttached,mRefreshIsPosted);
|
||||
if(mAttached&&!mRefreshIsPosted){
|
||||
postDelayed([this](){
|
||||
Runnable run;
|
||||
run=[this](){
|
||||
for(int i=ID_PRIMARY;i<=ID_SECONDARY;i++){
|
||||
RefreshData&rd=mData[i];
|
||||
doRefreshProgress(i, rd.progress, rd.fromUser, true, rd.animate);
|
||||
}
|
||||
mRefreshIsPosted=false;
|
||||
},10);
|
||||
};
|
||||
postDelayed(run,10);
|
||||
mRefreshIsPosted=true;
|
||||
}
|
||||
}
|
||||
@ -241,6 +243,7 @@ bool ProgressBar::setProgressInternal(int value, bool fromUser,bool animate){
|
||||
void ProgressBar::setProgress(int value){
|
||||
setProgressInternal(value,FALSE);
|
||||
}
|
||||
|
||||
void ProgressBar::setSecondaryProgress(int secondaryProgress) {
|
||||
if (mIndeterminate) return;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifndef __RECYCLEBIN_H__
|
||||
#define __RECYCLEBIN_H__
|
||||
#include <widget/view.h>
|
||||
#include <sparsearray.h>
|
||||
#include <core/sparsearray.h>
|
||||
namespace cdroid{
|
||||
|
||||
class RecycleBin{
|
||||
|
1
src/gui/widget/scrollview.h
Normal file → Executable file
1
src/gui/widget/scrollview.h
Normal file → Executable file
@ -3,7 +3,6 @@
|
||||
#include <widget/framelayout.h>
|
||||
#include <widget/overscroller.h>
|
||||
#include <widget/edgeeffect.h>
|
||||
#include <velocitytracker.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
|
2
src/gui/widget/simplemonthview.h
Normal file → Executable file
2
src/gui/widget/simplemonthview.h
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
#ifndef __SIMPLE_MONTHVIEW_H__
|
||||
#define __SIMPLE_MONTHVIEW_H__
|
||||
#include <widget/view.h>
|
||||
#include <calendar.h>
|
||||
#include <core/calendar.h>
|
||||
namespace cdroid{
|
||||
|
||||
class SimpleMonthView:public View{
|
||||
|
2
src/gui/widget/tablerow.h
Normal file → Executable file
2
src/gui/widget/tablerow.h
Normal file → Executable file
@ -1,7 +1,7 @@
|
||||
#ifndef __TABLE_ROW_H__
|
||||
#define __TABLE_ROW_H__
|
||||
#include <widget/linearlayout.h>
|
||||
#include <sparsearray.h>
|
||||
#include <core/sparsearray.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
|
@ -18,8 +18,8 @@
|
||||
#define __TEXTVIEW_H__
|
||||
|
||||
#include <widget/view.h>
|
||||
#include <gravity.h>
|
||||
#include <layout.h>
|
||||
#include <core/gravity.h>
|
||||
#include <core/layout.h>
|
||||
|
||||
namespace cdroid {
|
||||
|
||||
|
@ -165,7 +165,6 @@ void View::initView(){
|
||||
mOnFocusChangeListener=nullptr;
|
||||
mOnScrollChangeListener=nullptr;
|
||||
mOverScrollMode=OVER_SCROLL_NEVER;
|
||||
mOnMessage=nullptr;
|
||||
mVerticalScrollbarPosition=0;
|
||||
mUserPaddingLeft=mUserPaddingRight=0;
|
||||
mUserPaddingTop=mUserPaddingBottom=0;
|
||||
@ -532,7 +531,7 @@ void View::setFadingEdgeLength(int length){
|
||||
}
|
||||
void View::transformFromViewToWindowSpace(int*inOutLocation){
|
||||
View* view = this;
|
||||
double position[2]={inOutLocation[0],inOutLocation[1]};
|
||||
double position[2]={(double)inOutLocation[0],(double)inOutLocation[1]};
|
||||
if(!hasIdentityMatrix()){
|
||||
mMatrix.transform_point(position[0],position[1]);
|
||||
}
|
||||
@ -1225,10 +1224,6 @@ void View::setOnScrollChangeListener(OnScrollChangeListener l){
|
||||
mOnScrollChangeListener=l;
|
||||
}
|
||||
|
||||
void View::setMessageListener(MessageListener ls){
|
||||
mOnMessage=ls;
|
||||
}
|
||||
|
||||
void View::clip(RefPtr<Region>rgn){
|
||||
if(mParent){//clip sliblings
|
||||
BOOL afterthis=FALSE;
|
||||
@ -2595,7 +2590,9 @@ void View::invalidate(int l,int t,int w,int h){
|
||||
}
|
||||
|
||||
void View::postInvalidate(){
|
||||
postDelayed([this](){ invalidate(nullptr);},30);
|
||||
Runnable r;
|
||||
r=[this](){ invalidate(nullptr);};
|
||||
postDelayed(r,30);
|
||||
}
|
||||
|
||||
void View::postInvalidateOnAnimation(){
|
||||
@ -3311,7 +3308,7 @@ void View::checkForLongClick(int delayOffset,int x,int y){
|
||||
mHasPerformedLongPress = false;
|
||||
mOriginalPressedState=isPressed();
|
||||
mPendingCheckForLongPress=std::bind(&View::checkLongPressCallback,this,x,y);
|
||||
post(this,mPendingCheckForLongPress,ViewConfiguration::getLongPressTimeout()-delayOffset);
|
||||
postDelayed(mPendingCheckForLongPress,ViewConfiguration::getLongPressTimeout()-delayOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3427,52 +3424,27 @@ bool View::onTouchEvent(MotionEvent& mt){
|
||||
return false;
|
||||
}
|
||||
|
||||
void View::sendMessage(View*v,DWORD msgid,DWORD wParam,ULONG lParam,DWORD delayedtime){
|
||||
View*root=getRootView();
|
||||
if(root!=this)
|
||||
root->sendMessage(v,msgid,wParam,lParam,delayedtime);
|
||||
|
||||
}
|
||||
|
||||
void View::sendMessage(DWORD msgid,DWORD wParam,ULONG lParam,DWORD delayedtime){
|
||||
sendMessage(this,msgid,wParam,lParam,delayedtime);
|
||||
}
|
||||
|
||||
void View::postOnAnimation(Runnable action){
|
||||
post(this,action,10);
|
||||
postDelayed(action,10);
|
||||
}
|
||||
void View::postOnAnimationDelayed(Runnable action, long delayMillis){
|
||||
post(this,action,delayMillis);
|
||||
postDelayed(action,delayMillis);
|
||||
}
|
||||
|
||||
void View::post(View*v,const Runnable what,DWORD delay){
|
||||
View*root=getRootView();
|
||||
if(root!=this)root->post(v,what,delay);
|
||||
}
|
||||
|
||||
void View::post(const Runnable what){
|
||||
void View::post(Runnable& what){
|
||||
postDelayed(what,0);
|
||||
}
|
||||
|
||||
void View::postDelayed(const Runnable what,DWORD delay){
|
||||
void View::postDelayed(Runnable& what,uint32_t delay){
|
||||
View*root=getRootView();
|
||||
if(root&&(root!=this))root->post(this,what,delay);
|
||||
if(root&&(root!=this))root->postDelayed(what,delay);
|
||||
}
|
||||
|
||||
void View::removeCallbacks(const Runnable what){
|
||||
void View::removeCallbacks(const Runnable& what){
|
||||
View*root=getRootView();
|
||||
if(root&&(root!=this))root->removeCallbacks(what);
|
||||
}
|
||||
|
||||
bool View::onMessage(DWORD msgid,DWORD wParam,ULONG lParam){
|
||||
RECT r;
|
||||
switch(msgid){
|
||||
default:
|
||||
if(mOnMessage)return mOnMessage(*this,msgid,wParam,lParam);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
// For Layout support
|
||||
|
||||
@ -3667,7 +3639,7 @@ Matrix View::getInverseMatrix() {
|
||||
}
|
||||
|
||||
float View::getRotation(){
|
||||
|
||||
return .0f;
|
||||
}
|
||||
|
||||
void View::setRotation(float rotation){
|
||||
@ -3675,7 +3647,7 @@ void View::setRotation(float rotation){
|
||||
}
|
||||
|
||||
float View::getRotationX(){
|
||||
|
||||
return .0f;
|
||||
}
|
||||
|
||||
void View::setRotationX(float){
|
||||
|
@ -1,10 +1,10 @@
|
||||
#ifndef __NGL_VIEW_H__
|
||||
#define __NGL_VIEW_H__
|
||||
#include <eventcodes.h>
|
||||
#include <uievents.h>
|
||||
#include <canvas.h>
|
||||
#include <viewconfiguration.h>
|
||||
#include <systemclock.h>
|
||||
#include <core/eventcodes.h>
|
||||
#include <core/uievents.h>
|
||||
#include <core/canvas.h>
|
||||
#include <core/viewconfiguration.h>
|
||||
#include <core/systemclock.h>
|
||||
#include <widget/layoutparams.h>
|
||||
#include <widget/measurespec.h>
|
||||
#include <animation/animation.h>
|
||||
@ -12,10 +12,12 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <rect.h>
|
||||
#include <core/rect.h>
|
||||
#include <drawables.h>
|
||||
#include <attributeset.h>
|
||||
#include <context.h>
|
||||
#include <core/gravity.h>
|
||||
#include <core/attributeset.h>
|
||||
#include <core/context.h>
|
||||
#include <core/velocitytracker.h>
|
||||
|
||||
#ifndef _GLIBCXX_FUNCTIONAL
|
||||
#define DECLARE_UIEVENT(type,name,...) typedef type(*name)(__VA_ARGS__)
|
||||
@ -238,7 +240,6 @@ public:
|
||||
};
|
||||
DECLARE_UIEVENT(void,OnClickListener,View&);
|
||||
DECLARE_UIEVENT(bool,OnLongClickListener,View&);
|
||||
DECLARE_UIEVENT(bool,MessageListener,View&,DWORD,DWORD,ULONG);
|
||||
DECLARE_UIEVENT(void,OnFocusChangeListener,View&,bool);
|
||||
DECLARE_UIEVENT(void,OnScrollChangeListener,View& v, int, int, int, int);
|
||||
DECLARE_UIEVENT(void,OnLayoutChangeListener,View* v, int left, int top, int width, int height,
|
||||
@ -323,7 +324,6 @@ protected:
|
||||
OnFocusChangeListener mOnFocusChangeListener;
|
||||
std::vector<OnLayoutChangeListener> mOnLayoutChangeListeners;
|
||||
OnScrollChangeListener mOnScrollChangeListener;
|
||||
MessageListener mOnMessage;
|
||||
|
||||
bool hasIdentityMatrix();
|
||||
void computeOpaqueFlags();
|
||||
@ -356,7 +356,6 @@ protected:
|
||||
|
||||
void postOnAnimation(Runnable action);
|
||||
void postOnAnimationDelayed(Runnable action, long delayMillis);
|
||||
virtual void post(View*v,const Runnable what,DWORD delay=0);
|
||||
virtual void onSizeChanged(int w,int h,int oldw,int oldh);
|
||||
virtual void onScrollChanged(int l, int t, int oldl, int oldt);
|
||||
virtual void onLayout(bool ,int,int,int,int);
|
||||
@ -520,7 +519,6 @@ public:
|
||||
virtual void setOnLongClickListener(OnLongClickListener l);
|
||||
virtual void setOnFocusChangeListener(OnFocusChangeListener listtener);
|
||||
virtual void setOnScrollChangeListener(OnScrollChangeListener l);
|
||||
virtual void setMessageListener(MessageListener ls);
|
||||
void addOnLayoutChangeListener(OnLayoutChangeListener listener);
|
||||
void removeOnLayoutChangeListener(OnLayoutChangeListener listener);
|
||||
virtual bool performClick();
|
||||
@ -680,12 +678,10 @@ public:
|
||||
virtual bool onHoverEvent(MotionEvent& evt);
|
||||
virtual bool onGenericMotionEvent(MotionEvent& event);
|
||||
virtual void onHoverChanged(bool hovered);
|
||||
virtual void sendMessage(DWORD msgid,DWORD wParam,ULONG lParam,DWORD delayedtime=0);
|
||||
virtual void sendMessage(View*view,DWORD msgid,DWORD wParam,ULONG lParam,DWORD delayedtime=0);
|
||||
virtual bool onMessage(DWORD msgid,DWORD wParam,ULONG lParam);
|
||||
virtual void removeCallbacks(const Runnable what);
|
||||
virtual void post(const Runnable what);
|
||||
virtual void postDelayed(const Runnable what,DWORD delay=0);
|
||||
|
||||
virtual void postDelayed(Runnable& what,uint32_t delay=0);
|
||||
void post(Runnable& what);
|
||||
virtual void removeCallbacks(const Runnable& what);
|
||||
|
||||
virtual int getBaseline();
|
||||
static bool isLayoutModeOptical(View*);
|
||||
|
@ -85,9 +85,6 @@ ViewGroup::ViewGroup(int x,int y,int w,int h)
|
||||
}
|
||||
|
||||
void ViewGroup::initGroup(){
|
||||
focusRectSrc.set(0,0,0,0);
|
||||
focusRectDest.set(0,0,0,0);
|
||||
focusRect.set(0,0,0,0);
|
||||
mFocused=nullptr;
|
||||
mDefaultFocus=nullptr;
|
||||
mFocusedInCluster=nullptr;
|
||||
@ -1470,20 +1467,6 @@ bool ViewGroup::isTransformedTouchPointInView(int x,int y, View& child,POINT*out
|
||||
return isInView;
|
||||
}
|
||||
|
||||
void ViewGroup::onDraw(Canvas& canvas) {
|
||||
// Draw the background color, if enabled
|
||||
View::onDraw(canvas);
|
||||
canvas.save();
|
||||
onDrawFocusRect(canvas,focusRect);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
void ViewGroup::onDrawFocusRect(Canvas&canvas,const RECT&r){
|
||||
canvas.set_source_rgba(1,0,0,.5);
|
||||
canvas.rectangle(r.x,r.y,r.width,r.height);
|
||||
canvas.fill();
|
||||
}
|
||||
|
||||
void ViewGroup::onSizeChanged(int w,int h,int ow,int oh){
|
||||
}
|
||||
|
||||
@ -1770,25 +1753,6 @@ static int isExcludedKeys(int key){
|
||||
return key==KEY_MENU||key==KEY_ESCAPE;//||key==KEY_EXIT;
|
||||
}
|
||||
|
||||
void ViewGroup::moveFocusTo(const RECT&r){
|
||||
focusRectSrc=focusRectDest;
|
||||
focusRectDest=r;
|
||||
time_lastframe=SystemClock::uptimeMillis();
|
||||
|
||||
if(hasFlag(ATTR_ANIMATE_FOCUS))
|
||||
sendMessage(WM_TIMER,0,0,10);
|
||||
}
|
||||
|
||||
void ViewGroup::invalidateChildrenInFocusRect(){
|
||||
for(int i=0;i<getChildCount();i++){
|
||||
View*v=getChildAt(i);
|
||||
RECT r;
|
||||
if(!r.intersect(v->getBound(),focusRect))continue;
|
||||
r.offset(-v->getX(),-v->getY());
|
||||
v->invalidate(&r);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewGroup::drawableStateChanged(){
|
||||
View::drawableStateChanged();
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#define __NGLUI_GROUPVIEW_H__
|
||||
|
||||
#include <widget/view.h>
|
||||
#include <scroller.h>
|
||||
#include <core/scroller.h>
|
||||
|
||||
namespace cdroid {
|
||||
|
||||
@ -80,9 +80,6 @@ private:
|
||||
std::vector<View*>mVisibilityChangingChildren;
|
||||
int mChildCountWithTransientState;
|
||||
class TouchTarget* mFirstTouchTarget;
|
||||
RECT focusRectSrc;
|
||||
RECT focusRectDest;
|
||||
RECT focusRect;
|
||||
POINT animateTo;//save window boundray while animating
|
||||
POINT animateFrom;//window animate from boundary
|
||||
Transformation* mChildTransformation;
|
||||
@ -104,8 +101,6 @@ private:
|
||||
bool dispatchTransformedGenericPointerEvent(MotionEvent& event, View* child);
|
||||
|
||||
void setTouchscreenBlocksFocusNoRefocus(bool touchscreenBlocksFocus);
|
||||
void moveFocusTo(const RECT&r);
|
||||
void invalidateChildrenInFocusRect();
|
||||
void addInArray(View* child, int index);
|
||||
bool removeViewInternal(View* view);
|
||||
void removeViewInternal(int index, View* view);
|
||||
@ -161,7 +156,6 @@ protected:
|
||||
|
||||
void drawableStateChanged()override;
|
||||
std::vector<int> onCreateDrawableState()const override;
|
||||
virtual void onDraw(Canvas& canvas) override;
|
||||
void dispatchSetPressed(bool pressed)override;
|
||||
virtual int getChildDrawingOrder(int childCount, int i);
|
||||
|
||||
@ -257,7 +251,6 @@ public:
|
||||
bool dispatchUnhandledMove(View* focused, int direction)override;
|
||||
bool dispatchTouchEvent(MotionEvent& event)override;
|
||||
bool onInterceptTouchEvent(MotionEvent& evt);
|
||||
virtual void onDrawFocusRect(Canvas&,const RECT&);
|
||||
|
||||
void jumpDrawablesToCurrentState()override;
|
||||
void setAddStatesFromChildren(bool addsStates);
|
||||
|
@ -1144,7 +1144,9 @@ void ViewPager::completeScroll(bool postEvents){
|
||||
}
|
||||
}
|
||||
if (needPopulate) {
|
||||
if (postEvents) postOnAnimation([this](){setScrollState(SCROLL_STATE_IDLE);populate();});//mEndScrollRunnable);
|
||||
Runnable r;
|
||||
r=[this](){setScrollState(SCROLL_STATE_IDLE);populate();};
|
||||
if (postEvents) postOnAnimation(r);//mEndScrollRunnable);
|
||||
else {
|
||||
setScrollState(SCROLL_STATE_IDLE);
|
||||
populate();
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <widget/viewgroup.h>
|
||||
#include <widget/adapter.h>
|
||||
#include <widget/edgeeffect.h>
|
||||
#include <velocitytracker.h>
|
||||
#include <math.h>
|
||||
#include <limits>
|
||||
namespace cdroid{
|
||||
@ -121,7 +120,7 @@ private:
|
||||
/**
|
||||
* Determines speed during touch scrolling
|
||||
*/
|
||||
VelocityTracker* mVelocityTracker;
|
||||
class VelocityTracker* mVelocityTracker;
|
||||
int mMinimumVelocity;
|
||||
int mMaximumVelocity;
|
||||
int mFlingDistance;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user