remaking looper impl,remove MessageListener

This commit is contained in:
侯歌 2021-08-05 12:00:22 +08:00
parent 6bfddb7370
commit ee104a0285
121 changed files with 1114 additions and 1816 deletions

6
apps/samples/animation.cc Normal file → Executable file
View 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();
}

View File

@ -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);

View File

@ -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
View 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();
}

View File

@ -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(){

View File

@ -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
View 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
View 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
View 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
View 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
View 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()

View File

@ -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>)

View File

@ -1,6 +1,6 @@
#ifndef __ANIMATION_H__
#define __ANIMATION_H__
#include <context.h>
#include <core/context.h>
#include <animation/transformation.h>

View File

@ -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

View File

@ -2,7 +2,7 @@
#include <vector>
#include <memory>
#include <functional>
#include <interpolators.h>
#include <animation/interpolators.h>
namespace cdroid{

View File

@ -1,4 +1,4 @@
#include <interpolators.h>
#include <animation/interpolators.h>
namespace cdroid{
#if 0

View File

View File

@ -3,7 +3,6 @@
#include <map>
#include <functional>
#include <widget/viewgroup.h>
#include <interpolators.h>
#include <animation/animator.h>
namespace cdroid{

View File

@ -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{

View File

@ -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{

View File

@ -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));
}
}
}
}

View File

@ -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
View 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
View File

@ -1,6 +1,5 @@
#ifndef __ASSETS_H__
#define __ASSETS_H__
#include <context.h>
#include <map>
#include <memory>
#include <string>

View File

@ -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); }
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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{

View File

@ -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
View 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
View 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
View 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
View 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 }

View File

@ -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);

View File

@ -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,10 +18,10 @@ namespace GRT{
namespace cdroid{
class InputEventSource:public EventSource{
class InputEventSource:public EventHandler{
protected:
std::mutex mtxEvents;
bool isplayback;
bool isplayback;
nsecs_t lasteventTime;
std::ofstream frecord;
std::queue<InputEvent*>events;
@ -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
View 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
View 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(){
}
}

View File

@ -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
View 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
View 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
View 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 {

View File

@ -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>

152
src/gui/core/uieventsource.cc Normal file → Executable file
View File

@ -8,136 +8,60 @@
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();
mAttachedView->draw();
GraphDevice::getInstance().flip();
}
if(msg.view){
msg.view->onMessage(msg.msgid,msg.wParam,msg.lParam);
}
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;
if(GraphDevice::getInstance().needCompose())
GraphDevice::getInstance().ComposeSurfaces();
if(hasDelayedRunners()){
size_t old=mRunnables.size();
RUNNER runner=mRunnables.front();
runner.run();
mRunnables.erase(mRunnables.begin());
}
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);
});
}
}//end namespace

42
src/gui/core/uieventsource.h Normal file → Executable file
View 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
View 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;

View File

@ -48,7 +48,7 @@ WindowManager::~WindowManager() {
void WindowManager::addWindow(Window*win){
windows.push_back(win);
std::sort(windows.begin(),windows.end(),[](Window*w1,Window*w2){
return (w2->window_type-w1->window_type)>0;
return (w2->window_type-w1->window_type)>0;
});
for(int idx=0,type_idx=0;idx<windows.size();idx++){
@ -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
View 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
View 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{

View File

@ -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
View 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
View File

@ -2,7 +2,7 @@
#define __STATESET_H__
#include <string>
#include <vector>
#include <attributeset.h>
#include <core/attributeset.h>
namespace cdroid{
class StateSet{
private:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
View 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
View 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);

View File

@ -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());
}
}
}

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View File

@ -3,7 +3,6 @@
#include <widget/framelayout.h>
#include <widget/overscroller.h>
#include <widget/edgeeffect.h>
#include <velocitytracker.h>
namespace cdroid{

6
src/gui/widget/imageview.cc Normal file → Executable file
View 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,8 +387,8 @@ void ImageView::configureBounds(){
//mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
}
}
LOGD("ScaleType=%d DrawMatrix=%.2f,%.2f, %.2f,%.2f, %.2f,%.2f",mScaleType,
mDrawMatrix.xx,mDrawMatrix.yx,mDrawMatrix.xy,mDrawMatrix.yy,mDrawMatrix.x0,mDrawMatrix.y0);
LOGV("ScaleType=%d DrawMatrix=%.2f,%.2f, %.2f,%.2f, %.2f,%.2f",mScaleType,
mDrawMatrix.xx,mDrawMatrix.yx,mDrawMatrix.xy,mDrawMatrix.yy,mDrawMatrix.x0,mDrawMatrix.y0);
}
void ImageView::invalidateDrawable(Drawable& dr){

View File

@ -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
View 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
View 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
View 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{

View File

@ -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) {

View File

@ -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.

View File

@ -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;

View File

@ -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
View 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
View 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
View 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{

View File

@ -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 {

View File

@ -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){

View File

@ -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*);

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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