diff --git a/rainbow/Turtle/Ctrl.h b/rainbow/Turtle/Ctrl.h index 5afcba4ce..5af627870 100644 --- a/rainbow/Turtle/Ctrl.h +++ b/rainbow/Turtle/Ctrl.h @@ -2,11 +2,9 @@ private: static Ptr desktop; static Vector topctrl; - static bool invalid; static Point fbCursorPos; static Image fbCursorImage; - static bool sdlMouseIsIn; static Rect fbCaretRect; static int fbCaretTm; @@ -14,8 +12,29 @@ private: static bool fbEndSession; static int64 fbEventLoop; static int64 fbEndSessionLoop; + + static Ctrl& Desktop(); + + static void TimerAndPaint(); + static bool ProcessEvent(const String& event); + + static bool quit; + static int main_pid; + static Vector pid; + static TcpSocket socket; + static WebSocket websocket; + static int64 update_serial; + static int64 recieved_update_serial; - static void CursorSync(); + static Vector invalid; + + static BiVector event_queue; + static Size DesktopSize; + + static void AddInvalid(const Rect& r); + void AddInvalid() { AddInvalid(GetScreenRect()); } + + static void InvalidateDesktop(); int FindTopCtrl() const; static Rect GetClipBound(const Vector& inv, const Rect& r); @@ -49,21 +68,17 @@ private: void SetOpen(bool b) { isopen = b; } -protected: - static Ctrl& Desktop(); - - static void TimerAndPaint(); - static bool ProcessEvent(const String& event); - - static bool quit; - static int main_pid; - static Vector pid; - static TcpSocket socket; - static WebSocket websocket; - static void Signal(int signal); static void Broadcast(int signal); + static void Put8(int x) { turtle_stream.Put(x); } + static void Put16(int x); + static void Put32(int x); + static void Put(Point p); + static void Put(Size sz); + static void Put(const Rect& r); + static void Put(const String& s); + public: static bool DoKeyFB(dword key, int cnt); @@ -71,6 +86,9 @@ public: static int port; static bool debugmode; static String ip; + + static Time stat_started; + static int64 stat_data_send; static bool StartSession(); static Callback WhenDisconnect; @@ -80,21 +98,12 @@ public: static Ctrl *GetDesktop() { return desktop; } static void SetDesktopSize(Size sz); - static void Invalidate() { invalid = true; } - void DragRectDraw(const Rect& rect1, const Rect& rect2, const Rect& clip, int n, Color color, int type, int animation); static Ctrl *FindMouseTopCtrl(); static void PaintScene(SystemDraw& draw); - static void PaintCaretCursor(SystemDraw& draw); - static bool SystemCursor; - enum { DRAWDRAGRECT_SCREEN = 0x8000 }; - - _TODO_ - static bool ProcessEventQueue(const String& event_queue); - //$ }; diff --git a/rainbow/Turtle/Draw.cpp b/rainbow/Turtle/Draw.cpp index 4d4111a86..891252439 100644 --- a/rainbow/Turtle/Draw.cpp +++ b/rainbow/Turtle/Draw.cpp @@ -2,43 +2,10 @@ #ifdef GUI_TURTLE +#define LLOG(x) // LOG(x) + NAMESPACE_UPP -void SystemDraw::Put16(int x) -{ - Put8(LOBYTE(x)); - Put8(HIBYTE(x)); -} - -void SystemDraw::Put32(int x) -{ - Put16(LOWORD(x)); - Put16(HIWORD(x)); -} - -void SystemDraw::Put(Point p) -{// TODO: Clamp? - Put16(p.x); - Put16(p.y); -} - -void SystemDraw::Put(Size sz) -{ - Put((Point)sz); -} - -void SystemDraw::Put(const Rect& r) -{ - Put(r.TopLeft()); - Put(r.GetSize()); -} - -void SystemDraw::Put(const String& s) -{ - Put32(s.GetLength()); - turtle_stream.Put(s); -} - Index SystemDraw::img_index[3]; int SystemDraw::GetImageI(int from, Index& img_index, int maxcount, const Image& img) @@ -54,15 +21,16 @@ int SystemDraw::GetImageI(int from, Index& img_index, int maxcount, const q = Random(maxcount); img_index.Set(q, id); } - Put8(SETIMAGE); - Put16(q + from); - Put(img.GetSize()); + LLOG("SetImage " << q + from << ", size: " << img.GetLength()); + Ctrl::Put8(SETIMAGE); + Ctrl::Put16(q + from); + Ctrl::Put(img.GetSize()); const RGBA *end = ~img + img.GetLength(); for(const RGBA *s = ~img; s < end; s++) { - Put8(s->r); - Put8(s->g); - Put8(s->b); - Put8(s->a); + Ctrl::Put8(s->r); + Ctrl::Put8(s->g); + Ctrl::Put8(s->b); + Ctrl::Put8(s->a); } } return q + from; @@ -78,28 +46,55 @@ int SystemDraw::GetImageI(const Image& img) void SystemDraw::PutImage(Point p, const Image& img, const Rect& src) { + LLOG("Ctrl::PutImage " << p << ", size: " << img.GetSize() << ", src: " << src << ", id: " << img.GetSerialId()); int i = GetImageI(img); - Put8(IMAGE); - Put16(i); - Put(p); - Put(src); + if(Rect(img.GetSize()) == src) { + Point dp = p - pos; + if(abs(dp.x) < 256 && abs(dp.y) < 256) { + Ctrl::Put8(dp.x < 0 ? dp.y < 0 ? IMAGENN : IMAGENP : dp.y < 0 ? IMAGEPN : IMAGEPP); + Ctrl::Put8(abs(dp.x)); + Ctrl::Put8(abs(dp.y)); + Ctrl::Put16(i); + pos = p; + return; + } + } + Ctrl::Put8(IMAGE); + Ctrl::Put16(i); + Ctrl::Put(p); + Ctrl::Put(src); + pos = p; } void SystemDraw::PutRect(const Rect& r, Color color) -{ // TODO: Support InvertColor +{ + LLOG("Ctrl::PutRect " << r << ", color " << color); + Point p = r.TopLeft(); if(color == InvertColor()) { - Put8(INVERTRECT); - Put(r); + Ctrl::Put8(INVERTRECT); + Ctrl::Put(r); } else { - Put8(RECT); - Put(r); - Put8(color.GetR()); - Put8(color.GetG()); - Put8(color.GetB()); + Size sz = r.GetSize(); + Point dp = p - pos; + if(abs(dp.x) < 256 && abs(dp.y) < 256 && sz.cx < 256 && sz.cy < 256 && 0) { + Ctrl::Put8(dp.x < 0 ? dp.y < 0 ? RECTNN : RECTNP : dp.y < 0 ? RECTPN : RECTPP); + Ctrl::Put8(abs(dp.x)); + Ctrl::Put8(abs(dp.y)); + Ctrl::Put8(sz.cx); + Ctrl::Put8(sz.cy); + } + else { + Ctrl::Put8(RECT); + Ctrl::Put(r); + } + Ctrl::Put8(color.GetR()); + Ctrl::Put8(color.GetG()); + Ctrl::Put8(color.GetB()); } + pos = p; } END_UPP_NAMESPACE -#endif \ No newline at end of file +#endif diff --git a/rainbow/Turtle/DrawDragRect.cpp b/rainbow/Turtle/DrawDragRect.cpp index 8126d3eb3..5b94472f7 100644 --- a/rainbow/Turtle/DrawDragRect.cpp +++ b/rainbow/Turtle/DrawDragRect.cpp @@ -63,7 +63,7 @@ void DrawDragRect(Ctrl& q, const DrawDragRectInfo& f) DrawDragFrame(w, f.rect1, f.n, dash, f.animation); DrawDragFrame(w, f.rect2, f.n, dash, f.animation); // w.End(); - Ctrl::PaintCaretCursor(w); +// Ctrl::PaintCaretCursor(w); // SDL_GL_SwapWindow(screen.win); } @@ -88,7 +88,7 @@ void FinishDragRect(Ctrl& q) { SystemDraw w; Ctrl::PaintScene(w); - Ctrl::PaintCaretCursor(w); +// Ctrl::PaintCaretCursor(w); _TODO_ //SDL_GL_SwapWindow(screen.win); } diff --git a/rainbow/Turtle/Event.cpp b/rainbow/Turtle/Event.cpp index 3c889b586..c7fae6a96 100644 --- a/rainbow/Turtle/Event.cpp +++ b/rainbow/Turtle/Event.cpp @@ -8,9 +8,12 @@ NAMESPACE_UPP #define LDUMP(x) // RDUMP(x) #define LTIMING(x) +Time Ctrl::stat_started; +int64 Ctrl::stat_data_send; + static Point MousePos; -Size DesktopSize = Size(1000, 1000); +Size Ctrl::DesktopSize = Size(1000, 1000); StaticRect& DesktopRect() { @@ -23,24 +26,7 @@ Ctrl& Ctrl::Desktop() return DesktopRect(); } -BiVector event_queue; - -void Ctrl::TimerAndPaint() -{ - LLOG("TimerAndPaint " << msecs()); - TimerProc(GetTickCount()); - DefferedFocusSync(); - SyncCaret(); - SyncTopWindows(); - SweepMkImageCache(); - DoPaint(); - socket.Timeout(20000); - websocket.SendBinary(ZCompress(String(SystemDraw::DISABLESENDING, 1))); // Do not send events until data transfered and processed - String s = turtle_stream.FlushStream(); - if(s.GetCount() > 10) - LLOG("Sending " << s.GetLength()); - websocket.SendBinary(s); -} +BiVector Ctrl::event_queue; void Ctrl::EndSession() { @@ -66,8 +52,20 @@ bool Ctrl::IsWaitingEvent() } LLOG("Recieved data " << s); StringStream ss(s); - while(!ss.IsEof()) - event_queue.AddTail(ss.GetLine()); + while(!ss.IsEof()) { + String s = ss.GetLine(); + CParser p(s); + try { + if(p.Id("S")) { + uint32 l = p.ReadNumber(); + uint32 h = p.ReadNumber(); + recieved_update_serial = MAKEQWORD(l, h); + } + else + event_queue.AddTail(s); + } + catch(CParser::Error) {} + } } socket.Timeout(20000); if(socket.IsError()) @@ -148,86 +146,6 @@ void Ctrl::SetCaret(int x, int y, int cx, int cy) SyncCaret(); } -void Ctrl::SyncCaret() -{ - CursorSync(); -} - -void Ctrl::CursorSync() -{ -// LLOG("@ CursorSync"); - Point p = GetMousePos() - fbCursorImage.GetHotSpot(); - Rect cr = Null; - if(focusCtrl && (((GetTickCount() - fbCaretTm) / 500) & 1) == 0) - cr = (RectC(focusCtrl->caretx, focusCtrl->carety, focusCtrl->caretcx, focusCtrl->caretcy) - + focusCtrl->GetScreenView().TopLeft()) & focusCtrl->GetScreenView(); - if(fbCursorPos != p && !SystemCursor || cr != fbCaretRect) { - fbCaretRect = cr; - fbCursorPos = p; - Invalidate(); - } -} - -void Ctrl::PaintScene(SystemDraw& draw) -{ - if(!desktop) - return; - LLOG("@ DoPaint"); - LTIMING("DoPaint paint"); - draw.Init(DesktopSize); - draw.Begin(); - Vector invalid; - invalid.Add(DesktopSize); _TODO_ - for(int i = topctrl.GetCount() - 1; i >= 0; i--) { - Rect r = topctrl[i]->GetRect(); - Rect ri = GetClipBound(invalid, r); - if(!IsNull(ri)) { - draw.Clipoff(r); - topctrl[i]->UpdateArea(draw, ri - r.TopLeft()); - draw.End(); - Subtract(invalid, r); - draw.ExcludeClip(r); - } - } - Rect ri = GetClipBound(invalid, desktop->GetRect().GetSize()); - if(!IsNull(ri)) - desktop->UpdateArea(draw, ri); - draw.End(); -} - -void Ctrl::PaintCaretCursor(SystemDraw& draw) -{ - if(!IsNull(fbCaretRect)) - draw.DrawRect(fbCaretRect, InvertColor); - int64 q = fbCursorImage.GetAuxData(); - if(q) { - draw.Put8(SystemDraw::STD_CURSORIMAGE); - draw.Put8(clamp((int)q, 1, 16)); - } - else { - String h; - Point p = fbCursorImage.GetHotSpot(); - h << "url('data:image/png;base64," - << Base64Encode(PNGEncoder().SaveString(fbCursorImage)) - << "') " << p.x << ' ' << p.y << ", default"; - draw.Put8(SystemDraw::SETCURSORIMAGE); - draw.Put16(0); // _TODO_ Cursor cache - draw.Put(h); - draw.Put8(SystemDraw::CURSORIMAGE); - draw.Put16(0); // _TODO_ Cursor cache - } -} - -void Ctrl::DoPaint() -{ - if(invalid && desktop) { - invalid = false; - SystemDraw draw; - PaintScene(draw); - PaintCaretCursor(draw); - } -} - bool keyShift; bool keyCtrl; bool keyAlt; @@ -238,7 +156,8 @@ bool GetAlt() { return keyAlt; } bool GetCapsLock() { return false; } // Impossible to implement dword fbKEYtoK(dword chr) { - chr = chr + K_DELTA; + if(findarg(chr, 9, 0xd) < 0) + chr = chr + K_DELTA; if(chr == K_ALT_KEY || chr == K_CTRL_KEY || chr == K_SHIFT_KEY) return chr; if(GetCtrl()) chr |= K_CTRL; @@ -409,7 +328,7 @@ bool Ctrl::ProcessEvent(const String& event) int code = p.ReadInt(); int which = p.ReadInt(); ReadKeyMods(p); - if(which && !keyAlt && !keyCtrl) + if(which && !keyAlt && !keyCtrl && findarg(which, 9, 0xd) < 0) DoKeyFB(which, 1); } } diff --git a/rainbow/Turtle/Output.cpp b/rainbow/Turtle/Output.cpp new file mode 100644 index 000000000..507aa3ea9 --- /dev/null +++ b/rainbow/Turtle/Output.cpp @@ -0,0 +1,146 @@ +#include "Local.h" + +#ifdef GUI_TURTLE + +NAMESPACE_UPP + +#define LLOG(x) // LLOG(x) +#define LDUMP(x) // RDUMP(x) +#define LTIMING(x) + +void Ctrl::Put16(int x) +{ + Put8(LOBYTE(x)); + Put8(HIBYTE(x)); +} + +void Ctrl::Put32(int x) +{ + Put16(LOWORD(x)); + Put16(HIWORD(x)); +} + +void Ctrl::Put(Point p) +{// TODO: Clamp? + Put16(p.x); + Put16(p.y); +} + +void Ctrl::Put(Size sz) +{ + Put((Point)sz); +} + +void Ctrl::Put(const Rect& r) +{ + Put(r.TopLeft()); + Put(r.GetSize()); +} + +void Ctrl::Put(const String& s) +{ + Put32(s.GetLength()); + turtle_stream.Put(s); +} + +void Ctrl::TimerAndPaint() +{ + LLOG("TimerAndPaint " << msecs()); + TimerProc(GetTickCount()); + DefferedFocusSync(); + SyncCaret(); + SyncTopWindows(); + SweepMkImageCache(); + DoPaint(); + socket.Timeout(20000); + if(turtle_stream.HasData()) { + websocket.SendBinary(ZCompress(String(SystemDraw::DISABLESENDING, 1))); // Do not send events until data transfered and processed + int64 x = ++update_serial; + Put8(SystemDraw::UPDATESERIAL); + Put32(LODWORD(x)); + Put32(HIDWORD(x)); + String s = turtle_stream.FlushStream(); + stat_data_send += s.GetCount(); + LLOG("Sending " << s.GetLength()); + websocket.SendBinary(s); + } +} + +void Ctrl::SyncCaret() +{ + Rect cr = Null; + if(focusCtrl) + cr = (RectC(focusCtrl->caretx, focusCtrl->carety, focusCtrl->caretcx, focusCtrl->caretcy) + + focusCtrl->GetScreenView().TopLeft()) & focusCtrl->GetScreenView(); + if(cr != fbCaretRect) { // TODO: SetCaret should perhaps be called on Ctrl::SetCaret + Put8(SystemDraw::SETCARET); + Put(cr); + fbCaretRect = cr; + } +} + +void Ctrl::PaintScene(SystemDraw& draw) +{ + if(!desktop) + return; + LLOG("@ DoPaint"); + LTIMING("DoPaint paint"); + draw.Init(invalid, DesktopSize.cy); +// draw.Init(DesktopSize); + draw.Begin(); + for(int i = topctrl.GetCount() - 1; i >= 0; i--) { + Rect r = topctrl[i]->GetRect(); + Rect ri = GetClipBound(invalid, r); + LLOG(i << " Window " << r << ", bound " << ri); + if(!IsNull(ri)) { + draw.Clipoff(r); + topctrl[i]->UpdateArea(draw, ri - r.TopLeft()); + draw.End(); + draw.ExcludeClip(r); + Subtract(invalid, r); + } + } + Rect ri = GetClipBound(invalid, DesktopSize); + if(!IsNull(ri)) + desktop->UpdateArea(draw, ri); + invalid.Clear(); + draw.End(); + +// DDUMP(turtle_stream.FlushStream().GetCount()); abort(); +} + +void Ctrl::DoPaint() +{ + if(recieved_update_serial >= update_serial - 1) { // Prevent overloading of transfer + if(invalid.GetCount() && desktop) { + SystemDraw draw; + PaintScene(draw); + } + static int64 prev_cursor_id = Null; + int64 id = fbCursorImage.GetSerialId(); + if(id != prev_cursor_id) { + prev_cursor_id = id; + int64 q = fbCursorImage.GetAuxData(); + if(q) { + Put8(SystemDraw::STD_CURSORIMAGE); + Put8(clamp((int)q, 1, 16)); + } + else { + String h; + Point p = fbCursorImage.GetHotSpot(); + h << "url('data:image/png;base64," + << Base64Encode(PNGEncoder().SaveString(fbCursorImage)) + << "') " << p.x << ' ' << p.y << ", default"; + Put8(SystemDraw::SETCURSORIMAGE); + Put16(0); // _TODO_ Cursor cache + Put(h); + Put8(SystemDraw::CURSORIMAGE); + Put16(0); // _TODO_ Cursor cache + } + } + } +} + +END_UPP_NAMESPACE + +#endif diff --git a/rainbow/Turtle/Server.cpp b/rainbow/Turtle/Server.cpp index e4ea52016..75d69c957 100644 --- a/rainbow/Turtle/Server.cpp +++ b/rainbow/Turtle/Server.cpp @@ -25,35 +25,6 @@ void Ctrl::Broadcast(int signal) { kill(pid[i], signal); #endif } - -void Ctrl::Signal(int signal) -{ -#ifdef PLATFORM_POSIX - int i = 0; - while(i < pid.GetCount()) - if(pid[i] && waitpid(pid[i], 0, WNOHANG | WUNTRACED) > 0) - pid.Remove(i); - else - i++; - switch(signal) { - case SIGTERM: - case SIGHUP: - quit = true; - Broadcast(signal); - break; - case SIGINT: - Broadcast(signal); - exit(0); - break; - case SIGALRM: - if(getpid() != main_pid) { - // "Timeout - session stoped" - exit(0); - } - break; - } -#endif -} String Ctrl::host = "localhost"; int Ctrl::port = 8088; @@ -61,21 +32,14 @@ bool Ctrl::debugmode; String Ctrl::ip = "0.0.0.0"; TcpSocket Ctrl::socket; WebSocket Ctrl::websocket; +int64 Ctrl::update_serial; +int64 Ctrl::recieved_update_serial; bool Ctrl::StartSession() { LLOG("Connect"); #ifdef PLATFORM_POSIX - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = Signal; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGALRM, &sa, NULL); - sigaction(SIGCHLD, &sa, NULL); - main_pid = getpid(); #endif @@ -99,11 +63,19 @@ bool Ctrl::StartSession() } #endif - RLOG("Starting to listen on 8088"); + RLOG("Starting to listen on 8088, pid: " << getpid()); socket.Timeout(2000); // TODO: Not quite ideal way to make quit work.. for(;;) { if(quit) return false; +#ifdef PLATFORM_POSIX + int i = 0; + while(i < pid.GetCount()) + if(pid[i] && waitpid(pid[i], 0, WNOHANG | WUNTRACED) > 0) + pid.Remove(i); + else + i++; +#endif if(server.IsError()) server.ClearError(); if(socket.Accept(server)) { @@ -112,8 +84,10 @@ bool Ctrl::StartSession() RLOG("Accepted, header read"); if(websocket.WebAccept(socket, http)) { // TODO: Connection limit, info #ifdef PLATFORM_POSIX + if(debugmode) + break; int newpid = fork(); - if(debugmode || newpid == 0) + if(newpid == 0) break; else { pid.Add(newpid); @@ -132,7 +106,7 @@ bool Ctrl::StartSession() socket.Close(); } } - RLOG("Connection established with " << socket.GetPeerAddr()); + RLOG("Connection established with " << socket.GetPeerAddr() << ", pid: " << getpid()); server.Close(); if(socket.IsError()) RLOG("CONNECT ERROR: " << socket.GetErrorDesc()); @@ -145,12 +119,18 @@ bool Ctrl::StartSession() #endif ChStdSkin(); - extern Size DesktopSize; extern StaticRect& DesktopRect(); DesktopRect().Color(Cyan()); DesktopRect().SetRect(0, 0, DesktopSize.cx, DesktopSize.cy); SetDesktop(Desktop()); + + stat_started = GetSysTime(); + + while(!IsWaitingEvent()) + GuiSleep(10); + + ProcessEvents(); return true; } diff --git a/rainbow/Turtle/Stream.cpp b/rainbow/Turtle/Stream.cpp index bc92eaf71..0963d1d4a 100644 --- a/rainbow/Turtle/Stream.cpp +++ b/rainbow/Turtle/Stream.cpp @@ -14,11 +14,13 @@ void TurtleStream::Reset() { zlib.Clear(); zlib.Compress(); + hasdata = false; } void TurtleStream::Out(const void *data, dword size) { zlib.Put(data, (int)size); + hasdata = true; } String TurtleStream::FlushStream() diff --git a/rainbow/Turtle/Turtle.h b/rainbow/Turtle/Turtle.h index 6130323c9..802c95ffa 100644 --- a/rainbow/Turtle/Turtle.h +++ b/rainbow/Turtle/Turtle.h @@ -20,11 +20,13 @@ public: private: Zlib zlib; + bool hasdata; void Reset(); public: String FlushStream(); + bool HasData() const { return hasdata; } TurtleStream() { Reset(); } }; @@ -46,24 +48,33 @@ public: SETCURSORIMAGE = 5, CURSORIMAGE = 6, DISABLESENDING = 7, + UPDATESERIAL = 8, + + IMAGEPP = 9, + IMAGENP = 10, + IMAGEPN = 11, + IMAGENN = 12, + + RECTPP = 13, + RECTNP = 14, + RECTPN = 15, + RECTNN = 16, + + SETCARET = 17, }; static Index img_index[3]; + + Point pos; int GetImageI(int from, Index& img_index, int maxcount, const Image& img); int GetImageI(const Image& img); static void ResetI() { for(int i = 0; i < 3; i++) img_index[i].Clear(); } - void Put8(int x) { turtle_stream.Put(x); } - void Put16(int x); - void Put32(int x); - void Put(Point p); - void Put(Size sz); - void Put(const Rect& r); - void Put(const String& s); - bool CanSetSurface() { return false; } static void Flush() {} + + SystemDraw() { pos = Point(0, 0); } }; struct BackDraw__ : public SystemDraw { @@ -114,7 +125,7 @@ class TopWindowFrame; #define GUIPLATFORM_TOPWINDOW_DECLS_INCLUDE -class PrinterJob { // Dummy only... +class PrinterJob { // _TODO_ NilDraw nil; Vector pages; @@ -137,11 +148,6 @@ public: ~PrinterJob() {} }; -void USDLSetup(dword flags); - - -void InitTelpp(); - END_UPP_NAMESPACE #define GUIPLATFORM_INCLUDE_AFTER diff --git a/rainbow/Turtle/Turtle.html b/rainbow/Turtle/Turtle.html index 54c6f4dac..919360f09 100644 --- a/rainbow/Turtle/Turtle.html +++ b/rainbow/Turtle/Turtle.html @@ -40,8 +40,8 @@ U.prototype.k=function(){var b=this.input,d,a;d=this.q.k();this.a=this.q.a;if(th function Log(msg) { -// if (window.console && console.log) -// console.log(msg); //for firebug + if (window.console && console.log) + console.log(msg); //for firebug } function Char(p, ch) @@ -83,19 +83,94 @@ function GetString(p) var SendingEnabled = true; +var posx, posy; +var ctx; + +var caretx = 0, carety = 0, caretcx = 0, caretcy = 0, caretshown = false; +var caretTimerID; + +function InvertRect(x, y, cx, cy) +{ + if(cx <= 0 || cy <= 0) + return; + var imageData = ctx.getImageData(x, y, cx, cy); + var data = imageData.data; + for(var i = 0; i < data.length; i += 4) { + data[i] = 255 - data[i]; + data[i + 1] = 255 - data[i + 1]; + data[i + 2] = 255 - data[i + 2]; + } + ctx.putImageData(imageData, x, y); +} + +function InvertCaret() +{ +// Log("InvertCaret " + caretx + " " + carety + " " + caretcx + " " + caretcy); + if(caretcx >= 0 || caretcy >= 0) + InvertRect(caretx, carety, caretcx, caretcy); +} + +function ClearCaretTimer() +{ + if(caretTimerID != undefined) + clearTimeout(caretTimerID); +} + +function CaretTimer() +{ + ClearCaretTimer(); + caretTimerID = setTimeout(DoCaret, 500); +} + +function DoCaret() +{ + if(caretcx || caretcy) { + InvertCaret(); + caretshown = !caretshown; + CaretTimer(); + } +} + +function InvertShownCaret() +{ + if(caretshown) + InvertCaret(); +} + +function HideCaret(x, y, cx, cy) +{ + return; + if(caretHidden) + return; + if(Math.max(x, caretx) < Math.min(x + cx, caretx + caretcx) && + Math.max(y, carety) < Math.min(y + cy, carety + caretcy)) { + Log("Hiding caret"); + InvertShownCaret(); + caretHidden = true; + } +} + function ProcessDraw(s) { // console.clear(); +// window.document.title = "Processing draw"; + var p = new Object; p.data = s; p.pos = 0; var canvas = document.getElementById("myCanvas"); - var ctx = canvas.getContext("2d"); + + ctx = canvas.getContext("2d"); SendingEnabled = true; + posx = 0; + posy = 0; + + InvertShownCaret(); + while(p.pos < p.data.length) { // Log(p.pos + ": " + p.data[p.pos]); if(Char(p, 0)) { // RECT @@ -110,7 +185,10 @@ function ProcessDraw(s) var c = "rgb(" + r + "," + g + "," + b + ")"; ctx.fillStyle = c; // Log("color: " + c); + HideCaret(x, y, cx, cy); ctx.fillRect(x, y, cx, cy); + posx = x; + posy = y; } else if(Char(p, 3)) { // INVERTRECT @@ -119,14 +197,8 @@ function ProcessDraw(s) var cx = Get16(p); var cy = Get16(p); // Log("irect: " + x + ", " + y + ", " + cx + ", " + cy); - var imageData = ctx.getImageData(x, y, cx, cy); - var data = imageData.data; - for(var i = 0; i < data.length; i += 4) { - data[i] = 255 - data[i]; - data[i + 1] = 255 - data[i + 1]; - data[i + 2] = 255 - data[i + 2]; - } - ctx.putImageData(imageData, x, y); + HideCaret(x, y, cx, cy); + InvertRect(x, y, cx, cy); } else if(Char(p, 2)) { // SETIMAGE @@ -161,8 +233,12 @@ function ProcessDraw(s) // Log("Draw image: " + n); if(window.img_cache[n] == undefined) - alert("Undefined: " + n); + alert("Undefined image: " + n); + HideCaret(x, y, cx, cy); ctx.drawImage(window.img_cache[n], x, y, cx, cy, px, py, cx, cy); + + posx = px; + posy = py; } else if(Char(p, 4)) { // STD_CURSORIMAGE @@ -201,14 +277,93 @@ function ProcessDraw(s) if(Char(p, 7)) { // DISABLESENDING SendingEnabled = true; } + else + if(Char(p, 8)) { // UPDATESERIAL + update_serial_l = Get32(p); + update_serial_h = Get32(p); + ws.send("S " + update_serial_l + " " + update_serial_h + "\n"); + } + else + if(Char(p, 9)) // IMAGEPP + SImage(p, 1, 1); + else + if(Char(p, 10)) // IMAGENP + SImage(p, -1, 1); + else + if(Char(p, 11)) // IMAGEPN + SImage(p, 1, -1); + else + if(Char(p, 12)) // IMAGENN + SImage(p, -1, -1); + else + if(Char(p, 13)) // RECTPP + SRect(p, 1, 1); + else + if(Char(p, 14)) // RECTNP + SRect(p, -1, 1); + else + if(Char(p, 15)) // RECTPN + SRect(p, 1, -1); + else + if(Char(p, 16)) // RECTNN + SRect(p, -1, -1); + else + if(Char(p, 17)) { // SETCARET + caretx = Get16(p); + carety = Get16(p); + caretcx = Get16(p); + caretcy = Get16(p); + caretshown = true; + CaretTimer(); + // Log("SET CARET " + caretx + " " + carety + " " + caretcx + " " + caretcy); + } } + InvertShownCaret(); +// window.document.title = "OK"; if(SendingEnabled && event_queue.length) - ScheduleSend(); + ScheduleSend(); } +function SImage(p, sx, sy) +{ + var px = posx + sx * Get8(p); + var py = posy + sy * Get8(p); + var n = Get16(p); + // Log("Draw opt image: " + px + " " + py + " " + n); + var img = window.img_cache[n]; + if(img == undefined) + alert("Undefined image: " + n); + HideCaret(px, py, img.width, img.height); + ctx.drawImage(window.img_cache[n], px, py); + posx = px; + posy = py; +} + +function SRect(p, sx, sy) +{ + var px = posx + sx * Get8(p); + var py = posy + sy * Get8(p); + var cx = Get8(p); + var cy = Get8(p); + var r = Get8(p); + var g = Get8(p); + var b = Get8(p); + // Log("rect: " + x + ", " + y + ", " + cx + ", " + cy); + var c = "rgb(" + r + "," + g + "," + b + ")"; + ctx.fillStyle = c; + // Log("color: " + c); + HideCaret(x, y, cx, cy); + ctx.fillRect(x, y, cx, cy); + posx = px; + posy = py; +} + + window.img_cache = {}; window.event_queue = "I\n"; window.cursor_cache = {}; +window.update_serial_l = 0; +window.update_serial_h = 0; var canvas = document.getElementById("myCanvas"); @@ -302,9 +457,10 @@ function ScheduleSend() function SendEvents() { if(SendingEnabled) { - if(event_queue.length) - Log("Sending " + event_queue); - ws.send(event_queue); + if(event_queue.length) { + Log(event_queue); + ws.send(event_queue); + } event_queue = ""; if(timerID != undefined) clearTimeout(timerID); @@ -320,7 +476,7 @@ ws.onopen = function() ws.onmessage = function(event) { - Log("onmessage"); +// Log("onmessage"); if(event.data instanceof ArrayBuffer) { var inflate = new Zlib.Inflate(new Uint8Array(event.data)); ProcessDraw(inflate.decompress()); @@ -329,6 +485,7 @@ ws.onmessage = function(event) ws.onclose = function(ev) { + ClearCaretTimer(); alert("Connection closed."); }; diff --git a/rainbow/Turtle/Turtle.upp b/rainbow/Turtle/Turtle.upp index 5270392d4..807db5992 100644 --- a/rainbow/Turtle/Turtle.upp +++ b/rainbow/Turtle/Turtle.upp @@ -19,6 +19,7 @@ file Cursor.cpp, Stream.cpp, Server.cpp, + Output.cpp, Event.cpp, Top.h, TopFrame.cpp, diff --git a/rainbow/Turtle/Wnd.cpp b/rainbow/Turtle/Wnd.cpp index 384a86b1d..0dc89cad5 100644 --- a/rainbow/Turtle/Wnd.cpp +++ b/rainbow/Turtle/Wnd.cpp @@ -12,31 +12,32 @@ NAMESPACE_UPP Ptr Ctrl::desktop; Vector Ctrl::topctrl; -bool Ctrl::invalid; - -bool Ctrl::sdlMouseIsIn; - Point Ctrl::fbCursorPos = Null; Image Ctrl::fbCursorImage; Rect Ctrl::fbCaretRect; int Ctrl::fbCaretTm; bool Ctrl::fbEndSession; -bool Ctrl::SystemCursor; +Vector Ctrl::invalid; + +void Ctrl::InvalidateDesktop() +{ + AddInvalid(desktop->GetSize()); +} void Ctrl::SetDesktop(Ctrl& q) { desktop = &q; desktop->SetOpen(true); desktop->NewTop(); - invalid = true; + InvalidateDesktop(); } void Ctrl::SetDesktopSize(Size sz) { if(desktop) desktop->SetRect(sz); - invalid = true; + InvalidateDesktop(); SyncTopWindows(); } @@ -164,11 +165,11 @@ Rect Ctrl::GetClipBound(const Vector& inv, const Rect& r) return ri; } -void Ctrl::WndUpdate(const Rect&) +void Ctrl::WndUpdate(const Rect& r) { GuiLock __; - Invalidate(); - DoPaint(); +// WndInvalidateRect(r); +// DoPaint(); // TODO } Rect Ctrl::GetWndScreenRect() const @@ -255,7 +256,7 @@ void Ctrl::DestroyWnd() topctrl[i]->WndDestroy(); int q = FindTopCtrl(); if(q >= 0) { - Invalidate(); + AddInvalid(); topctrl.Remove(q); } if(top) { @@ -279,7 +280,7 @@ void Ctrl::PutForeground() { int q = FindTopCtrl(); if(q >= 0) { - Invalidate(); + AddInvalid(); topctrl.Remove(q); topctrl.Add(this); } @@ -355,10 +356,21 @@ bool Ctrl::HasWndCapture() const return captureCtrl && captureCtrl->GetTopCtrl() == this; } -void Ctrl::WndInvalidateRect(const Rect&) +void Ctrl::AddInvalid(const Rect& r_) +{ + Rect r = r_ & Rect(DesktopSize); + if(!IsNull(r)) + AddRefreshRect(invalid, r); +} + +void Ctrl::WndInvalidateRect(const Rect& r) { GuiLock __; - Invalidate(); + int q = FindTopCtrl(); + if(q >= 0) + AddInvalid(r + topctrl[q]->GetRect().TopLeft()); + else + AddInvalid(r); } void Ctrl::WndSetPos(const Rect& rect) @@ -367,14 +379,15 @@ void Ctrl::WndSetPos(const Rect& rect) TopWindow *w = dynamic_cast(this); if(w) w->SyncFrameRect(rect); - Invalidate(); + AddInvalid(); SetWndRect(rect); + AddInvalid(rect); } void Ctrl::WndScrollView(const Rect& r, int dx, int dy) { GuiLock __; - LLOG("ScrollView " << rect); + LLOG("ScrollView " << r << ", size " << GetSize()); WndInvalidateRect(r); } @@ -396,7 +409,7 @@ void Ctrl::PopUp(Ctrl *owner, bool savebits, bool activate, bool dropshadow, boo popup = isopen = true; RefreshLayoutDeep(); if(activate) SetFocusWnd(); - Invalidate(); + AddInvalid(); } Rect Ctrl::GetDefaultWindowRect() { diff --git a/rainbow/WebWord/WebWord.cpp b/rainbow/WebWord/WebWord.cpp index aab55712c..6c77a7346 100644 --- a/rainbow/WebWord/WebWord.cpp +++ b/rainbow/WebWord/WebWord.cpp @@ -1,7 +1,4 @@ -#include -#include - -using namespace Upp; +#include "WebWord.h" #define IMAGECLASS UWordImg #define IMAGEFILE @@ -19,46 +16,6 @@ FileSel& PdfFs() return fs; } -struct UWord : public TopWindow { -public: - virtual void DragAndDrop(Point, PasteClip& d); - virtual void FrameDragAndDrop(Point, PasteClip& d); - - virtual void ShutdownWindow(); - - RichEdit editor; - MenuBar menubar; - ToolBar toolbar; - StatusBar statusbar; - String filename; - - static LRUList& lrufile() { static LRUList l; return l; } - - void Load(const String& filename); - void OpenFile(const String& fn); - void New(); - void Open(); - void Save0(); - void Save(); - void SaveAs(); - void Print(); - void Pdf(); - void About(); - void Destroy(bool shutdown); - void SetBar(); - void FileBar(Bar& bar); - void AboutMenu(Bar& bar); - void MainMenu(Bar& bar); - void MainBar(Bar& bar); - -public: - typedef UWord CLASSNAME; - - static void SerializeApp(Stream& s); - - UWord(); -}; - void UWord::FileBar(Bar& bar) { /* @@ -94,6 +51,36 @@ void UWord::AboutMenu(Bar& bar) bar.Add("About..", THISBACK(About)); } +String FormatSize(int64 n) +{ + if(n < 10000) + return Format("%d B", n); + else + if(n < 10000 * 1024) + return Format("%d.%d KB", n >> 10, (n & 1023) / 103); + else + if(n < I64(10000000) * 1024) + return Format("%d.%d MB", n >> 20, (n & 1023) / 103); + else + return Format("%d.%d GB", n >> 30, (n & 1023) / 103); +} + + +void UWord::ShowInfo() +{ + String s; + s << "Mem " << MemoryUsedKb() << " KB"; + int secs = GetSysTime() - Ctrl::stat_started; + Time tm = Time(1, 1, 1, 0, 0, 0) + secs; + s << ", uptime " << Format("%d:%0d:%02d:%02d", tm - Date(1, 1, 1), tm.hour, tm.minute, tm.second); + s << ", data sent " << FormatSize(Ctrl::stat_data_send); + if(secs) + s << ", average bandwidth " << FormatSize(Ctrl::stat_data_send / secs) << "/s"; + s << ", actual bandwidth " << FormatSize(Ctrl::stat_data_send - sent_prev); + sent_prev = Ctrl::stat_data_send; + statusbar.Set(s); +} + void UWord::MainMenu(Bar& bar) { // bar.Add("File", THISBACK(FileBar)); @@ -248,6 +235,9 @@ UWord::UWord() editor.WhenRefreshBar = THISBACK(SetBar); OpenMain(); ActiveFocus(editor); + + SetTimeCallback(-1000, THISBACK(ShowInfo)); + sent_prev = 0; } void UWord::SerializeApp(Stream& s) @@ -294,7 +284,7 @@ struct EventsWnd : TopWindow { EventsWnd() { Add(l.SizePos()); - SetTimeCallback(-100, THISBACK(Do)); + SetTimeCallback(-1000, THISBACK(Do)); } }; @@ -311,7 +301,8 @@ CONSOLE_APP_MAIN LOG("Session Started"); #ifdef _DEBUG - MemoryLimitKb(10000); + MemoryLimitKb(5000000); + Ctrl::debugmode = true; #endif Ctrl::WhenDisconnect = callback(FinishApp); @@ -324,6 +315,8 @@ CONSOLE_APP_MAIN { SetLanguage(LNG_ENGLISH); SetDefaultCharset(CHARSET_UTF8); + + PromptOK("Session started"); UWordFs().Type("QTF files", "*.qtf") .AllFilesType() diff --git a/rainbow/WebWord/WebWord.h b/rainbow/WebWord/WebWord.h new file mode 100644 index 000000000..66d5c3e25 --- /dev/null +++ b/rainbow/WebWord/WebWord.h @@ -0,0 +1,53 @@ +#ifndef _WebWord_WebWord_h_ +#define _WebWord_WebWord_h_ + +#include +#include + +using namespace Upp; + +struct UWord : public TopWindow { +public: + virtual void DragAndDrop(Point, PasteClip& d); + virtual void FrameDragAndDrop(Point, PasteClip& d); + + virtual void ShutdownWindow(); + + RichEdit editor; + MenuBar menubar; + ToolBar toolbar; + StatusBar statusbar; + String filename; + + int64 sent_prev; + + static LRUList& lrufile() { static LRUList l; return l; } + + void Load(const String& filename); + void OpenFile(const String& fn); + void New(); + void Open(); + void Save0(); + void Save(); + void SaveAs(); + void Print(); + void Pdf(); + void About(); + void Destroy(bool shutdown); + void SetBar(); + void FileBar(Bar& bar); + void AboutMenu(Bar& bar); + void MainMenu(Bar& bar); + void MainBar(Bar& bar); + + void ShowInfo(); + +public: + typedef UWord CLASSNAME; + + static void SerializeApp(Stream& s); + + UWord(); +}; + +#endif diff --git a/rainbow/WebWord/WebWord.upp b/rainbow/WebWord/WebWord.upp index f29bfdce3..ad6ad68e7 100644 --- a/rainbow/WebWord/WebWord.upp +++ b/rainbow/WebWord/WebWord.upp @@ -7,6 +7,7 @@ uses file test.qtf, + WebWord.h, WebWord.cpp; mainconfig diff --git a/rainbow/guiplatform.h b/rainbow/guiplatform.h index f36d0e43a..de15bf1f5 100644 --- a/rainbow/guiplatform.h +++ b/rainbow/guiplatform.h @@ -57,4 +57,5 @@ #define GUIPLATFORM_KEYCODES_INCLUDE //need to make SDL_keysym.h known before K_ enum #define GUIPLATFORM_INCLUDE +#define GUIPLATFORM_NOSCROLL #endif