Home | History | Annotate | Download | only in win_text
      1 
      2 // win_text.cpp : Defines the entry point for the application.
      3 //
      4 //
      5 
      6 #define STRICT
      7 #define WIN32_LEAN_AND_MEAN
      8 #define NOMINMAX
      9 
     10 #include <windows.h>
     11 #include <windowsx.h>
     12 #include <ole2.h>
     13 #include <commctrl.h>
     14 #include <shlwapi.h>
     15 #include <shlobj.h>
     16 #include <shellapi.h>
     17 
     18 #pragma comment(lib, "user32.lib")
     19 #pragma comment(lib, "gdi32.lib")
     20 #pragma comment(lib, "Comctl32.lib")
     21 #pragma comment(lib, "Ole32.lib")
     22 
     23 #include <new>
     24 #include <utility>
     25 #include <memory>
     26 #include <type_traits>
     27 #include <tuple>
     28 #include <list>
     29 
     30 #include "rxcpp/rx.hpp"
     31 // create alias' to simplify code
     32 // these are owned by the user so that
     33 // conflicts can be managed by the user.
     34 namespace rx=rxcpp;
     35 namespace rxsub=rxcpp::subjects;
     36 namespace rxu=rxcpp::util;
     37 
     38 // At this time, RxCpp will fail to compile if the contents
     39 // of the std namespace are merged into the global namespace
     40 // DO NOT USE: 'using namespace std;'
     41 
     42 #include "unwinder.h"
     43 
     44 #include "windows_user.h"
     45 namespace wu = windows_user;
     46 
     47 #include "rx_windows_user.h"
     48 namespace rxwu = rxcpp::windows_user;
     49 
     50 struct RootWindow : public rxwu::rx_messages, public rxwu::enable_send_call<RootWindow, WM_USER+1>
     51 {
     52     // window class
     53     using window_class = wu::window_class<RootWindow>;
     54     static LPCWSTR class_name() {return L"Scratch";}
     55     static void change_class(WNDCLASSEX&) {}
     56 
     57     // createstruct parameter type
     58     using param_type = std::wstring;
     59 
     60     // public methods
     61 
     62     // static methods use a window message per call
     63 
     64     static LRESULT set_title(HWND w, const std::wstring& t) {
     65         return send_call(w, [&](RootWindow& r){
     66             r.set_title(t);
     67             return 0;
     68         });
     69     }
     70     static std::wstring get_title(HWND w) {
     71         std::wstring t;
     72         send_call(w, [&](RootWindow& r){
     73             t = r.get_title();
     74             return 0;
     75         });
     76         return t;
     77     }
     78 
     79     // instance methods are accessed using static send_call(hwnd, [](RootWindow& r){. . .});
     80     // send_call uses one window message, the lambda can call many instance methods.
     81 
     82     void set_title(const std::wstring& t) {
     83         title = t;
     84     }
     85     const std::wstring& get_title() {
     86         return title;
     87     }
     88 
     89     // lifetime
     90 
     91     // called during WM_NCDESTROY
     92     ~RootWindow() {
     93         PostQuitMessage(0);
     94     }
     95 
     96     // called during WM_NCCREATE
     97     RootWindow(HWND w, LPCREATESTRUCT, param_type* title)
     98         : window(w)
     99         , title(title ? *title : L"RootWindow")
    100         , position{40, 10} {
    101         // listen for the following messages
    102         OnPaint();
    103         OnPrintClient();
    104         OnKeyDown();
    105         OnMovesWhileLButtonDown();
    106     }
    107 
    108 private:
    109     // implementation
    110 
    111     HWND window;
    112     std::wstring title;
    113     POINTS position;
    114 
    115     void PaintContent(PAINTSTRUCT& ps) {
    116         RECT rect;
    117         GetClientRect (window, &rect) ;
    118         SetTextColor(ps.hdc, 0x00000000);
    119         SetBkMode(ps.hdc,TRANSPARENT);
    120         rect.left=position.x;
    121         rect.top=position.y;
    122         DrawText( ps.hdc, title.c_str(), -1, &rect, DT_SINGLELINE | DT_NOCLIP  ) ;
    123     }
    124 
    125     void OnKeyDown() {
    126         messages<WM_KEYDOWN>().
    127         subscribe([this](auto m) {
    128             m.handled(); // skip DefWindowProc
    129 
    130             MessageBox(window, L"KeyDown", L"RootWindow", MB_OK);
    131             // NOTE: MessageBox pumps messages, but this subscription only
    132             // receives messages if it is suspended by 'for await', so any
    133             // WM_KEYDOWN arriving while the message box is up is not delivered.
    134             // the other subscriptions will receive messages.
    135         });
    136     }
    137 
    138     void OnMovesWhileLButtonDown() {
    139 
    140         auto moves_while_lbutton_down = messages<WM_LBUTTONDOWN>().
    141             map(
    142                 [this](auto m) {
    143                     m.handled(); // skip DefWindowProc
    144 
    145                     return this->messages<WM_MOUSEMOVE>().
    146                         take_until(this->messages<WM_LBUTTONUP>());
    147                 }).
    148             merge();
    149 
    150         moves_while_lbutton_down.
    151         subscribe([this](auto m) {
    152             m.handled(); // skip DefWindowProc
    153 
    154             position = MAKEPOINTS(m.lParam);
    155             InvalidateRect(window, nullptr, true);
    156         });
    157     }
    158 
    159     void OnPaint() {
    160         messages<WM_PAINT>().
    161         subscribe([this](auto m) {
    162             m.handled(); // skip DefWindowProc
    163 
    164             PAINTSTRUCT ps;
    165             BeginPaint(window, &ps);
    166             PaintContent(ps);
    167             EndPaint(window, &ps);
    168         });
    169     }
    170 
    171     void OnPrintClient() {
    172         messages<WM_PRINTCLIENT, HDC>().
    173         subscribe([this](auto m) {
    174             m.handled(); // skip DefWindowProc
    175 
    176             PAINTSTRUCT ps;
    177             ps.hdc = m.wParam;
    178             GetClientRect(window, &ps.rcPaint);
    179             PaintContent(ps);
    180         });
    181     }
    182 };
    183 
    184 int PASCAL
    185 wWinMain(HINSTANCE hinst, HINSTANCE, LPWSTR, int nShowCmd)
    186 {
    187     HRESULT hr = S_OK;
    188 
    189     hr = CoInitialize(NULL);
    190     if (FAILED(hr))
    191     {
    192         return FALSE;
    193     }
    194     ON_UNWIND_AUTO([&]{CoUninitialize();});
    195 
    196     InitCommonControls();
    197 
    198     RootWindow::window_class::Register();
    199 
    200     LONG winerror = ERROR_SUCCESS;
    201 
    202     std::wstring title{L"Scratch App - RootWindow"};
    203 
    204     // normal create window call, just takes the class name and optional create parameters
    205     HWND window = CreateWindow(
    206         RootWindow::window_class::Name(), title.c_str(),
    207         WS_OVERLAPPEDWINDOW,
    208         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    209         NULL, NULL,
    210         hinst,
    211         &title);
    212     if (!window) {winerror = GetLastError();}
    213 
    214     if (!!winerror || !window)
    215     {
    216         return winerror;
    217     }
    218 
    219     ShowWindow(window, nShowCmd);
    220 
    221     // interact with window safely on the UI thread from another thread
    222     auto settitle = std::async([window](){
    223 
    224         // by static method (two SendMessage)
    225         RootWindow::set_title(window, L"SET_TITLE! " + RootWindow::get_title(window));
    226 
    227         // or multiple instance methods (one SendMessage)
    228         RootWindow::send_call(window, [](RootWindow& r){
    229             r.set_title(L"SEND_CALL! " + r.get_title());
    230             return 0;
    231         });
    232     });
    233 
    234     MSG msg = {};
    235     while (GetMessage(&msg, NULL, 0, 0))
    236     {
    237         TranslateMessage(&msg);
    238         DispatchMessage(&msg);
    239     }
    240 
    241     settitle.get();
    242 
    243     return 0;
    244 }
    245