#include "Local.h" #ifdef GUI_TURTLE namespace Upp { #define LLOG(x) // LLOG(x) #define LDUMP(x) // RDUMP(x) #define LTIMING(x) TurtleStream Ctrl::turtle_stream; 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.SetDataFlag(); turtle_stream.Put(s); } void Turtle_PutLink(const String& link) { Ctrl::Put8(Ctrl::OPENLINK); Ctrl::Put(link); } void Ctrl::Output() { if(turtle_stream.HasData()) { websocket.SendBinary(ZCompress(String(DISABLESENDING, 1))); // Do not send events until data transfered and processed int64 x = ++update_serial; if(IsNull(serial_time0)) { serial_time0 = msecs(); serial_0 = update_serial; } Put8(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::TimerAndPaint() { LLOG("TimerAndPaint " << msecs()); TimerProc(msecs()); DefferedFocusSync(); SyncCaret(); SyncTopWindows(); SweepMkImageCache(); DoPaint(); Output(); } 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(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::SetMouseCursor(const Image& image) { GuiLock __; if(image.GetSerialId() != fbCursorImage.GetSerialId()) { fbCursorImage = image; fbCursorPos = Null; } } void Ctrl::SyncClient() { while(recieved_update_serial < update_serial) { GuiSleep(10); IsWaitingEvent(); } } void Ctrl::DoPaint() { if(recieved_update_serial < update_serial - 1) // Falling behind, wait SyncClient(); 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(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(SETCURSORIMAGE); Put16(0); // _TODO_ Cursor cache Put(h); Put8(MOUSECURSOR); Put16(0); // _TODO_ Cursor cache } } } } #endif