reflexion 0.5.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.doc/ext/reflex/application.cpp +56 -7
- data/.doc/ext/reflex/capture_event.cpp +1 -1
- data/.doc/ext/reflex/chase_constraint.cpp +84 -0
- data/.doc/ext/reflex/clipboard.cpp +65 -0
- data/.doc/ext/reflex/color_event.cpp +76 -0
- data/.doc/ext/reflex/color_picker.cpp +113 -0
- data/.doc/ext/reflex/constraint.cpp +135 -0
- data/.doc/ext/reflex/contact_event.cpp +1 -1
- data/.doc/ext/reflex/control_change_event.cpp +1 -1
- data/.doc/ext/reflex/device.cpp +1 -1
- data/.doc/ext/reflex/device_event.cpp +1 -1
- data/.doc/ext/reflex/draw_event.cpp +1 -1
- data/.doc/ext/reflex/ellipse_shape.cpp +1 -1
- data/.doc/ext/reflex/event.cpp +1 -1
- data/.doc/ext/reflex/file_dialog.cpp +181 -0
- data/.doc/ext/reflex/file_event.cpp +103 -0
- data/.doc/ext/reflex/filter.cpp +1 -1
- data/.doc/ext/reflex/focus_event.cpp +1 -1
- data/.doc/ext/reflex/frame_event.cpp +1 -1
- data/.doc/ext/reflex/gamepad.cpp +48 -0
- data/.doc/ext/reflex/image_view.cpp +1 -1
- data/.doc/ext/reflex/key_event.cpp +1 -274
- data/.doc/ext/reflex/line_shape.cpp +1 -1
- data/.doc/ext/reflex/link_constraint.cpp +178 -0
- data/.doc/ext/reflex/menu.cpp +303 -0
- data/.doc/ext/reflex/midi.cpp +9 -2
- data/.doc/ext/reflex/midi_event.cpp +1 -1
- data/.doc/ext/reflex/motion_event.cpp +1 -1
- data/.doc/ext/reflex/native.cpp +40 -10
- data/.doc/ext/reflex/note_event.cpp +1 -1
- data/.doc/ext/reflex/pin.cpp +156 -0
- data/.doc/ext/reflex/pointer.cpp +3 -1
- data/.doc/ext/reflex/pointer_event.cpp +3 -3
- data/.doc/ext/reflex/polygon_shape.cpp +1 -1
- data/.doc/ext/reflex/rect_shape.cpp +1 -1
- data/.doc/ext/reflex/reflex.cpp +606 -237
- data/.doc/ext/reflex/screen.cpp +27 -1
- data/.doc/ext/reflex/scroll_event.cpp +1 -1
- data/.doc/ext/reflex/selector.cpp +5 -5
- data/.doc/ext/reflex/shape.cpp +1 -1
- data/.doc/ext/reflex/snap_constraint.cpp +125 -0
- data/.doc/ext/reflex/style.cpp +1 -1
- data/.doc/ext/reflex/style_length.cpp +4 -3
- data/.doc/ext/reflex/text_event.cpp +104 -0
- data/.doc/ext/reflex/timer.cpp +1 -1
- data/.doc/ext/reflex/timer_event.cpp +1 -1
- data/.doc/ext/reflex/update_event.cpp +1 -1
- data/.doc/ext/reflex/view.cpp +206 -79
- data/.doc/ext/reflex/wheel_constraint.cpp +142 -0
- data/.doc/ext/reflex/wheel_event.cpp +1 -1
- data/.doc/ext/reflex/window.cpp +282 -31
- data/.github/workflows/release-gem.yml +2 -40
- data/.github/workflows/tag.yml +5 -28
- data/.github/workflows/test.yml +1 -28
- data/ChangeLog.md +79 -0
- data/Gemfile.lock +13 -8
- data/README.md +1 -0
- data/Rakefile +13 -2
- data/Reflex.podspec +2 -2
- data/VERSION +1 -1
- data/ext/reflex/application.cpp +62 -7
- data/ext/reflex/capture_event.cpp +1 -1
- data/ext/reflex/chase_constraint.cpp +89 -0
- data/ext/reflex/clipboard.cpp +69 -0
- data/ext/reflex/color_event.cpp +80 -0
- data/ext/reflex/color_picker.cpp +121 -0
- data/ext/reflex/constraint.cpp +146 -0
- data/ext/reflex/contact_event.cpp +1 -1
- data/ext/reflex/control_change_event.cpp +1 -1
- data/ext/reflex/device.cpp +1 -1
- data/ext/reflex/device_event.cpp +1 -1
- data/ext/reflex/draw_event.cpp +1 -1
- data/ext/reflex/ellipse_shape.cpp +1 -1
- data/ext/reflex/event.cpp +1 -1
- data/ext/reflex/extconf.rb +4 -2
- data/ext/reflex/file_dialog.cpp +194 -0
- data/ext/reflex/file_event.cpp +108 -0
- data/ext/reflex/filter.cpp +1 -1
- data/ext/reflex/focus_event.cpp +1 -1
- data/ext/reflex/frame_event.cpp +1 -1
- data/ext/reflex/gamepad.cpp +50 -0
- data/ext/reflex/image_view.cpp +1 -1
- data/ext/reflex/key_event.cpp +1 -275
- data/ext/reflex/line_shape.cpp +1 -1
- data/ext/reflex/link_constraint.cpp +194 -0
- data/ext/reflex/menu.cpp +331 -0
- data/ext/reflex/midi.cpp +11 -3
- data/ext/reflex/midi_event.cpp +1 -1
- data/ext/reflex/motion_event.cpp +1 -1
- data/ext/reflex/native.cpp +40 -10
- data/ext/reflex/note_event.cpp +1 -1
- data/ext/reflex/pin.cpp +165 -0
- data/ext/reflex/pointer.cpp +3 -1
- data/ext/reflex/pointer_event.cpp +3 -3
- data/ext/reflex/polygon_shape.cpp +1 -1
- data/ext/reflex/rect_shape.cpp +1 -1
- data/ext/reflex/reflex.cpp +608 -237
- data/ext/reflex/screen.cpp +31 -2
- data/ext/reflex/scroll_event.cpp +1 -1
- data/ext/reflex/selector.cpp +5 -5
- data/ext/reflex/selector.h +10 -10
- data/ext/reflex/shape.cpp +1 -1
- data/ext/reflex/snap_constraint.cpp +135 -0
- data/ext/reflex/style.cpp +1 -1
- data/ext/reflex/style_length.cpp +4 -3
- data/ext/reflex/text_event.cpp +111 -0
- data/ext/reflex/timer.cpp +1 -1
- data/ext/reflex/timer_event.cpp +1 -1
- data/ext/reflex/update_event.cpp +1 -1
- data/ext/reflex/view.cpp +236 -96
- data/ext/reflex/wheel_constraint.cpp +154 -0
- data/ext/reflex/wheel_event.cpp +1 -1
- data/ext/reflex/window.cpp +318 -40
- data/include/reflex/application.h +19 -0
- data/include/reflex/clipboard.h +53 -0
- data/include/reflex/color_picker.h +65 -0
- data/include/reflex/constraint.h +275 -0
- data/include/reflex/defs.h +204 -195
- data/include/reflex/event.h +180 -88
- data/include/reflex/file_dialog.h +73 -0
- data/include/reflex/gamepad.h +3 -0
- data/include/reflex/menu.h +120 -0
- data/include/reflex/midi.h +3 -0
- data/include/reflex/pin.h +68 -0
- data/include/reflex/pointer.h +4 -0
- data/include/reflex/reflex.h +2 -0
- data/include/reflex/ruby/application.h +6 -1
- data/include/reflex/ruby/clipboard.h +23 -0
- data/include/reflex/ruby/color_picker.h +89 -0
- data/include/reflex/ruby/constraint.h +94 -0
- data/include/reflex/ruby/event.h +62 -29
- data/include/reflex/ruby/file_dialog.h +89 -0
- data/include/reflex/ruby/gamepad.h +46 -0
- data/include/reflex/ruby/menu.h +103 -0
- data/include/reflex/ruby/pin.h +40 -0
- data/include/reflex/ruby/reflex.h +3 -0
- data/include/reflex/ruby/view.h +123 -39
- data/include/reflex/ruby/window.h +96 -19
- data/include/reflex/ruby.h +3 -0
- data/include/reflex/screen.h +11 -2
- data/include/reflex/view.h +66 -27
- data/include/reflex/window.h +57 -12
- data/include/reflex.h +8 -0
- data/lib/reflex/application.rb +5 -5
- data/lib/reflex/autoinit.rb +3 -1
- data/lib/reflex/button.rb +3 -3
- data/lib/reflex/chase_constraint.rb +15 -0
- data/lib/reflex/clipboard.rb +19 -0
- data/lib/reflex/color_event.rb +16 -0
- data/lib/reflex/color_picker.rb +45 -0
- data/lib/reflex/constraint.rb +29 -0
- data/lib/reflex/control_change_event.rb +17 -0
- data/lib/reflex/extension.rb +1 -1
- data/lib/reflex/file_dialog.rb +70 -0
- data/lib/reflex/file_event.rb +37 -0
- data/lib/reflex/helper.rb +79 -0
- data/lib/reflex/key_event.rb +14 -14
- data/lib/reflex/link_constraint.rb +31 -0
- data/lib/reflex/menu.rb +92 -0
- data/lib/reflex/model.rb +19 -19
- data/lib/reflex/note_event.rb +1 -1
- data/lib/reflex/pin.rb +39 -0
- data/lib/reflex/pointer.rb +30 -1
- data/lib/reflex/pointer_event.rb +13 -2
- data/lib/reflex/reflex.rb +5 -0
- data/lib/reflex/shape.rb +14 -14
- data/lib/reflex/snap_constraint.rb +28 -0
- data/lib/reflex/style.rb +16 -16
- data/lib/reflex/text_event.rb +40 -0
- data/lib/reflex/timer.rb +3 -3
- data/lib/reflex/view.rb +85 -18
- data/lib/reflex/wheel_constraint.rb +28 -0
- data/lib/reflex/wheel_event.rb +19 -1
- data/lib/reflex/window.rb +25 -13
- data/lib/reflex.rb +23 -8
- data/pod.rake +1 -1
- data/reflex.gemspec +4 -4
- data/samples/constraint.rb +152 -0
- data/samples/ime.rb +100 -0
- data/samples/ios/hello/hello.xcodeproj/project.pbxproj +236 -224
- data/samples/menu.rb +32 -0
- data/samples/model.rb +3 -3
- data/samples/test/alert.rb +93 -0
- data/samples/test/always_on.rb +76 -0
- data/samples/test/app_background.rb +51 -0
- data/samples/test/boundary.rb +75 -0
- data/samples/test/callback_exception.rb +101 -0
- data/samples/test/cancel.rb +53 -0
- data/samples/test/color_picker.rb +63 -0
- data/samples/test/file_dialog.rb +102 -0
- data/samples/window_style.rb +156 -0
- data/src/application.cpp +180 -20
- data/src/application.h +95 -5
- data/src/clipboard.cpp +81 -0
- data/src/color_picker.cpp +113 -0
- data/src/color_picker.h +36 -0
- data/src/constraint.cpp +1662 -0
- data/src/constraint.h +64 -0
- data/src/event.cpp +416 -252
- data/src/event.h +13 -2
- data/src/file_dialog.cpp +163 -0
- data/src/file_dialog.h +52 -0
- data/src/gamepad.cpp +42 -5
- data/src/gamepad.h +4 -0
- data/src/ios/app_delegate.mm +5 -3
- data/src/ios/application.mm +29 -0
- data/src/ios/clipboard.mm +44 -0
- data/src/ios/color_picker.mm +19 -0
- data/src/ios/event.h +6 -2
- data/src/ios/event.mm +31 -12
- data/src/ios/file_dialog.mm +21 -0
- data/src/ios/gamepad.mm +4 -4
- data/src/ios/menu.mm +41 -0
- data/src/ios/reflex.mm +8 -0
- data/src/ios/screen.mm +26 -0
- data/src/ios/view_controller.mm +47 -42
- data/src/ios/window.mm +44 -9
- data/src/menu.cpp +387 -0
- data/src/menu.h +81 -0
- data/src/midi.cpp +61 -31
- data/src/osx/app_delegate.h +4 -0
- data/src/osx/app_delegate.mm +168 -139
- data/src/osx/application.mm +103 -5
- data/src/osx/clipboard.mm +45 -0
- data/src/osx/color_picker.mm +112 -0
- data/src/osx/event.h +10 -0
- data/src/osx/event.mm +114 -30
- data/src/osx/file_dialog.mm +168 -0
- data/src/osx/gamepad.mm +2 -2
- data/src/osx/gamepad_hid.mm +1 -1
- data/src/osx/menu.h +25 -0
- data/src/osx/menu.mm +516 -0
- data/src/osx/native_window.h +16 -2
- data/src/osx/native_window.mm +141 -57
- data/src/osx/opengl_view.h +2 -1
- data/src/osx/opengl_view.mm +229 -37
- data/src/osx/reflex.mm +38 -0
- data/src/osx/screen.mm +36 -0
- data/src/osx/window.mm +117 -24
- data/src/pin.cpp +137 -0
- data/src/pointer.cpp +36 -16
- data/src/pointer.h +10 -0
- data/src/rays.h +46 -0
- data/src/sdl/application.cpp +73 -8
- data/src/sdl/clipboard.cpp +39 -0
- data/src/sdl/color_picker.cpp +18 -0
- data/src/sdl/event.cpp +44 -6
- data/src/sdl/event.h +18 -3
- data/src/sdl/file_dialog.cpp +20 -0
- data/src/sdl/gamepad.cpp +3 -7
- data/src/sdl/menu.cpp +40 -0
- data/src/sdl/reflex.cpp +20 -0
- data/src/sdl/screen.cpp +36 -0
- data/src/sdl/window.cpp +168 -37
- data/src/shape.cpp +15 -10
- data/src/view.cpp +583 -233
- data/src/view.h +22 -4
- data/src/vk.h +416 -0
- data/src/win32/application.cpp +167 -12
- data/src/win32/application.h +20 -0
- data/src/win32/clipboard.cpp +210 -0
- data/src/win32/color_picker.cpp +82 -0
- data/src/win32/event.cpp +123 -11
- data/src/win32/event.h +22 -3
- data/src/win32/file_dialog.cpp +226 -0
- data/src/win32/gamepad.cpp +9 -2
- data/src/win32/menu.cpp +490 -0
- data/src/win32/menu.h +35 -0
- data/src/win32/opengl.cpp +2 -9
- data/src/win32/reflex.cpp +44 -3
- data/src/win32/screen.cpp +164 -3
- data/src/win32/screen.h +8 -0
- data/src/win32/tray.cpp +191 -0
- data/src/win32/tray.h +22 -0
- data/src/win32/vk.cpp +11 -0
- data/src/win32/window.cpp +858 -135
- data/src/win32/window.h +9 -0
- data/src/window.cpp +929 -183
- data/src/window.h +77 -33
- data/src/world.cpp +86 -15
- data/src/world.h +9 -2
- data/test/helper.rb +24 -0
- data/test/test_application.rb +101 -1
- data/test/test_chase_constraint.rb +122 -0
- data/test/test_clipboard.rb +54 -0
- data/test/test_color_event.rb +36 -0
- data/test/test_color_picker.rb +62 -0
- data/test/test_constraint.rb +184 -0
- data/test/test_event.rb +1 -1
- data/test/test_file_dialog.rb +48 -0
- data/test/test_file_event.rb +43 -0
- data/test/test_has_text_preedit.rb +54 -0
- data/test/test_key_event.rb +23 -2
- data/test/test_link_constraint.rb +237 -0
- data/test/test_menu.rb +237 -0
- data/test/test_pin.rb +65 -0
- data/test/test_pointer.rb +50 -26
- data/test/test_pointer_event.rb +25 -10
- data/test/test_reflex.rb +36 -0
- data/test/test_screen.rb +24 -2
- data/test/test_snap_constraint.rb +140 -0
- data/test/test_text_event.rb +54 -0
- data/test/test_view.rb +152 -25
- data/test/test_wheel_constraint.rb +125 -0
- data/test/test_wheel_event.rb +24 -10
- data/test/test_window.rb +205 -43
- metadata +154 -10
- data/.github/workflows/utils.rb +0 -127
data/src/win32/window.cpp
CHANGED
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
#include "window.h"
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
#include <xot/windows.h>
|
|
5
|
+
#include <imm.h>
|
|
6
|
+
#include <dwmapi.h>
|
|
7
|
+
#include <shellapi.h>
|
|
8
|
+
|
|
4
9
|
#include <assert.h>
|
|
10
|
+
#include <limits.h>
|
|
11
|
+
#include <math.h>
|
|
5
12
|
#include <map>
|
|
6
13
|
#include <memory>
|
|
7
14
|
#include <xot/time.h>
|
|
8
|
-
#include <xot/windows.h>
|
|
9
15
|
#include <rays/rays.h>
|
|
10
16
|
#include "reflex/defs.h"
|
|
11
17
|
#include "reflex/exception.h"
|
|
12
18
|
#include "reflex/debug.h"
|
|
19
|
+
#include "../application.h"
|
|
13
20
|
#include "../view.h"
|
|
14
21
|
#include "event.h"
|
|
15
|
-
#include "
|
|
22
|
+
#include "application.h"
|
|
23
|
+
#include "menu.h"
|
|
16
24
|
#include "screen.h"
|
|
25
|
+
#include "gamepad.h"
|
|
17
26
|
#include "opengl.h"
|
|
18
27
|
|
|
19
28
|
|
|
@@ -24,17 +33,26 @@ namespace Reflex
|
|
|
24
33
|
typedef std::map<int, String> PressingKeyMap;
|
|
25
34
|
|
|
26
35
|
|
|
27
|
-
static const
|
|
36
|
+
static const wchar_t* WINDOWCLASS = L"Reflex:WindowClass";
|
|
28
37
|
|
|
29
|
-
static const
|
|
38
|
+
static const wchar_t* USERDATA_PROP = L"Reflex:Window:HWND";
|
|
30
39
|
|
|
31
40
|
|
|
32
41
|
struct WindowData : public Window::Data
|
|
33
42
|
{
|
|
34
43
|
|
|
35
|
-
HWND hwnd
|
|
44
|
+
HWND hwnd = NULL;
|
|
45
|
+
|
|
46
|
+
bool need_rebind = false;
|
|
47
|
+
|
|
48
|
+
bool transparent = false;
|
|
36
49
|
|
|
37
|
-
bool
|
|
50
|
+
bool tracking_mouse = false;
|
|
51
|
+
|
|
52
|
+
// the first half of a surrogate pair, waiting for the second half
|
|
53
|
+
wchar_t pending_surrogate = 0;
|
|
54
|
+
|
|
55
|
+
HACCEL haccel = NULL;
|
|
38
56
|
|
|
39
57
|
OpenGLContext context;
|
|
40
58
|
|
|
@@ -42,6 +60,17 @@ namespace Reflex
|
|
|
42
60
|
|
|
43
61
|
mutable String title_tmp;
|
|
44
62
|
|
|
63
|
+
virtual ~WindowData ()
|
|
64
|
+
{
|
|
65
|
+
set_accelerator_table(NULL);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void set_accelerator_table (HACCEL haccel)
|
|
69
|
+
{
|
|
70
|
+
if (this->haccel) DestroyAcceleratorTable(this->haccel);
|
|
71
|
+
this->haccel = haccel;
|
|
72
|
+
}
|
|
73
|
+
|
|
45
74
|
bool is_valid () const
|
|
46
75
|
{
|
|
47
76
|
return hwnd && IsWindow(hwnd);
|
|
@@ -64,12 +93,20 @@ namespace Reflex
|
|
|
64
93
|
return get_data(const_cast<Window*>(window));
|
|
65
94
|
}
|
|
66
95
|
|
|
96
|
+
HWND
|
|
97
|
+
Window_get_hwnd (const Window* window)
|
|
98
|
+
{
|
|
99
|
+
if (!window) return NULL;
|
|
100
|
+
|
|
101
|
+
return get_data(window)->hwnd;
|
|
102
|
+
}
|
|
103
|
+
|
|
67
104
|
static bool
|
|
68
105
|
window_has_wndproc (HWND hwnd)
|
|
69
106
|
{
|
|
70
107
|
if (!hwnd) return false;
|
|
71
108
|
|
|
72
|
-
WNDPROC proc = (WNDPROC)
|
|
109
|
+
WNDPROC proc = (WNDPROC) GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
|
|
73
110
|
if (proc == wndproc)
|
|
74
111
|
return true;
|
|
75
112
|
|
|
@@ -77,24 +114,42 @@ namespace Reflex
|
|
|
77
114
|
// it can not determine the hwnd is mine or not.
|
|
78
115
|
|
|
79
116
|
enum {BUFSIZE = 256};
|
|
80
|
-
|
|
117
|
+
wchar_t buf[BUFSIZE + 1];
|
|
81
118
|
if (
|
|
82
|
-
|
|
119
|
+
GetClassNameW(hwnd, &buf[0], BUFSIZE) == 0 &&
|
|
83
120
|
GetLastError() != 0)
|
|
84
121
|
{
|
|
85
122
|
return false;
|
|
86
123
|
}
|
|
87
124
|
|
|
88
|
-
return
|
|
125
|
+
return _wcsicmp(buf, WINDOWCLASS) == 0;
|
|
89
126
|
}
|
|
90
127
|
|
|
91
128
|
static Window*
|
|
92
129
|
get_window_from_hwnd (HWND hwnd)
|
|
93
130
|
{
|
|
94
131
|
if (window_has_wndproc(hwnd))
|
|
95
|
-
return (Window*)
|
|
132
|
+
return (Window*) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
|
96
133
|
else
|
|
97
|
-
return (Window*)
|
|
134
|
+
return (Window*) GetPropW(hwnd, USERDATA_PROP);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
bool
|
|
138
|
+
Window_translate_accelerator (MSG* msg)
|
|
139
|
+
{
|
|
140
|
+
if (!msg || !msg->hwnd) return false;
|
|
141
|
+
|
|
142
|
+
if (msg->message != WM_KEYDOWN && msg->message != WM_SYSKEYDOWN)
|
|
143
|
+
return false;
|
|
144
|
+
|
|
145
|
+
HWND hwnd = GetAncestor(msg->hwnd, GA_ROOT);
|
|
146
|
+
Window* win = get_window_from_hwnd(hwnd);
|
|
147
|
+
if (!win) return false;
|
|
148
|
+
|
|
149
|
+
HACCEL haccel = get_data(win)->haccel;
|
|
150
|
+
if (!haccel) return false;
|
|
151
|
+
|
|
152
|
+
return TranslateAcceleratorW(hwnd, haccel, msg) != 0;
|
|
98
153
|
}
|
|
99
154
|
|
|
100
155
|
static void
|
|
@@ -108,13 +163,13 @@ namespace Reflex
|
|
|
108
163
|
if (window_has_wndproc(hwnd))
|
|
109
164
|
{
|
|
110
165
|
SetLastError(0);
|
|
111
|
-
|
|
166
|
+
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR) win);
|
|
112
167
|
if (GetLastError() != 0)
|
|
113
168
|
system_error(__FILE__, __LINE__);
|
|
114
169
|
}
|
|
115
170
|
else
|
|
116
171
|
{
|
|
117
|
-
if (!
|
|
172
|
+
if (!SetPropW(hwnd, USERDATA_PROP, (HANDLE) win))
|
|
118
173
|
system_error(__FILE__, __LINE__);
|
|
119
174
|
}
|
|
120
175
|
|
|
@@ -155,13 +210,13 @@ namespace Reflex
|
|
|
155
210
|
if (window_has_wndproc(self->hwnd))
|
|
156
211
|
{
|
|
157
212
|
SetLastError(0);
|
|
158
|
-
|
|
213
|
+
SetWindowLongPtrW(self->hwnd, GWLP_USERDATA, 0);
|
|
159
214
|
if (GetLastError() != 0)
|
|
160
215
|
system_error(__FILE__, __LINE__);
|
|
161
216
|
}
|
|
162
217
|
else
|
|
163
218
|
{
|
|
164
|
-
if (!
|
|
219
|
+
if (!RemovePropW(self->hwnd, USERDATA_PROP))
|
|
165
220
|
system_error(__FILE__, __LINE__);
|
|
166
221
|
}
|
|
167
222
|
|
|
@@ -170,8 +225,162 @@ namespace Reflex
|
|
|
170
225
|
|
|
171
226
|
win->release();
|
|
172
227
|
|
|
173
|
-
|
|
174
|
-
|
|
228
|
+
Application_quit_if_should();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
static bool
|
|
232
|
+
has_style (HWND hwnd, DWORD style)
|
|
233
|
+
{
|
|
234
|
+
return ((DWORD) GetWindowLongPtrW(hwnd, GWL_STYLE) & style) == style;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
static bool
|
|
238
|
+
calc_size (LRESULT* result, HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
239
|
+
{
|
|
240
|
+
if (
|
|
241
|
+
!wp || IsZoomed(hwnd) ||
|
|
242
|
+
has_style(hwnd, WS_CAPTION) || !has_style(hwnd, WS_THICKFRAME))
|
|
243
|
+
{
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// without a caption the sizing border is still drawn at the
|
|
248
|
+
// top of the window, so let the client area cover it
|
|
249
|
+
NCCALCSIZE_PARAMS* params = (NCCALCSIZE_PARAMS*) lp;
|
|
250
|
+
LONG top = params->rgrc[0].top;
|
|
251
|
+
*result = DefWindowProcW(hwnd, msg, wp, lp);
|
|
252
|
+
params->rgrc[0].top = top;
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
static int
|
|
257
|
+
border_size ()
|
|
258
|
+
{
|
|
259
|
+
return
|
|
260
|
+
GetSystemMetrics(SM_CYSIZEFRAME) +
|
|
261
|
+
GetSystemMetrics(SM_CXPADDEDBORDER);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
static bool
|
|
265
|
+
hit_test (LRESULT* result, Window* win, HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
266
|
+
{
|
|
267
|
+
// the client area covers the sizing border, or there is no border at
|
|
268
|
+
// all, so an edge answers HTCLIENT and cannot resize. this gives the
|
|
269
|
+
// edges back.
|
|
270
|
+
if (has_style(hwnd, WS_CAPTION) || IsZoomed(hwnd))
|
|
271
|
+
return false;
|
|
272
|
+
|
|
273
|
+
LRESULT hit = DefWindowProcW(hwnd, msg, wp, lp);
|
|
274
|
+
|
|
275
|
+
// the sizing border of a window that cannot resize is only there for
|
|
276
|
+
// the shadow, so its edges answer as a plain border
|
|
277
|
+
if (!win || !win->has_flag(Window::FLAG_RESIZABLE))
|
|
278
|
+
{
|
|
279
|
+
*result = HTBORDER;
|
|
280
|
+
return HTSIZEFIRST <= hit && hit <= HTSIZELAST;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (hit != HTCLIENT)
|
|
284
|
+
return false;
|
|
285
|
+
|
|
286
|
+
RECT window;
|
|
287
|
+
if (!GetWindowRect(hwnd, &window))
|
|
288
|
+
system_error(__FILE__, __LINE__);
|
|
289
|
+
|
|
290
|
+
int size = border_size();
|
|
291
|
+
POINT pos = {GET_X_LPARAM(lp), GET_Y_LPARAM(lp)};
|
|
292
|
+
bool left = pos.x < window.left + size;
|
|
293
|
+
bool right = pos.x >= window.right - size;
|
|
294
|
+
bool top = pos.y < window.top + size;
|
|
295
|
+
bool bottom = pos.y >= window.bottom - size;
|
|
296
|
+
|
|
297
|
+
// a sizing border draws the other edges outside the client area
|
|
298
|
+
if (has_style(hwnd, WS_THICKFRAME) && !top)
|
|
299
|
+
return false;
|
|
300
|
+
|
|
301
|
+
int corner = size * 2;
|
|
302
|
+
bool near_l = pos.x < window.left + corner;
|
|
303
|
+
bool near_r = pos.x >= window.right - corner;
|
|
304
|
+
bool near_t = pos.y < window.top + corner;
|
|
305
|
+
bool near_b = pos.y >= window.bottom - corner;
|
|
306
|
+
|
|
307
|
+
if (top && near_l) *result = HTTOPLEFT;
|
|
308
|
+
else if (top && near_r) *result = HTTOPRIGHT;
|
|
309
|
+
else if (bottom && near_l) *result = HTBOTTOMLEFT;
|
|
310
|
+
else if (bottom && near_r) *result = HTBOTTOMRIGHT;
|
|
311
|
+
else if (left && near_t) *result = HTTOPLEFT;
|
|
312
|
+
else if (left && near_b) *result = HTBOTTOMLEFT;
|
|
313
|
+
else if (right && near_t) *result = HTTOPRIGHT;
|
|
314
|
+
else if (right && near_b) *result = HTBOTTOMRIGHT;
|
|
315
|
+
else if (top) *result = HTTOP;
|
|
316
|
+
else if (bottom) *result = HTBOTTOM;
|
|
317
|
+
else if (left) *result = HTLEFT;
|
|
318
|
+
else if (right) *result = HTRIGHT;
|
|
319
|
+
else return false;
|
|
320
|
+
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
static void
|
|
325
|
+
keep_caption_on_screen (HWND hwnd, RECT* rect)
|
|
326
|
+
{
|
|
327
|
+
if (!has_style(hwnd, WS_CAPTION)) return;
|
|
328
|
+
|
|
329
|
+
HMONITOR hmonitor = MonitorFromRect(rect, MONITOR_DEFAULTTONEAREST);
|
|
330
|
+
if (!hmonitor) return;
|
|
331
|
+
|
|
332
|
+
MONITORINFO info = {sizeof(info)};
|
|
333
|
+
if (!GetMonitorInfoW(hmonitor, &info))
|
|
334
|
+
system_error(__FILE__, __LINE__);
|
|
335
|
+
|
|
336
|
+
LONG over = info.rcWork.top - rect->top;
|
|
337
|
+
if (over <= 0) return;
|
|
338
|
+
|
|
339
|
+
rect->top += over;
|
|
340
|
+
rect->bottom += over;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
static bool
|
|
344
|
+
window_pos_changing (
|
|
345
|
+
LRESULT* result, Window* win, HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
346
|
+
{
|
|
347
|
+
WINDOWPOS* pos = (WINDOWPOS*) lp;
|
|
348
|
+
|
|
349
|
+
if (win && win->has_flag(Window::FLAG_ALWAYS_ON_BOTTOM))
|
|
350
|
+
{
|
|
351
|
+
pos->hwndInsertAfter = HWND_BOTTOM;
|
|
352
|
+
pos->flags &= ~SWP_NOZORDER;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (!(pos->flags & SWP_SHOWWINDOW) && !IsWindowVisible(hwnd))
|
|
356
|
+
{
|
|
357
|
+
// a hidden window gets the size it asks for, but windows widens
|
|
358
|
+
// a captioned one here, so take the width back
|
|
359
|
+
int cx = pos->cx;
|
|
360
|
+
*result = DefWindowProcW(hwnd, msg, wp, lp);
|
|
361
|
+
pos->cx = cx;
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (!(pos->flags & SWP_NOMOVE) && !IsIconic(hwnd) && !IsZoomed(hwnd))
|
|
366
|
+
{
|
|
367
|
+
// once on screen the caption has to stay where it can be grabbed
|
|
368
|
+
RECT rect = {pos->x, pos->y, pos->x + pos->cx, pos->y + pos->cy};
|
|
369
|
+
keep_caption_on_screen(hwnd, &rect);
|
|
370
|
+
pos->y = rect.top;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
static void
|
|
377
|
+
update_accelerator_table (Window* win)
|
|
378
|
+
{
|
|
379
|
+
Menu* menu = win->menu();
|
|
380
|
+
if (!menu || !Menu_is_modified(menu))
|
|
381
|
+
return;
|
|
382
|
+
|
|
383
|
+
get_data(win)->set_accelerator_table(Menu_create_accelerator_table(menu));
|
|
175
384
|
}
|
|
176
385
|
|
|
177
386
|
void
|
|
@@ -179,11 +388,12 @@ namespace Reflex
|
|
|
179
388
|
{
|
|
180
389
|
WindowData* self = get_data(win);
|
|
181
390
|
|
|
391
|
+
update_accelerator_table(win);
|
|
182
392
|
Gamepad_poll();
|
|
183
393
|
|
|
184
394
|
Window_call_update_event(win);
|
|
185
395
|
|
|
186
|
-
if (self->
|
|
396
|
+
if (Xot::check_and_remove_flag(&self->flags, Window::Data::REDRAW))
|
|
187
397
|
{
|
|
188
398
|
#if 1
|
|
189
399
|
InvalidateRect(self->hwnd, NULL, FALSE);
|
|
@@ -191,8 +401,6 @@ namespace Reflex
|
|
|
191
401
|
RedrawWindow(
|
|
192
402
|
self->hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | EDW_ALLCHILDREN);
|
|
193
403
|
#endif
|
|
194
|
-
|
|
195
|
-
self->redraw = false;
|
|
196
404
|
}
|
|
197
405
|
}
|
|
198
406
|
|
|
@@ -219,32 +427,51 @@ namespace Reflex
|
|
|
219
427
|
Window_call_draw_event(win, &e);
|
|
220
428
|
}
|
|
221
429
|
|
|
222
|
-
static
|
|
223
|
-
|
|
430
|
+
static String
|
|
431
|
+
get_chars (WindowData* self, UINT msg)
|
|
224
432
|
{
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
win->self->prev_size = b.size();
|
|
230
|
-
|
|
231
|
-
if (dpos == 0 && dsize == 0) return;
|
|
232
|
-
|
|
233
|
-
Reflex::FrameEvent e(b, dpos.x, dpos.y, 0, dsize.x, dsize.y, 0);
|
|
234
|
-
if (dpos != 0) win->on_move(&e);
|
|
235
|
-
if (dsize != 0)
|
|
433
|
+
MSG wmchar;
|
|
434
|
+
UINT filter = msg == WM_SYSKEYDOWN ? WM_SYSCHAR : WM_CHAR;
|
|
435
|
+
BOOL peeked = PeekMessageW(&wmchar, self->hwnd, filter, filter, PM_NOREMOVE);
|
|
436
|
+
if (peeked)
|
|
236
437
|
{
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
438
|
+
// a character outside the BMP is injected as one VK_PACKET per
|
|
439
|
+
// UTF-16 code unit, so the halves of the surrogate pair arrive in
|
|
440
|
+
// two key events and the first of them has to be held back until
|
|
441
|
+
// the second one completes the character.
|
|
442
|
+
wchar_t unit = (wchar_t) wmchar.wParam;
|
|
443
|
+
wchar_t pending = self->pending_surrogate;
|
|
444
|
+
self->pending_surrogate = 0;
|
|
445
|
+
|
|
446
|
+
if (IS_HIGH_SURROGATE(unit))
|
|
447
|
+
self->pending_surrogate = unit;
|
|
448
|
+
else if (IS_LOW_SURROGATE(unit))
|
|
449
|
+
{
|
|
450
|
+
if (pending)
|
|
451
|
+
{
|
|
452
|
+
wchar_t pair[] = {pending, unit};
|
|
453
|
+
return String(pair, 2);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
else
|
|
457
|
+
return String(&unit, 1);
|
|
458
|
+
}
|
|
459
|
+
return "";
|
|
460
|
+
}
|
|
242
461
|
|
|
243
|
-
|
|
244
|
-
|
|
462
|
+
static bool
|
|
463
|
+
accepts_text_input (Window* win)
|
|
464
|
+
{
|
|
465
|
+
const View* focus = win->focus();
|
|
466
|
+
return focus && focus->accepts_text_input();
|
|
467
|
+
}
|
|
245
468
|
|
|
246
|
-
|
|
247
|
-
|
|
469
|
+
// macos never commits a control character, so it is not text here either
|
|
470
|
+
static bool
|
|
471
|
+
is_committable (const String& chars)
|
|
472
|
+
{
|
|
473
|
+
uchar c = chars.empty() ? 0 : (uchar) chars[0];
|
|
474
|
+
return c >= 0x20 && c != 0x7f;
|
|
248
475
|
}
|
|
249
476
|
|
|
250
477
|
static void
|
|
@@ -252,23 +479,26 @@ namespace Reflex
|
|
|
252
479
|
{
|
|
253
480
|
assert(*win);
|
|
254
481
|
|
|
255
|
-
|
|
482
|
+
if (wp == VK_PROCESSKEY) return;
|
|
256
483
|
|
|
257
|
-
|
|
258
|
-
UINT filter = msg == WM_SYSKEYDOWN ? WM_SYSCHAR : WM_CHAR;
|
|
259
|
-
BOOL peeked = PeekMessage(&wmchar, self->hwnd, filter, filter, PM_NOREMOVE);
|
|
484
|
+
WindowData* self = get_data(win);
|
|
260
485
|
|
|
261
|
-
String chars;
|
|
262
|
-
if (peeked) chars += (char) wmchar.wParam;
|
|
486
|
+
String chars = get_chars(self, msg);
|
|
263
487
|
|
|
264
488
|
NativeKeyEvent e(msg, wp, lp, chars);
|
|
265
|
-
|
|
266
489
|
self->pressing_keys.insert_or_assign(e.code(), chars);
|
|
490
|
+
|
|
267
491
|
#if 0
|
|
268
492
|
for (auto kv : self->pressing_keys)
|
|
269
493
|
doutln("0x%x : %s", kv.first, (const char*) kv.second);
|
|
270
494
|
#endif
|
|
271
495
|
|
|
496
|
+
if (accepts_text_input(win) && is_committable(chars))
|
|
497
|
+
{
|
|
498
|
+
TextEvent te(TextEvent::COMMIT, chars);
|
|
499
|
+
Window_call_text_event(win, &te);
|
|
500
|
+
}
|
|
501
|
+
|
|
272
502
|
Window_call_key_event(win, &e);
|
|
273
503
|
}
|
|
274
504
|
|
|
@@ -283,11 +513,73 @@ namespace Reflex
|
|
|
283
513
|
|
|
284
514
|
auto it = self->pressing_keys.find(e.code());
|
|
285
515
|
if (it != self->pressing_keys.end())
|
|
516
|
+
{
|
|
286
517
|
KeyEvent_set_chars(&e, it->second);
|
|
518
|
+
self->pressing_keys.erase(it);
|
|
519
|
+
}
|
|
287
520
|
|
|
288
521
|
Window_call_key_event(win, &e);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
static void
|
|
525
|
+
update_composition (Window* win, LPARAM lp)
|
|
526
|
+
{
|
|
527
|
+
assert(*win);
|
|
528
|
+
|
|
529
|
+
WindowData* self = get_data(win);
|
|
530
|
+
|
|
531
|
+
HIMC himc = ImmGetContext(self->hwnd);
|
|
532
|
+
if (!himc) return;
|
|
533
|
+
|
|
534
|
+
if (lp & GCS_RESULTSTR)
|
|
535
|
+
{
|
|
536
|
+
NativeTextEvent e(TextEvent::COMMIT, himc, GCS_RESULTSTR);
|
|
537
|
+
Window_call_text_event(win, &e, true);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (lp & GCS_COMPSTR)
|
|
541
|
+
{
|
|
542
|
+
NativeTextEvent e(TextEvent::PREEDIT, himc, GCS_COMPSTR);
|
|
543
|
+
Window_call_text_event(win, &e);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
ImmReleaseContext(self->hwnd, himc);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
static void
|
|
550
|
+
clear_composition (Window* win)
|
|
551
|
+
{
|
|
552
|
+
assert(*win);
|
|
553
|
+
|
|
554
|
+
TextEvent e(TextEvent::PREEDIT, "");
|
|
555
|
+
Window_call_text_event(win, &e);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
static void
|
|
559
|
+
update_ime_position (Window* win)
|
|
560
|
+
{
|
|
561
|
+
assert(*win);
|
|
562
|
+
|
|
563
|
+
const View* focus = win->focus();
|
|
564
|
+
if (!focus) return;
|
|
565
|
+
|
|
566
|
+
WindowData* self = get_data(win);
|
|
567
|
+
|
|
568
|
+
HIMC himc = ImmGetContext(self->hwnd);
|
|
569
|
+
if (!himc) return;
|
|
570
|
+
|
|
571
|
+
Bounds b = focus->text_input_bounds();
|
|
572
|
+
POINT p1 = Window_to_native_coord(*win, focus->to_window(b.position()));
|
|
573
|
+
POINT p2 = Window_to_native_coord(*win, focus->to_window(b.position() + b.size()));
|
|
289
574
|
|
|
290
|
-
|
|
575
|
+
CANDIDATEFORM form = {0};
|
|
576
|
+
form.dwIndex = 0;
|
|
577
|
+
form.dwStyle = CFS_EXCLUDE;
|
|
578
|
+
form.ptCurrentPos = {(LONG) p1.x, (LONG) p2.y};
|
|
579
|
+
form.rcArea = {(LONG) p1.x, (LONG) p1.y, (LONG) p2.x, (LONG) p2.y};
|
|
580
|
+
ImmSetCandidateWindow(himc, &form);
|
|
581
|
+
|
|
582
|
+
ImmReleaseContext(self->hwnd, himc);
|
|
291
583
|
}
|
|
292
584
|
|
|
293
585
|
#ifndef MOUSEEVENTF_FROMTOUCH
|
|
@@ -300,13 +592,76 @@ namespace Reflex
|
|
|
300
592
|
return (GetMessageExtraInfo() & 0xffffff00) == MOUSEEVENTF_FROMTOUCH;
|
|
301
593
|
}
|
|
302
594
|
|
|
595
|
+
static void
|
|
596
|
+
capture_mouse_on_button_down (HWND hwnd, UINT msg)
|
|
597
|
+
{
|
|
598
|
+
switch (msg)
|
|
599
|
+
{
|
|
600
|
+
case WM_LBUTTONDOWN:
|
|
601
|
+
case WM_RBUTTONDOWN:
|
|
602
|
+
case WM_MBUTTONDOWN:
|
|
603
|
+
case WM_LBUTTONDBLCLK:
|
|
604
|
+
case WM_RBUTTONDBLCLK:
|
|
605
|
+
case WM_MBUTTONDBLCLK:
|
|
606
|
+
SetCapture(hwnd);
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
static void
|
|
612
|
+
release_mouse_on_button_up (HWND hwnd, UINT msg, WPARAM wp)
|
|
613
|
+
{
|
|
614
|
+
switch (msg)
|
|
615
|
+
{
|
|
616
|
+
case WM_LBUTTONUP:
|
|
617
|
+
case WM_RBUTTONUP:
|
|
618
|
+
case WM_MBUTTONUP:
|
|
619
|
+
if (
|
|
620
|
+
(wp & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON)) == 0 &&
|
|
621
|
+
hwnd == GetCapture())
|
|
622
|
+
{
|
|
623
|
+
ReleaseCapture();
|
|
624
|
+
}
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
303
629
|
static void
|
|
304
630
|
mouse (Window* win, UINT msg, WPARAM wp, LPARAM lp)
|
|
305
631
|
{
|
|
306
632
|
if (is_from_touch_event()) return;
|
|
307
633
|
|
|
308
|
-
|
|
634
|
+
WindowData* self = get_data(win);
|
|
635
|
+
|
|
636
|
+
if (msg == WM_MOUSEMOVE && !self->tracking_mouse)
|
|
637
|
+
{
|
|
638
|
+
TRACKMOUSEEVENT tme = {sizeof(tme), TME_LEAVE, self->hwnd, 0};
|
|
639
|
+
TrackMouseEvent(&tme);
|
|
640
|
+
self->tracking_mouse = true;
|
|
641
|
+
|
|
642
|
+
// Win32 has no mouse-enter message; the first move after (re)arming
|
|
643
|
+
// the leave tracking is when the mouse entered the window.
|
|
644
|
+
NativePointerEvent e(*win, msg, wp, lp, Pointer::ENTER);
|
|
645
|
+
Window_call_pointer_event(win, &e);
|
|
646
|
+
}
|
|
647
|
+
else if (msg == WM_MOUSELEAVE)
|
|
648
|
+
{
|
|
649
|
+
self->tracking_mouse = false;
|
|
650
|
+
|
|
651
|
+
POINT pt;
|
|
652
|
+
if (GetCursorPos(&pt) && ScreenToClient(self->hwnd, &pt))
|
|
653
|
+
lp = MAKELPARAM(pt.x, pt.y);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// before the press is handled: a popup menu opened by it takes the
|
|
657
|
+
// capture away and eats the release, which would never come to let
|
|
658
|
+
// go of a capture taken after
|
|
659
|
+
capture_mouse_on_button_down(self->hwnd, msg);
|
|
660
|
+
|
|
661
|
+
NativePointerEvent e(*win, msg, wp, lp);
|
|
309
662
|
Window_call_pointer_event(win, &e);
|
|
663
|
+
|
|
664
|
+
release_mouse_on_button_up(self->hwnd, msg, wp);
|
|
310
665
|
}
|
|
311
666
|
|
|
312
667
|
static void
|
|
@@ -321,18 +676,18 @@ namespace Reflex
|
|
|
321
676
|
{
|
|
322
677
|
wp_y = wp;
|
|
323
678
|
MSG m;
|
|
324
|
-
if (
|
|
679
|
+
if (PeekMessageW(&m, self->hwnd, WM_MOUSEHWHEEL, WM_MOUSEHWHEEL, PM_REMOVE))
|
|
325
680
|
wp_x = m.wParam;
|
|
326
681
|
}
|
|
327
682
|
else
|
|
328
683
|
{
|
|
329
684
|
wp_x = wp;
|
|
330
685
|
MSG m;
|
|
331
|
-
if (
|
|
686
|
+
if (PeekMessageW(&m, self->hwnd, WM_MOUSEWHEEL, WM_MOUSEWHEEL, PM_REMOVE))
|
|
332
687
|
wp_y = m.wParam;
|
|
333
688
|
}
|
|
334
689
|
|
|
335
|
-
NativeWheelEvent e(wp_x, wp_y, lp);
|
|
690
|
+
NativeWheelEvent e(*win, wp_x, wp_y, lp);
|
|
336
691
|
Window_call_wheel_event(win, &e);
|
|
337
692
|
}
|
|
338
693
|
|
|
@@ -350,7 +705,7 @@ namespace Reflex
|
|
|
350
705
|
if (!GetTouchInputInfo(handle, size, &touches[0], sizeof(TOUCHINPUT)))
|
|
351
706
|
return;
|
|
352
707
|
|
|
353
|
-
NativePointerEvent e(
|
|
708
|
+
NativePointerEvent e(*win, &touches[0], size);
|
|
354
709
|
Window_call_pointer_event(win, &e);
|
|
355
710
|
|
|
356
711
|
CloseTouchInputHandle(handle);
|
|
@@ -360,12 +715,36 @@ namespace Reflex
|
|
|
360
715
|
window_proc (Window* win, HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
361
716
|
{
|
|
362
717
|
if (!win || !*win || hwnd != get_data(win)->hwnd)
|
|
363
|
-
return
|
|
718
|
+
return DefWindowProcW(hwnd, msg, wp, lp);
|
|
364
719
|
|
|
365
720
|
WindowData* self = get_data(win);
|
|
366
721
|
|
|
367
722
|
switch (msg)
|
|
368
723
|
{
|
|
724
|
+
case WM_NCCALCSIZE:
|
|
725
|
+
{
|
|
726
|
+
LRESULT result = 0;
|
|
727
|
+
if (calc_size(&result, hwnd, msg, wp, lp))
|
|
728
|
+
return result;
|
|
729
|
+
break;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
case WM_NCHITTEST:
|
|
733
|
+
{
|
|
734
|
+
LRESULT result = 0;
|
|
735
|
+
if (hit_test(&result, win, hwnd, msg, wp, lp))
|
|
736
|
+
return result;
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
case WM_WINDOWPOSCHANGING:
|
|
741
|
+
{
|
|
742
|
+
LRESULT result = 0;
|
|
743
|
+
if (window_pos_changing(&result, win, hwnd, msg, wp, lp))
|
|
744
|
+
return result;
|
|
745
|
+
break;
|
|
746
|
+
}
|
|
747
|
+
|
|
369
748
|
case WM_ACTIVATE:
|
|
370
749
|
{
|
|
371
750
|
if (LOWORD(wp) == WA_INACTIVE)
|
|
@@ -380,10 +759,40 @@ namespace Reflex
|
|
|
380
759
|
|
|
381
760
|
case WM_CLOSE:
|
|
382
761
|
{
|
|
383
|
-
win
|
|
762
|
+
Window_call_close(win);
|
|
384
763
|
return 0;
|
|
385
764
|
}
|
|
386
765
|
|
|
766
|
+
case WM_COMMAND:
|
|
767
|
+
{
|
|
768
|
+
if (HIWORD(wp) == 1)
|
|
769
|
+
{
|
|
770
|
+
// menu items are reported by WM_MENUCOMMAND (MNS_NOTIFYBYPOS),
|
|
771
|
+
// so only accelerators (HIWORD == 1) arrive here
|
|
772
|
+
Menu_call_command_event(win->menu(), LOWORD(wp));
|
|
773
|
+
return 0;
|
|
774
|
+
}
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
case WM_MENUCOMMAND:
|
|
779
|
+
{
|
|
780
|
+
Menu_call_command_event((HMENU) lp, (uint) wp);
|
|
781
|
+
return 0;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
case WM_INITMENUPOPUP:
|
|
785
|
+
{
|
|
786
|
+
Menu_call_open_event((HMENU) wp);
|
|
787
|
+
break;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
case WM_UNINITMENUPOPUP:
|
|
791
|
+
{
|
|
792
|
+
Menu_call_close_event((HMENU) wp);
|
|
793
|
+
break;
|
|
794
|
+
}
|
|
795
|
+
|
|
387
796
|
case WM_PAINT:
|
|
388
797
|
{
|
|
389
798
|
self->context.make_current();
|
|
@@ -406,13 +815,13 @@ namespace Reflex
|
|
|
406
815
|
|
|
407
816
|
case WM_MOVE:
|
|
408
817
|
{
|
|
409
|
-
|
|
818
|
+
Window_call_frame_event(win);
|
|
410
819
|
break;
|
|
411
820
|
}
|
|
412
821
|
|
|
413
822
|
case WM_SIZE:
|
|
414
823
|
{
|
|
415
|
-
|
|
824
|
+
Window_call_frame_event(win);
|
|
416
825
|
break;
|
|
417
826
|
}
|
|
418
827
|
|
|
@@ -430,6 +839,31 @@ namespace Reflex
|
|
|
430
839
|
break;
|
|
431
840
|
}
|
|
432
841
|
|
|
842
|
+
case WM_IME_STARTCOMPOSITION:
|
|
843
|
+
{
|
|
844
|
+
if (!accepts_text_input(win)) break;
|
|
845
|
+
|
|
846
|
+
update_ime_position(win);
|
|
847
|
+
return 0;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
case WM_IME_ENDCOMPOSITION:
|
|
851
|
+
{
|
|
852
|
+
if (!accepts_text_input(win)) break;
|
|
853
|
+
|
|
854
|
+
clear_composition(win);
|
|
855
|
+
return 0;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
case WM_IME_COMPOSITION:
|
|
859
|
+
{
|
|
860
|
+
if (!accepts_text_input(win)) break;
|
|
861
|
+
|
|
862
|
+
update_composition(win, lp);
|
|
863
|
+
update_ime_position(win);
|
|
864
|
+
return 0;
|
|
865
|
+
}
|
|
866
|
+
|
|
433
867
|
case WM_LBUTTONDOWN:
|
|
434
868
|
case WM_RBUTTONDOWN:
|
|
435
869
|
case WM_MBUTTONDOWN:
|
|
@@ -440,6 +874,7 @@ namespace Reflex
|
|
|
440
874
|
case WM_RBUTTONUP:
|
|
441
875
|
case WM_MBUTTONUP:
|
|
442
876
|
case WM_MOUSEMOVE:
|
|
877
|
+
case WM_MOUSELEAVE:
|
|
443
878
|
{
|
|
444
879
|
mouse(win, msg, wp, lp);
|
|
445
880
|
break;
|
|
@@ -452,6 +887,12 @@ namespace Reflex
|
|
|
452
887
|
break;
|
|
453
888
|
}
|
|
454
889
|
|
|
890
|
+
case WM_CAPTURECHANGED:
|
|
891
|
+
{
|
|
892
|
+
Window_cancel_active_pointers(win);
|
|
893
|
+
break;
|
|
894
|
+
}
|
|
895
|
+
|
|
455
896
|
case WM_TOUCH:
|
|
456
897
|
{
|
|
457
898
|
touch(win, msg, wp, lp);
|
|
@@ -468,29 +909,51 @@ namespace Reflex
|
|
|
468
909
|
}
|
|
469
910
|
}
|
|
470
911
|
|
|
471
|
-
return
|
|
912
|
+
return DefWindowProcW(hwnd, msg, wp, lp);
|
|
472
913
|
}
|
|
473
914
|
|
|
474
915
|
static LRESULT CALLBACK
|
|
475
916
|
wndproc (HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
|
476
917
|
{
|
|
477
|
-
|
|
478
|
-
|
|
918
|
+
if (Application_has_exception())
|
|
919
|
+
return DefWindowProcW(hwnd, msg, wp, lp);
|
|
920
|
+
|
|
921
|
+
return Application_guard([&]() -> LRESULT
|
|
479
922
|
{
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
923
|
+
Window* win = NULL;
|
|
924
|
+
if (msg == WM_NCCREATE)
|
|
925
|
+
{
|
|
926
|
+
CREATESTRUCTW* cs = (CREATESTRUCTW*) lp;
|
|
927
|
+
win = (Window*) cs->lpCreateParams;
|
|
928
|
+
setup_window(win, hwnd);
|
|
929
|
+
}
|
|
484
930
|
|
|
485
|
-
|
|
486
|
-
|
|
931
|
+
if (!win) win = get_window_from_hwnd(hwnd);
|
|
932
|
+
if (win) rebind(win);
|
|
487
933
|
|
|
488
|
-
|
|
934
|
+
LRESULT ret = window_proc(win, hwnd, msg, wp, lp);
|
|
489
935
|
|
|
490
|
-
|
|
491
|
-
|
|
936
|
+
if (msg == WM_NCDESTROY)
|
|
937
|
+
cleanup_window(win);
|
|
492
938
|
|
|
493
|
-
|
|
939
|
+
return ret;
|
|
940
|
+
}, (LRESULT) 0);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
static void
|
|
944
|
+
load_app_icons (HICON* large, HICON* small)
|
|
945
|
+
{
|
|
946
|
+
// the icons Explorer shows for the host executable, if it has any;
|
|
947
|
+
// NULL leaves the window with the default icon
|
|
948
|
+
*large = *small = NULL;
|
|
949
|
+
|
|
950
|
+
wchar_t path[32768];
|
|
951
|
+
if (GetModuleFileNameW(NULL, path, sizeof(path) / sizeof(path[0])) == 0)
|
|
952
|
+
return;
|
|
953
|
+
|
|
954
|
+
UINT n = ExtractIconExW(path, 0, large, small, 1);
|
|
955
|
+
if (n == 0 || n == UINT_MAX)
|
|
956
|
+
*large = *small = NULL;
|
|
494
957
|
}
|
|
495
958
|
|
|
496
959
|
static void
|
|
@@ -499,22 +962,21 @@ namespace Reflex
|
|
|
499
962
|
static bool registered = false;
|
|
500
963
|
if (registered) return;
|
|
501
964
|
|
|
502
|
-
|
|
965
|
+
WNDCLASSEXW wc;
|
|
503
966
|
memset(&wc, 0, sizeof(wc));
|
|
504
|
-
|
|
505
967
|
wc.cbSize = sizeof(wc);
|
|
506
968
|
wc.lpszClassName = WINDOWCLASS;
|
|
507
969
|
wc.lpfnWndProc = (WNDPROC) wndproc;
|
|
508
970
|
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
|
|
509
|
-
wc.hInstance =
|
|
510
|
-
|
|
511
|
-
//wc.hIconSm = LoadIcon(wc.hInstance, IDI_APP_SMALL);
|
|
512
|
-
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
971
|
+
wc.hInstance = GetModuleHandleW(NULL);
|
|
972
|
+
wc.hCursor = LoadCursorW(NULL, (LPCWSTR) IDC_ARROW);
|
|
513
973
|
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
|
|
514
974
|
wc.lpszMenuName = NULL;
|
|
515
975
|
wc.cbWndExtra = sizeof(Window*);
|
|
516
976
|
|
|
517
|
-
|
|
977
|
+
load_app_icons(&wc.hIcon, &wc.hIconSm);
|
|
978
|
+
|
|
979
|
+
if (!RegisterClassExW(&wc))
|
|
518
980
|
system_error(__FILE__, __LINE__);
|
|
519
981
|
|
|
520
982
|
registered = true;
|
|
@@ -527,10 +989,10 @@ namespace Reflex
|
|
|
527
989
|
invalid_state_error(__FILE__, __LINE__);
|
|
528
990
|
|
|
529
991
|
register_windowclass();
|
|
530
|
-
HWND hwnd =
|
|
531
|
-
0, WINDOWCLASS, "",
|
|
992
|
+
HWND hwnd = CreateWindowExW(
|
|
993
|
+
0, WINDOWCLASS, L"",
|
|
532
994
|
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
|
|
533
|
-
0, 0, 0, 0, NULL, NULL,
|
|
995
|
+
0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), win);
|
|
534
996
|
if (!hwnd)
|
|
535
997
|
system_error(__FILE__, __LINE__);
|
|
536
998
|
|
|
@@ -552,9 +1014,12 @@ namespace Reflex
|
|
|
552
1014
|
Window_default_flags ()
|
|
553
1015
|
{
|
|
554
1016
|
return
|
|
555
|
-
Window::FLAG_CLOSABLE
|
|
556
|
-
Window::
|
|
557
|
-
Window::
|
|
1017
|
+
Window::FLAG_CLOSABLE |
|
|
1018
|
+
Window::FLAG_MINIMIZABLE |
|
|
1019
|
+
Window::FLAG_RESIZABLE |
|
|
1020
|
+
Window::FLAG_TITLEBAR_BUTTONS |
|
|
1021
|
+
Window::FLAG_TITLEBAR_BACKGROUND |
|
|
1022
|
+
Window::FLAG_SHADOW;
|
|
558
1023
|
}
|
|
559
1024
|
|
|
560
1025
|
void
|
|
@@ -573,9 +1038,15 @@ namespace Reflex
|
|
|
573
1038
|
|
|
574
1039
|
WindowData* self = get_data(window);
|
|
575
1040
|
|
|
1041
|
+
// the frame is passed so that WM_WINDOWPOSCHANGING can correct it
|
|
1042
|
+
RECT rect = {0};
|
|
1043
|
+
if (!GetWindowRect(self->hwnd, &rect))
|
|
1044
|
+
system_error(__FILE__, __LINE__);
|
|
1045
|
+
|
|
576
1046
|
SetWindowPos(
|
|
577
|
-
self->hwnd, HWND_TOP,
|
|
578
|
-
|
|
1047
|
+
self->hwnd, HWND_TOP,
|
|
1048
|
+
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
|
1049
|
+
SWP_SHOWWINDOW);
|
|
579
1050
|
UpdateWindow(self->hwnd);
|
|
580
1051
|
}
|
|
581
1052
|
|
|
@@ -610,7 +1081,7 @@ namespace Reflex
|
|
|
610
1081
|
|
|
611
1082
|
if (!*window) return;
|
|
612
1083
|
|
|
613
|
-
if (!
|
|
1084
|
+
if (!SetWindowTextW(get_data(window)->hwnd, String(title).to_wstr().c_str()))
|
|
614
1085
|
system_error(__FILE__, __LINE__);
|
|
615
1086
|
}
|
|
616
1087
|
|
|
@@ -621,75 +1092,80 @@ namespace Reflex
|
|
|
621
1092
|
|
|
622
1093
|
const WindowData* self = get_data(&window);
|
|
623
1094
|
|
|
624
|
-
int size =
|
|
1095
|
+
int size = GetWindowTextLengthW(self->hwnd);
|
|
625
1096
|
if (size <= 0) return "";
|
|
626
1097
|
|
|
627
|
-
std::unique_ptr<
|
|
628
|
-
if (
|
|
1098
|
+
std::unique_ptr<wchar_t[]> buf(new wchar_t[size + 1]);
|
|
1099
|
+
if (GetWindowTextW(self->hwnd, &buf[0], size + 1) != size)
|
|
629
1100
|
return "";
|
|
630
1101
|
|
|
631
|
-
self->title_tmp = &buf[0];
|
|
1102
|
+
self->title_tmp = String(&buf[0], size);
|
|
632
1103
|
return self->title_tmp.c_str();
|
|
633
1104
|
}
|
|
634
1105
|
|
|
635
|
-
static
|
|
636
|
-
|
|
637
|
-
HWND hwnd, coord* x, coord* y, coord* width, coord* height,
|
|
638
|
-
coord* nonclient_width = NULL, coord* nonclient_height = NULL)
|
|
1106
|
+
static RECT
|
|
1107
|
+
get_client_rect (HWND hwnd)
|
|
639
1108
|
{
|
|
640
|
-
if (!x && !y && !width && !height && !nonclient_width && !nonclient_height)
|
|
641
|
-
argument_error(__FILE__, __LINE__);
|
|
642
|
-
|
|
643
|
-
RECT window;
|
|
644
|
-
if (!GetWindowRect(hwnd, &window))
|
|
645
|
-
system_error(__FILE__, __LINE__);
|
|
646
|
-
|
|
647
1109
|
RECT client;
|
|
648
1110
|
if (!GetClientRect(hwnd, &client))
|
|
649
1111
|
system_error(__FILE__, __LINE__);
|
|
650
1112
|
|
|
651
|
-
|
|
652
|
-
if (
|
|
653
|
-
|
|
654
|
-
if (height) *height = client.bottom - client.top;
|
|
1113
|
+
POINT pos = {client.left, client.top};
|
|
1114
|
+
if (!ClientToScreen(hwnd, &pos))
|
|
1115
|
+
system_error(__FILE__, __LINE__);
|
|
655
1116
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
1117
|
+
return {
|
|
1118
|
+
pos.x,
|
|
1119
|
+
pos.y,
|
|
1120
|
+
pos.x + (client.right - client.left),
|
|
1121
|
+
pos.y + (client.bottom - client.top)
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
static void
|
|
1126
|
+
client_to_window_rect (HWND hwnd, RECT* rect)
|
|
1127
|
+
{
|
|
1128
|
+
DWORD style = (DWORD) GetWindowLongPtrW(hwnd, GWL_STYLE);
|
|
1129
|
+
DWORD exstyle = (DWORD) GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
|
|
1130
|
+
|
|
1131
|
+
LONG top = rect->top;
|
|
1132
|
+
if (!AdjustWindowRectEx(rect, style, GetMenu(hwnd) != NULL, exstyle))
|
|
1133
|
+
system_error(__FILE__, __LINE__);
|
|
1134
|
+
|
|
1135
|
+
// WM_NCCALCSIZE gives the top of the sizing border to the client area
|
|
1136
|
+
// when there is no caption, so it takes no room here either
|
|
1137
|
+
if (!has_style(hwnd, WS_CAPTION)) rect->top = top;
|
|
668
1138
|
}
|
|
669
1139
|
|
|
670
1140
|
void
|
|
671
|
-
Window_set_frame (Window* window, coord x, coord y, coord
|
|
1141
|
+
Window_set_frame (Window* window, coord x, coord y, coord w, coord h)
|
|
672
1142
|
{
|
|
673
1143
|
if (!*window) return;
|
|
674
1144
|
|
|
675
|
-
|
|
1145
|
+
HWND hwnd = get_data(window)->hwnd;
|
|
676
1146
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
1147
|
+
RECT now = get_client_rect(hwnd);
|
|
1148
|
+
RECT rect = Screen_to_native_coord(x, y, w, h);
|
|
1149
|
+
UINT flags = 0;
|
|
680
1150
|
|
|
681
|
-
|
|
682
|
-
|
|
1151
|
+
if (rect.left == now.left && rect.top == now.top)
|
|
1152
|
+
flags |= SWP_NOMOVE;
|
|
683
1153
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
1154
|
+
if (
|
|
1155
|
+
rect.right - rect.left == now.right - now.left &&
|
|
1156
|
+
rect.bottom - rect.top == now.bottom - now.top)
|
|
1157
|
+
{
|
|
1158
|
+
flags |= SWP_NOSIZE;
|
|
1159
|
+
}
|
|
687
1160
|
|
|
688
1161
|
if (flags == (SWP_NOMOVE | SWP_NOSIZE))
|
|
689
1162
|
return;
|
|
690
1163
|
|
|
1164
|
+
client_to_window_rect(hwnd, &rect);
|
|
1165
|
+
|
|
691
1166
|
if (!SetWindowPos(
|
|
692
|
-
|
|
1167
|
+
hwnd, NULL,
|
|
1168
|
+
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
|
693
1169
|
flags | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER))
|
|
694
1170
|
{
|
|
695
1171
|
system_error(__FILE__, __LINE__);
|
|
@@ -702,9 +1178,20 @@ namespace Reflex
|
|
|
702
1178
|
if (!window)
|
|
703
1179
|
invalid_state_error(__FILE__, __LINE__);
|
|
704
1180
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
1181
|
+
return Screen_from_native_coord(get_client_rect(get_data(&window)->hwnd));
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
void
|
|
1185
|
+
Window_set_menu (Window* window, Menu* menu)
|
|
1186
|
+
{
|
|
1187
|
+
WindowData* self = get_data(window);
|
|
1188
|
+
HWND hwnd = self->hwnd;
|
|
1189
|
+
if (!hwnd) return;
|
|
1190
|
+
|
|
1191
|
+
SetMenu(hwnd, menu ? Menu_get_hmenu(menu, true) : NULL);
|
|
1192
|
+
DrawMenuBar(hwnd);
|
|
1193
|
+
|
|
1194
|
+
self->set_accelerator_table(menu ? Menu_create_accelerator_table(menu) : NULL);
|
|
708
1195
|
}
|
|
709
1196
|
|
|
710
1197
|
Screen
|
|
@@ -717,20 +1204,256 @@ namespace Reflex
|
|
|
717
1204
|
return s;
|
|
718
1205
|
}
|
|
719
1206
|
|
|
1207
|
+
static void
|
|
1208
|
+
set_background_transparent (HWND hwnd, bool transparent)
|
|
1209
|
+
{
|
|
1210
|
+
std::shared_ptr<HRGN__> region;
|
|
1211
|
+
if (transparent)
|
|
1212
|
+
{
|
|
1213
|
+
region.reset(CreateRectRgn(0, 0, -1, -1), DeleteObject);// no blur
|
|
1214
|
+
if (!region)
|
|
1215
|
+
system_error(__FILE__, __LINE__);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
DWM_BLURBEHIND blur = {0};
|
|
1219
|
+
blur.dwFlags = DWM_BB_ENABLE | (transparent ? DWM_BB_BLURREGION : 0);
|
|
1220
|
+
blur.fEnable = transparent ? TRUE : FALSE;
|
|
1221
|
+
blur.hRgnBlur = region.get();
|
|
1222
|
+
HRESULT result = DwmEnableBlurBehindWindow(hwnd, &blur);
|
|
1223
|
+
if (FAILED(result))
|
|
1224
|
+
{
|
|
1225
|
+
system_error(
|
|
1226
|
+
__FILE__, __LINE__,
|
|
1227
|
+
"DwmEnableBlurBehindWindow failed (0x%08x)", (uint) result);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
static DWORD
|
|
1232
|
+
make_window_style (uint flags, DWORD style)
|
|
1233
|
+
{
|
|
1234
|
+
using namespace Xot;
|
|
1235
|
+
|
|
1236
|
+
bool caption = has_flag(flags, Window::FLAG_TITLEBAR_BACKGROUND);
|
|
1237
|
+
|
|
1238
|
+
// the sizing border follows resizable, but a captionless window keeps
|
|
1239
|
+
// it for the shadow and leaves the resizing to the hit test
|
|
1240
|
+
bool sizing_border = caption
|
|
1241
|
+
? has_flag(flags, Window::FLAG_RESIZABLE)
|
|
1242
|
+
: has_flag(flags, Window::FLAG_SHADOW);
|
|
1243
|
+
|
|
1244
|
+
update_flag(&style, WS_SYSMENU, has_flag(flags, Window::FLAG_TITLEBAR_BUTTONS));
|
|
1245
|
+
update_flag(&style, WS_CAPTION, caption);
|
|
1246
|
+
update_flag(&style, WS_MINIMIZEBOX, has_flag(flags, Window::FLAG_MINIMIZABLE));
|
|
1247
|
+
update_flag(&style, WS_MAXIMIZEBOX, has_flag(flags, Window::FLAG_RESIZABLE));
|
|
1248
|
+
update_flag(&style, WS_THICKFRAME, sizing_border);
|
|
1249
|
+
|
|
1250
|
+
return style;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
static void
|
|
1254
|
+
set_window_style (HWND hwnd, DWORD style)
|
|
1255
|
+
{
|
|
1256
|
+
RECT client = {0};
|
|
1257
|
+
bool normal = !IsIconic(hwnd) && !IsZoomed(hwnd) && GetClientRect(hwnd, &client);
|
|
1258
|
+
|
|
1259
|
+
POINT pos = {0, 0};
|
|
1260
|
+
if (normal && !ClientToScreen(hwnd, &pos))
|
|
1261
|
+
system_error(__FILE__, __LINE__);
|
|
1262
|
+
|
|
1263
|
+
RECT rect = {
|
|
1264
|
+
pos.x, pos.y,
|
|
1265
|
+
pos.x + (client.right - client.left),
|
|
1266
|
+
pos.y + (client.bottom - client.top)
|
|
1267
|
+
};
|
|
1268
|
+
|
|
1269
|
+
SetLastError(0);
|
|
1270
|
+
SetWindowLongPtrW(hwnd, GWL_STYLE, style);
|
|
1271
|
+
if (GetLastError() != 0)
|
|
1272
|
+
system_error(__FILE__, __LINE__);
|
|
1273
|
+
|
|
1274
|
+
UINT posflags = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE;
|
|
1275
|
+
if (normal)
|
|
1276
|
+
client_to_window_rect(hwnd, &rect);
|
|
1277
|
+
else
|
|
1278
|
+
posflags |= SWP_NOMOVE | SWP_NOSIZE;
|
|
1279
|
+
|
|
1280
|
+
if (!SetWindowPos(
|
|
1281
|
+
hwnd, NULL,
|
|
1282
|
+
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
|
|
1283
|
+
posflags))
|
|
1284
|
+
{
|
|
1285
|
+
system_error(__FILE__, __LINE__);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
static void
|
|
1290
|
+
set_closable (HWND hwnd, bool closable)
|
|
1291
|
+
{
|
|
1292
|
+
// the close button follows the state of the close menu item
|
|
1293
|
+
HMENU menu = GetSystemMenu(hwnd, FALSE);
|
|
1294
|
+
if (!menu) return;
|
|
1295
|
+
|
|
1296
|
+
EnableMenuItem(
|
|
1297
|
+
menu, SC_CLOSE, MF_BYCOMMAND | (closable ? MF_ENABLED : MF_GRAYED));
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
static void
|
|
1301
|
+
set_unlisted (HWND hwnd, bool state)
|
|
1302
|
+
{
|
|
1303
|
+
DWORD current = (DWORD) GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
|
|
1304
|
+
DWORD exstyle = state
|
|
1305
|
+
? current | WS_EX_TOOLWINDOW
|
|
1306
|
+
: current & ~WS_EX_TOOLWINDOW;
|
|
1307
|
+
if (exstyle == current) return;
|
|
1308
|
+
|
|
1309
|
+
SetLastError(0);
|
|
1310
|
+
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exstyle);
|
|
1311
|
+
if (GetLastError() != 0)
|
|
1312
|
+
system_error(__FILE__, __LINE__);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
720
1315
|
void
|
|
721
1316
|
Window_set_flags (Window* window, uint flags)
|
|
722
1317
|
{
|
|
1318
|
+
if (
|
|
1319
|
+
Xot::has_flag(flags, Window::FLAG_TITLEBAR_BUTTONS) &&
|
|
1320
|
+
!Xot::has_flag(flags, Window::FLAG_TITLEBAR_BACKGROUND))
|
|
1321
|
+
{
|
|
1322
|
+
argument_error(
|
|
1323
|
+
__FILE__, __LINE__, "FLAG_TITLEBAR_BUTTONS needs FLAG_TITLEBAR_BACKGROUND");
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
if (
|
|
1327
|
+
Xot::has_flag(flags, Window::FLAG_TITLEBAR_BACKGROUND) &&
|
|
1328
|
+
!Xot::has_flag(flags, Window::FLAG_SHADOW))
|
|
1329
|
+
{
|
|
1330
|
+
argument_error(
|
|
1331
|
+
__FILE__, __LINE__, "FLAG_TITLEBAR_BACKGROUND needs FLAG_SHADOW");
|
|
1332
|
+
}
|
|
1333
|
+
|
|
723
1334
|
if (Xot::has_flag(flags, Window::FLAG_PORTRAIT))
|
|
724
1335
|
argument_error(__FILE__, __LINE__, "FLAG_PORTRAIT is not supported");
|
|
725
1336
|
|
|
726
1337
|
if (Xot::has_flag(flags, Window::FLAG_LANDSCAPE))
|
|
727
1338
|
argument_error(__FILE__, __LINE__, "FLAG_LANDSCAPE is not supported");
|
|
1339
|
+
|
|
1340
|
+
if (!*window)
|
|
1341
|
+
invalid_state_error(__FILE__, __LINE__);
|
|
1342
|
+
|
|
1343
|
+
WindowData* self = get_data(window);
|
|
1344
|
+
|
|
1345
|
+
bool transparent = Xot::has_flag(flags, Window::FLAG_TRANSPARENT);
|
|
1346
|
+
if (transparent != self->transparent)
|
|
1347
|
+
{
|
|
1348
|
+
set_background_transparent(self->hwnd, transparent);
|
|
1349
|
+
self->transparent = transparent;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
DWORD current = (DWORD) GetWindowLongPtrW(self->hwnd, GWL_STYLE);
|
|
1353
|
+
DWORD style = make_window_style(flags, current);
|
|
1354
|
+
if (style != current)
|
|
1355
|
+
set_window_style(self->hwnd, style);
|
|
1356
|
+
|
|
1357
|
+
set_closable(self->hwnd, Xot::has_flag(flags, Window::FLAG_CLOSABLE));
|
|
1358
|
+
|
|
1359
|
+
set_unlisted(self->hwnd, Xot::has_flag(flags, Window::FLAG_UNLISTED));
|
|
1360
|
+
|
|
1361
|
+
HWND after = HWND_NOTOPMOST;
|
|
1362
|
+
if (Xot::has_flag(flags, Window::FLAG_ALWAYS_ON_TOP))
|
|
1363
|
+
after = HWND_TOPMOST;
|
|
1364
|
+
else if (Xot::has_flag(flags, Window::FLAG_ALWAYS_ON_BOTTOM))
|
|
1365
|
+
after = HWND_BOTTOM;
|
|
1366
|
+
if (!SetWindowPos(
|
|
1367
|
+
self->hwnd, after, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE))
|
|
1368
|
+
{
|
|
1369
|
+
system_error(__FILE__, __LINE__);
|
|
1370
|
+
}
|
|
728
1371
|
}
|
|
729
1372
|
|
|
730
1373
|
float
|
|
731
1374
|
Window_get_pixel_density (const Window& window)
|
|
732
1375
|
{
|
|
733
|
-
|
|
1376
|
+
HWND hwnd = get_data(&window)->hwnd;
|
|
1377
|
+
return Screen_get_pixel_density(
|
|
1378
|
+
hwnd ? MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) : NULL);
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
Point
|
|
1382
|
+
Window_from_native_coord (const Window& window, coord x, coord y)
|
|
1383
|
+
{
|
|
1384
|
+
float density = Window_get_pixel_density(window);
|
|
1385
|
+
return Point(x / density, y / density);
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
POINT
|
|
1389
|
+
Window_to_native_coord (const Window& window, const Point& point)
|
|
1390
|
+
{
|
|
1391
|
+
float density = Window_get_pixel_density(window);
|
|
1392
|
+
return {
|
|
1393
|
+
(LONG) lround(point.x * density),
|
|
1394
|
+
(LONG) lround(point.y * density)
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
void
|
|
1399
|
+
Window_set_pointer_through (Window* window, bool through)
|
|
1400
|
+
{
|
|
1401
|
+
static const DWORD THROUGH = WS_EX_TRANSPARENT | WS_EX_LAYERED;
|
|
1402
|
+
|
|
1403
|
+
HWND hwnd = get_data(window)->hwnd;
|
|
1404
|
+
DWORD current = (DWORD) GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
|
|
1405
|
+
DWORD exstyle = through ? current | THROUGH : current & ~THROUGH;
|
|
1406
|
+
if (exstyle == current) return;
|
|
1407
|
+
|
|
1408
|
+
SetLastError(0);
|
|
1409
|
+
SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exstyle);
|
|
1410
|
+
if (GetLastError() != 0)
|
|
1411
|
+
system_error(__FILE__, __LINE__);
|
|
1412
|
+
|
|
1413
|
+
if (through && !SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA))
|
|
1414
|
+
system_error(__FILE__, __LINE__);
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
static bool
|
|
1418
|
+
is_covered_by_another_window (HWND hwnd, POINT pos)
|
|
1419
|
+
{
|
|
1420
|
+
// only a window that takes mouse events counts as covering. the hit
|
|
1421
|
+
// test skips a window letting pointers through, so the hit can be one
|
|
1422
|
+
// below hwnd itself; it covers hwnd when it is among the windows above
|
|
1423
|
+
|
|
1424
|
+
HWND hit = WindowFromPoint(pos);
|
|
1425
|
+
if (hit) hit = GetAncestor(hit, GA_ROOT);
|
|
1426
|
+
if (!hit || hit == hwnd)
|
|
1427
|
+
return false;
|
|
1428
|
+
|
|
1429
|
+
for (HWND h = GetWindow(hwnd, GW_HWNDPREV); h; h = GetWindow(h, GW_HWNDPREV))
|
|
1430
|
+
{
|
|
1431
|
+
if (h == hit)
|
|
1432
|
+
return true;
|
|
1433
|
+
}
|
|
1434
|
+
return false;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
bool
|
|
1438
|
+
Window_is_pointer_over_and_uncovered (Point* position, const Window& window)
|
|
1439
|
+
{
|
|
1440
|
+
POINT pos;
|
|
1441
|
+
if (!GetCursorPos(&pos))
|
|
1442
|
+
return false;
|
|
1443
|
+
|
|
1444
|
+
HWND hwnd = get_data(&window)->hwnd;
|
|
1445
|
+
RECT rect;
|
|
1446
|
+
if (!GetWindowRect(hwnd, &rect))
|
|
1447
|
+
return false;
|
|
1448
|
+
if (!PtInRect(&rect, pos))
|
|
1449
|
+
return false;
|
|
1450
|
+
if (is_covered_by_another_window(hwnd, pos))
|
|
1451
|
+
return false;
|
|
1452
|
+
if (!ScreenToClient(hwnd, &pos))
|
|
1453
|
+
return false;
|
|
1454
|
+
|
|
1455
|
+
*position = Window_from_native_coord(window, pos.x, pos.y);
|
|
1456
|
+
return true;
|
|
734
1457
|
}
|
|
735
1458
|
|
|
736
1459
|
|