const char *TcpSocketErrorDesc(int code) { static Tuple2<int, const char *> err[] = { { WSAEINTR, "Interrupted function call." }, { WSAEACCES, "Permission denied." }, { WSAEFAULT, "Bad address." }, { WSAEINVAL, "Invalid argument." }, { WSAEMFILE, "Too many open files." }, { WSAEWOULDBLOCK, "Resource temporarily unavailable." }, { WSAEINPROGRESS, "Operation now in progress." }, { WSAEALREADY, "Operation already in progress." }, { WSAENOTSOCK, "TcpSocket operation on nonsocket." }, { WSAEDESTADDRREQ, "Destination address required." }, { WSAEMSGSIZE, "Message too long." }, { WSAEPROTOTYPE, "Protocol wrong type for socket." }, { WSAENOPROTOOPT, "Bad protocol option." }, { WSAEPROTONOSUPPORT, "Protocol not supported." }, { WSAESOCKTNOSUPPORT, "TcpSocket type not supported." }, { WSAEOPNOTSUPP, "Operation not supported." }, { WSAEPFNOSUPPORT, "Protocol family not supported." }, { WSAEAFNOSUPPORT, "Address family not supported by protocol family." }, { WSAEADDRINUSE, "Address already in use." }, { WSAEADDRNOTAVAIL, "Cannot assign requested address." }, { WSAENETDOWN, "Network is down." }, { WSAENETUNREACH, "Network is unreachable." }, { WSAENETRESET, "Network dropped connection on reset." }, { WSAECONNABORTED, "Software caused connection abort." }, { WSAECONNRESET, "Connection reset by peer." }, { WSAENOBUFS, "No buffer space available." }, { WSAEISCONN, "TcpSocket is already connected." }, { WSAENOTCONN, "TcpSocket is not connected." }, { WSAESHUTDOWN, "Cannot send after socket shutdown." }, { WSAETIMEDOUT, "Connection timed out." }, { WSAECONNREFUSED, "Connection refused." }, { WSAEHOSTDOWN, "Host is down." }, { WSAEHOSTUNREACH, "No route to host." }, { WSAEPROCLIM, "Too many processes." }, { WSASYSNOTREADY, "Network subsystem is unavailable." }, { WSAVERNOTSUPPORTED, "Winsock.dll version out of range." }, { WSANOTINITIALISED, "Successful WSAStartup not yet performed." }, { WSAEDISCON, "Graceful shutdown in progress." }, { WSATYPE_NOT_FOUND, "Class type not found." }, { WSAHOST_NOT_FOUND, "Host not found." }, { WSATRY_AGAIN, "Nonauthoritative host not found." }, { WSANO_RECOVERY, "This is a nonrecoverable error." }, { WSANO_DATA, "Valid name, no data record of requested type." }, { WSASYSCALLFAILURE, "System call failure." }, }; const Tuple2<int, const char *> *x = FindTuple(err, __countof(err), code); return x ? x->b : "Unknown error code."; }
gboolean Ctrl::GtkEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data) { GuiLock __; GdkEventKey *key; bool pressed = false; bool retval = true; Value value; Ctrl *p = GetTopCtrlFromId(user_data); #ifdef LOG_EVENTS String ev = "?"; Tuple2<int, const char *> *f = FindTuple(xEvent, __countof(xEvent), event->type); if(f) ev = f->b; LOG(rmsecs() << " FETCH EVENT " << ev << " ctrl: " << Name(p)); #endif switch(event->type) { case GDK_EXPOSE: case GDK_DAMAGE: if(p) { #ifdef LOG_EVENTS TimeStop tm; #endif p->fullrefresh = false; GdkEventExpose *e = (GdkEventExpose *)event; SystemDraw w(gdk_cairo_create(p->gdk()), p->gdk()); painting = true; Rect r = RectC(e->area.x, e->area.y, e->area.width, e->area.height); w.SetInvalid(e->region); w.Clip(r); p->UpdateArea(w, r); w.End(); cairo_destroy(w); if(p->top->dr) DrawDragRect(*p, *p->top->dr); painting = false; #ifdef LOG_EVENTS LOG("* " << ev << " elapsed " << tm); #endif } return true; case GDK_DELETE: break; case GDK_FOCUS_CHANGE: if(p) { if(((GdkEventFocus *)event)->in) gtk_im_context_focus_in(p->top->im_context); else gtk_im_context_focus_out(p->top->im_context); AddEvent(user_data, EVENT_NONE, value, event); } return false; case GDK_LEAVE_NOTIFY: case GDK_MOTION_NOTIFY: break; case GDK_BUTTON_PRESS: value = DoButtonEvent(event, true); if(IsNull(value)) return false; break; case GDK_2BUTTON_PRESS: value = DoButtonEvent(event, true); if(IsNull(value)) return false; break; case GDK_BUTTON_RELEASE: value = DoButtonEvent(event, false); if(IsNull(value)) return false; break; case GDK_SCROLL: { GdkEventScroll *e = (GdkEventScroll *)event; value = findarg(e->direction, GDK_SCROLL_UP, GDK_SCROLL_LEFT) < 0 ? -120 : 120; break; } case GDK_KEY_PRESS: pressed = true; case GDK_KEY_RELEASE: key = (GdkEventKey *)event; value = (int) key->keyval; if(pressed) { p = GetTopCtrlFromId(user_data); if(p && gtk_im_context_filter_keypress(p->top->im_context, key)) return true; } break; case GDK_CONFIGURE: { retval = false; GdkEventConfigure *e = (GdkEventConfigure *)event; value = RectC(e->x, e->y, e->width, e->height); LLOG("GDK_CONFIGURE " << value); break; } default: return false; } AddEvent(user_data, event->type, value, event); return retval; }
void TupleTutorial() { /// . Tuples /// Template class `Tuple` allows combining 2-4 values with /// different types. These are principally similar to `std::tuple`, with some advantages. /// Unlike `std::tuple`, individual elements are directly accessible as member variables /// `a`..`d`, `Tuple` supports persistent storage patterns (`Serialize`, `Jsonize`, `Xmlize`), hash /// code (`GetHashValue`), conversion to `String` and Value conversions. /// To create a `Tuple` value, you can use the `MakeTuple` function. Tuple<int, String, String> x = MakeTuple(12, "hello", "world"); /// Individual values are accessible as members `a` .. `d`: DUMP(x.a); DUMP(x.b); DUMP(x.c); /// Or using `Get`: DUMP(x.Get<1>()); DUMP(x.Get<int>()); /// As long as all individual types have conversion to `String` (`AsString`), the tuple also /// has such conversion and thus can e.g. be easily logged: DUMP(x); /// As long as individual types have defined `GetHashValue`, so does `Tuple`: DUMP(GetHashValue(x)); /// As long as individual types have defined `operator==`, `Tuple` has defined `operator==` /// and `operator!=`: Tuple<int, String, String> y = x; DUMP(x == y); DUMP(x != y); y.a++; DUMP(x == y); DUMP(x != y); /// As long as all individual types have defined `SgnCompare`, /// Tuple has SgnCompare, Compare method and operators <, <=, >, >=: DUMP(x.Compare(y)); DUMP(SgnCompare(x, y)); DUMP(x < y); /// GetCount returns the width of `Tuple`: DUMP(x.GetCount()); /// Elements that are directly convertible with `Value` can be 'Get'/'Set': for(int i = 0; i < x.GetCount(); i++) DUMP(x.Get(i)); /// x.Set(1, "Hi"); DUMP(x); /// As long as all individual types are convertible with `Value`, you can convert Tuple to /// `ValueArray` and back: ValueArray va = x.GetArray(); DUMP(va); va.Set(2, "Joe"); x.SetArray(va); /// It is OK to assign `Tuple` to `Tuple` with different individual types, as long as types /// are directly convertible: Tuple<double, String, String> d = x; DUMP(d); /// Tie can be used to assign tuple to l-values: int i; String s1, s2; Tie(i, s1, s2) = x; DUMP(i); DUMP(s1); DUMP(s2); /// U++ Tuples are carefully designed as POD type, which allows POD arrays to be intialized /// with classic C style: static Tuple2<int, const char *> map[] = { { 1, "one" }, { 2, "one" }, { 3, "one" }, }; /// Simple FindTuple template function is provided to search for tuple based on the first /// value (`a`) (linear O(n) search): DUMP(FindTuple(map, __countof(map), 3)->b); /// }
void Ctrl::Proc() { #ifdef LOG_EVENTS String ev = "?"; Tuple2<int, const char *> *f = FindTuple(xEvent, __countof(xEvent), CurrentEvent.type); if(f) ev = f->b; LOG(rmsecs() << " PROCESS EVENT " << Upp::Name(this) << " " << ev); ProcStop tm; tm.ev = ev; #endif if(!IsOpen()) return; Ptr<Ctrl> _this = this; bool pressed = false; int kv; static int clicktime = msecs() - 100000; switch(CurrentEvent.type) { case GDK_MOTION_NOTIFY: { GtkMouseEvent(MOUSEMOVE, MOUSEMOVE, 0); break; } case GDK_BUTTON_PRESS: if(!HasWndFocus() && !popup) SetWndFocus(); ClickActivateWnd(); if(ignoremouseup) { KillRepeat(); ignoreclick = false; ignoremouseup = false; } if(!ignoreclick) GtkButtonEvent(msecs(clicktime) < 250 ? DOUBLE : DOWN); clicktime = msecs(); break; /* case GDK_2BUTTON_PRESS: if(!ignoreclick) GtkButtonEvent(DOUBLE); break; */ case GDK_BUTTON_RELEASE: if(ignoreclick) EndIgnore(); else GtkButtonEvent(UP); break; case GDK_SCROLL: { GtkMouseEvent(MOUSEWHEEL, MOUSEWHEEL, CurrentEvent.value); break; } case GDK_KEY_PRESS: pressed = true; case GDK_KEY_RELEASE: kv = CurrentEvent.value; if(kv >= 0 && kv < 65536) { LLOG("keyval " << FormatIntHex(kv) << ' ' << (char)kv); if(kv >= 'a' && kv <= 'z') kv = kv - 'a' + 'A'; static Tuple2<int, int> cv[] = { { GDKEY(BackSpace), K_BACKSPACE }, { GDKEY(Tab), K_TAB }, { GDKEY(ISO_Left_Tab), K_TAB }, { GDKEY(Return), K_ENTER }, { GDKEY(Escape), K_ESCAPE }, { GDKEY(space), K_SPACE }, { GDKEY(Control_L), K_CTRL_KEY }, { GDKEY(Control_R), K_CTRL_KEY }, { GDKEY(Shift_L), K_SHIFT_KEY }, { GDKEY(Shift_R), K_SHIFT_KEY }, { GDKEY(Alt_L), K_ALT_KEY }, { GDKEY(Alt_R), K_ALT_KEY }, { GDKEY(KP_Space), K_SPACE }, { GDKEY(KP_Tab), K_TAB }, { GDKEY(KP_Enter), K_ENTER }, { GDKEY(KP_F1), K_F1 }, { GDKEY(KP_F2), K_F2 }, { GDKEY(KP_F3), K_F3 }, { GDKEY(KP_F4), K_F4 }, { GDKEY(KP_Home), K_HOME }, { GDKEY(KP_Left), K_LEFT }, { GDKEY(KP_Up), K_UP }, { GDKEY(KP_Right), K_RIGHT }, { GDKEY(KP_Down), K_DOWN }, { GDKEY(KP_Page_Up), K_PAGEUP }, { GDKEY(KP_Page_Down), K_PAGEDOWN }, { GDKEY(KP_End), K_END }, { GDKEY(KP_Begin), K_HOME }, { GDKEY(KP_Insert), K_INSERT }, { GDKEY(KP_Delete), K_DELETE }, }; Tuple2<int, int> *x = FindTuple(cv, __countof(cv), kv); if(x) kv = x->b; else kv += K_DELTA; if(GetShift() && kv != K_SHIFT_KEY) kv |= K_SHIFT; if(GetCtrl() && kv != K_CTRL_KEY) kv |= K_CTRL; if(GetAlt() && kv != K_ALT_KEY) kv |= K_ALT; LLOG(GetKeyDesc(kv) << ", pressed: " << pressed << ", count: " << CurrentEvent.count); #ifdef GDK_WINDOWING_X11 if(pressed) for(int i = 0; i < hotkey.GetCount(); i++) { if(hotkey[i] && keyhot[i] == (dword)kv) { hotkey[i](); return; } } #endif DispatchKey(!pressed * K_KEYUP + kv, CurrentEvent.count); } break; case EVENT_TEXT: { WString h = CurrentEvent.value; for(int i = 0; i < h.GetCount(); i++) // TODO: Add compression DispatchKey(h[i], 1); break; } case GDK_DELETE: { TopWindow *w = dynamic_cast<TopWindow *>(this); if(w) { if(IsEnabled()) { IgnoreMouseUp(); w->WhenClose(); } } return; } case GDK_CONFIGURE: { Rect rect = CurrentEvent.value; if(GetRect() != rect) SetWndRect(rect); } break; default: return; } if(_this) _this->PostInput(); }