reflexion 0.4.0 → 0.4.2
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/ChangeLog.md +18 -0
- data/VERSION +1 -1
- data/reflex.gemspec +3 -3
- data/samples/multi_window.rb +80 -0
- data/src/ios/event.h +1 -1
- data/src/ios/event.mm +2 -2
- data/src/ios/view_controller.mm +71 -4
- data/src/osx/event.h +1 -1
- data/src/osx/event.mm +2 -4
- data/src/osx/native_window.mm +21 -8
- data/src/osx/opengl_view.mm +27 -50
- data/src/sdl/opengl.cpp +16 -14
- data/src/sdl/opengl.h +2 -2
- data/src/sdl/window.cpp +34 -5
- data/src/view.cpp +3 -5
- data/src/win32/opengl.cpp +17 -40
- data/src/win32/opengl.h +0 -2
- data/src/win32/window.cpp +32 -15
- data/src/window.cpp +0 -1
- data/test/test_midi_event.rb +2 -2
- metadata +9 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 385852765cb2073b46cffebf4c22bcd1e432f4d17b911f7cde7d67864add658b
|
|
4
|
+
data.tar.gz: 8645ad9b05be24a1f69c241757b4dda8004a36411704932729872d6a0410ee79
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1577fd876c000d34cb1435732f83292fcb27a940493926f1d8209f77cac8bc58da08e9782e629894a683b7e0624dba9c1786a1c4526732c051d17d3d3d40c628
|
|
7
|
+
data.tar.gz: 121844b893ea518437ab0eb2cd255af14c9c804af32281624ecde6629358b633339294530944b209dac3cfe4fcf1b242363a208df747a5b181f9c269aa60340b
|
data/ChangeLog.md
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# reflex ChangeLog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## [v0.4.2] - 2026-06-12
|
|
5
|
+
|
|
6
|
+
- Share single offscreen GL context across windows
|
|
7
|
+
- Apply GC-root rebind pattern to window lifecycle on Win32 and SDL
|
|
8
|
+
- Lazy-initialize OpenGL context until first drawRect:
|
|
9
|
+
- Fire on_close by the close button on SDL
|
|
10
|
+
- Do not destroy the view tree in Window#close to survive closing on event handlers
|
|
11
|
+
- Add multi_window sample to demonstrate cross-window texture sharing
|
|
12
|
+
|
|
13
|
+
- Fix iterator invalidation in View::clear_children
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [v0.4.1] - 2026-05-20
|
|
17
|
+
|
|
18
|
+
- Track actual key repeat count on macOS
|
|
19
|
+
- Add key repeat on iOS
|
|
20
|
+
|
|
21
|
+
|
|
4
22
|
## [v0.4.0] - 2026-05-17
|
|
5
23
|
|
|
6
24
|
- [BREAKING] Normalize wheel Y delta to top-left origin convention
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.4.
|
|
1
|
+
0.4.2
|
data/reflex.gemspec
CHANGED
|
@@ -25,9 +25,9 @@ Gem::Specification.new do |s|
|
|
|
25
25
|
s.platform = Gem::Platform::RUBY
|
|
26
26
|
s.required_ruby_version = '>= 3.0.0'
|
|
27
27
|
|
|
28
|
-
s.add_dependency 'xot', '~> 0.3.
|
|
29
|
-
s.add_dependency 'rucy', '~> 0.3.
|
|
30
|
-
s.add_dependency 'rays', '~> 0.3.
|
|
28
|
+
s.add_dependency 'xot', '~> 0.3.14'
|
|
29
|
+
s.add_dependency 'rucy', '~> 0.3.14'
|
|
30
|
+
s.add_dependency 'rays', '~> 0.3.15'
|
|
31
31
|
|
|
32
32
|
s.files = `git ls-files`.split $/
|
|
33
33
|
s.executables = s.files.grep(%r{^bin/}) {|f| File.basename f}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
%w[xot rays reflex]
|
|
2
|
+
.map {|s| File.expand_path "../../#{s}/lib", __dir__}
|
|
3
|
+
.each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
|
|
4
|
+
|
|
5
|
+
require 'reflex'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Shared off-screen canvas. The same Rays::Image is rendered into by
|
|
9
|
+
# SourceWindow and sampled as a texture by MirrorWindow. This only works
|
|
10
|
+
# because all Reflex windows share a single GL context, so a texture
|
|
11
|
+
# allocated in one window is visible to the others.
|
|
12
|
+
SIZE = 300
|
|
13
|
+
CANVAS = Rays::Image.new SIZE, SIZE
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SourceWindow < Reflex::Window
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
super title: 'source', frame: [80, 80, SIZE + 20, SIZE + 40]
|
|
20
|
+
@t = 0.0
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def on_draw (e)
|
|
24
|
+
@t += 0.04
|
|
25
|
+
|
|
26
|
+
CANVAS.paint do |p|
|
|
27
|
+
# fade the previous frame so dots leave fading trails
|
|
28
|
+
p.no_stroke
|
|
29
|
+
p.fill 0, 0, 0, 0.06
|
|
30
|
+
p.rect 0, 0, SIZE, SIZE
|
|
31
|
+
|
|
32
|
+
6.times do |i|
|
|
33
|
+
a = @t + i * Math::PI / 3
|
|
34
|
+
r = 110 + Math.sin(@t * 0.6 + i) * 25
|
|
35
|
+
x = SIZE / 2 + Math.cos(a) * r
|
|
36
|
+
y = SIZE / 2 + Math.sin(a) * r
|
|
37
|
+
p.fill (Math.sin(@t + i) + 1) / 2,
|
|
38
|
+
(Math.sin(@t + i + 2.1) + 1) / 2,
|
|
39
|
+
(Math.sin(@t + i + 4.2) + 1) / 2
|
|
40
|
+
p.ellipse x, y, 16, 16
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
e.painter.background 0.1
|
|
45
|
+
e.painter.image CANVAS, 10, 10
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def on_update (e) = redraw
|
|
49
|
+
|
|
50
|
+
end# SourceWindow
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class MirrorWindow < Reflex::Window
|
|
54
|
+
|
|
55
|
+
TILE = SIZE / 2
|
|
56
|
+
SCALES = [[1.0, 1.0], [1.0, 0.5], [0.5, 1.0], [0.5, 0.5]]
|
|
57
|
+
|
|
58
|
+
def initialize
|
|
59
|
+
super title: 'mirror', frame: [420, 80, TILE * 2 + 20, TILE * 2 + 40]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def on_draw (e)
|
|
63
|
+
p = e.painter
|
|
64
|
+
p.background 0
|
|
65
|
+
4.times do |i|
|
|
66
|
+
row, col = i / 2, i % 2
|
|
67
|
+
sx, sy = SCALES[i]
|
|
68
|
+
p.image CANVAS, col * TILE, row * TILE, TILE * sx, TILE * sy
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def on_update (e) = redraw
|
|
73
|
+
|
|
74
|
+
end# MirrorWindow
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
Reflex.start do
|
|
78
|
+
SourceWindow.new.show
|
|
79
|
+
MirrorWindow.new.show
|
|
80
|
+
end
|
data/src/ios/event.h
CHANGED
data/src/ios/event.mm
CHANGED
|
@@ -115,10 +115,10 @@ namespace Reflex
|
|
|
115
115
|
return s.UTF8String;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
NativeKeyEvent::NativeKeyEvent (UIPress* press, Action action)
|
|
118
|
+
NativeKeyEvent::NativeKeyEvent (UIPress* press, Action action, int repeat)
|
|
119
119
|
: KeyEvent(
|
|
120
120
|
action, get_chars(press.key), (int) press.key.keyCode,
|
|
121
|
-
to_modifiers(press.key.modifierFlags),
|
|
121
|
+
to_modifiers(press.key.modifierFlags), repeat)
|
|
122
122
|
{
|
|
123
123
|
}
|
|
124
124
|
|
data/src/ios/view_controller.mm
CHANGED
|
@@ -65,6 +65,14 @@ show_reflex_view_controller (
|
|
|
65
65
|
[top presentViewController: reflex_vc animated: YES completion: nil];
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
static BOOL
|
|
69
|
+
is_modifier_key (long keyCode) API_AVAILABLE(ios(13.4))
|
|
70
|
+
{
|
|
71
|
+
return
|
|
72
|
+
keyCode >= UIKeyboardHIDUsageKeyboardLeftControl &&
|
|
73
|
+
keyCode <= UIKeyboardHIDUsageKeyboardRightGUI;
|
|
74
|
+
}
|
|
75
|
+
|
|
68
76
|
|
|
69
77
|
namespace global
|
|
70
78
|
{
|
|
@@ -129,6 +137,10 @@ ReflexViewController_get_show_fun ()
|
|
|
129
137
|
|
|
130
138
|
@property(nonatomic, strong) UIHoverGestureRecognizer* hoverRecognizer;
|
|
131
139
|
|
|
140
|
+
@property(nonatomic, strong) UIPress* repeatingKeyPress;
|
|
141
|
+
|
|
142
|
+
@property(nonatomic, strong) NSTimer* repeatingKeyTimer;
|
|
143
|
+
|
|
132
144
|
@end
|
|
133
145
|
|
|
134
146
|
|
|
@@ -138,6 +150,7 @@ ReflexViewController_get_show_fun ()
|
|
|
138
150
|
Reflex::Window *pwindow, *ptr_for_rebind;
|
|
139
151
|
int update_count;
|
|
140
152
|
int touching_count;
|
|
153
|
+
int repeating_key_count;
|
|
141
154
|
}
|
|
142
155
|
|
|
143
156
|
- (id) init
|
|
@@ -145,10 +158,11 @@ ReflexViewController_get_show_fun ()
|
|
|
145
158
|
self = [super init];
|
|
146
159
|
if (!self) return nil;
|
|
147
160
|
|
|
148
|
-
pwindow
|
|
149
|
-
ptr_for_rebind
|
|
150
|
-
update_count
|
|
151
|
-
touching_count
|
|
161
|
+
pwindow =
|
|
162
|
+
ptr_for_rebind = NULL;
|
|
163
|
+
update_count = 0;
|
|
164
|
+
touching_count = 0;
|
|
165
|
+
repeating_key_count = 0;
|
|
152
166
|
|
|
153
167
|
return self;
|
|
154
168
|
}
|
|
@@ -301,6 +315,8 @@ ReflexViewController_get_show_fun ()
|
|
|
301
315
|
ReflexView* view = self.reflexView;
|
|
302
316
|
if (!view) return;
|
|
303
317
|
|
|
318
|
+
[self stopKeyRepeat];
|
|
319
|
+
|
|
304
320
|
if (view.context && view.context == [EAGLContext currentContext])
|
|
305
321
|
Rays::activate_offscreen_context();
|
|
306
322
|
|
|
@@ -333,6 +349,7 @@ ReflexViewController_get_show_fun ()
|
|
|
333
349
|
|
|
334
350
|
- (void) viewDidDisappear: (BOOL) animated
|
|
335
351
|
{
|
|
352
|
+
[self stopKeyRepeat];
|
|
336
353
|
[self resignFirstResponder];
|
|
337
354
|
|
|
338
355
|
[NSNotificationCenter.defaultCenter
|
|
@@ -357,6 +374,7 @@ ReflexViewController_get_show_fun ()
|
|
|
357
374
|
|
|
358
375
|
- (void) willResignActive
|
|
359
376
|
{
|
|
377
|
+
[self stopKeyRepeat];
|
|
360
378
|
Window_call_deactivate_event(self.window);
|
|
361
379
|
}
|
|
362
380
|
|
|
@@ -638,7 +656,56 @@ ReflexViewController_get_show_fun ()
|
|
|
638
656
|
if (!press.key) continue;
|
|
639
657
|
Reflex::NativeKeyEvent e(press, action);
|
|
640
658
|
Window_call_key_event(win, &e);
|
|
659
|
+
|
|
660
|
+
if (action == Reflex::KeyEvent::DOWN)
|
|
661
|
+
{
|
|
662
|
+
if (!is_modifier_key(press.key.keyCode))
|
|
663
|
+
[self startKeyRepeat: press];
|
|
664
|
+
}
|
|
665
|
+
else if (
|
|
666
|
+
self.repeatingKeyPress &&
|
|
667
|
+
press.key.keyCode == self.repeatingKeyPress.key.keyCode)
|
|
668
|
+
{
|
|
669
|
+
[self stopKeyRepeat];
|
|
670
|
+
}
|
|
641
671
|
}
|
|
642
672
|
}
|
|
643
673
|
|
|
674
|
+
- (void) startKeyRepeat: (UIPress*) press
|
|
675
|
+
API_AVAILABLE(ios(13.4))
|
|
676
|
+
{
|
|
677
|
+
[self stopKeyRepeat];
|
|
678
|
+
|
|
679
|
+
repeating_key_count = 0;
|
|
680
|
+
self.repeatingKeyPress = press;
|
|
681
|
+
self.repeatingKeyTimer = [NSTimer scheduledTimerWithTimeInterval: 0.4
|
|
682
|
+
target: self selector: @selector(keyRepeatFired:) userInfo: nil repeats: NO];
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
- (void) keyRepeatFired: (NSTimer*) timer
|
|
686
|
+
API_AVAILABLE(ios(13.4))
|
|
687
|
+
{
|
|
688
|
+
Reflex::Window* win = self.window;
|
|
689
|
+
UIPress* press = self.repeatingKeyPress;
|
|
690
|
+
if (!win || !press || !press.key)
|
|
691
|
+
{
|
|
692
|
+
[self stopKeyRepeat];
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
Reflex::NativeKeyEvent e(press, Reflex::KeyEvent::DOWN, ++repeating_key_count);
|
|
697
|
+
Window_call_key_event(win, &e);
|
|
698
|
+
|
|
699
|
+
self.repeatingKeyTimer = [NSTimer scheduledTimerWithTimeInterval: 0.1
|
|
700
|
+
target: self selector: @selector(keyRepeatFired:) userInfo: nil repeats: NO];
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
- (void) stopKeyRepeat
|
|
704
|
+
{
|
|
705
|
+
[self.repeatingKeyTimer invalidate];
|
|
706
|
+
self.repeatingKeyTimer = nil;
|
|
707
|
+
self.repeatingKeyPress = nil;
|
|
708
|
+
repeating_key_count = 0;
|
|
709
|
+
}
|
|
710
|
+
|
|
644
711
|
@end// ReflexViewController
|
data/src/osx/event.h
CHANGED
data/src/osx/event.mm
CHANGED
|
@@ -52,10 +52,8 @@ namespace Reflex
|
|
|
52
52
|
return [chars UTF8String];
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
NativeKeyEvent::NativeKeyEvent (NSEvent* e, Action action)
|
|
56
|
-
: KeyEvent(
|
|
57
|
-
action, get_chars(e), [e keyCode],
|
|
58
|
-
get_modifiers(e), [e isARepeat] ? 1 : 0)
|
|
55
|
+
NativeKeyEvent::NativeKeyEvent (NSEvent* e, Action action, int repeat)
|
|
56
|
+
: KeyEvent(action, get_chars(e), [e keyCode], get_modifiers(e), repeat)
|
|
59
57
|
{
|
|
60
58
|
}
|
|
61
59
|
|
data/src/osx/native_window.mm
CHANGED
|
@@ -56,6 +56,8 @@ move_to_main_screen_origin (NativeWindow* window)
|
|
|
56
56
|
OpenGLView* view;
|
|
57
57
|
NSTimer* timer;
|
|
58
58
|
int update_count;
|
|
59
|
+
int repeating_key_code;
|
|
60
|
+
int repeating_key_count;
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
- (id) init
|
|
@@ -67,11 +69,13 @@ move_to_main_screen_origin (NativeWindow* window)
|
|
|
67
69
|
defer: NO];
|
|
68
70
|
if (!self) return nil;
|
|
69
71
|
|
|
70
|
-
pwindow
|
|
71
|
-
ptr_for_rebind
|
|
72
|
-
view
|
|
73
|
-
timer
|
|
74
|
-
update_count
|
|
72
|
+
pwindow =
|
|
73
|
+
ptr_for_rebind = NULL;
|
|
74
|
+
view = nil;
|
|
75
|
+
timer = nil;
|
|
76
|
+
update_count = 0;
|
|
77
|
+
repeating_key_code = -1;
|
|
78
|
+
repeating_key_count = 0;
|
|
75
79
|
|
|
76
80
|
[self setDelegate: self];
|
|
77
81
|
[self setupContentView];
|
|
@@ -102,8 +106,8 @@ move_to_main_screen_origin (NativeWindow* window)
|
|
|
102
106
|
// ruby value references native window weakly.
|
|
103
107
|
data.native = self;
|
|
104
108
|
|
|
105
|
-
// Reflex::Window is not constructed
|
|
106
|
-
// so
|
|
109
|
+
// Reflex::Window is not fully constructed yet,
|
|
110
|
+
// so cannot call ClassWrapper::retain().
|
|
107
111
|
window->Xot::template RefCountable<>::retain();
|
|
108
112
|
|
|
109
113
|
// defer calling ClassWrapper::retain() to rebind.
|
|
@@ -365,7 +369,16 @@ move_to_main_screen_origin (NativeWindow* window)
|
|
|
365
369
|
Reflex::Window* win = self.window;
|
|
366
370
|
if (!win) return;
|
|
367
371
|
|
|
368
|
-
|
|
372
|
+
int code = (int) event.keyCode;
|
|
373
|
+
if (event.isARepeat && code == repeating_key_code)
|
|
374
|
+
++repeating_key_count;
|
|
375
|
+
else
|
|
376
|
+
{
|
|
377
|
+
repeating_key_code = code;
|
|
378
|
+
repeating_key_count = 0;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
Reflex::NativeKeyEvent e(event, Reflex::KeyEvent::DOWN, repeating_key_count);
|
|
369
382
|
Window_call_key_event(win, &e);
|
|
370
383
|
}
|
|
371
384
|
|
data/src/osx/opengl_view.mm
CHANGED
|
@@ -2,55 +2,20 @@
|
|
|
2
2
|
#import "opengl_view.h"
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
#include <vector>
|
|
6
5
|
#import <Cocoa/Cocoa.h>
|
|
7
6
|
#import <OpenGL/OpenGL.h>
|
|
7
|
+
#include <rays/rays.h>
|
|
8
8
|
#import "native_window.h"
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
//#define TRANSPARENT_BACKGROUND
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
is_valid_antialias_nsample (int n)
|
|
16
|
-
{
|
|
17
|
-
return n == 0 || n == 2 || n == 4 || n == 6 || n == 8 || n == 16 || n == 32;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static NSOpenGLPixelFormat*
|
|
21
|
-
make_pixelformat (int antialias_nsample = 0)
|
|
22
|
-
{
|
|
23
|
-
if (!is_valid_antialias_nsample(antialias_nsample))
|
|
24
|
-
return nil;
|
|
14
|
+
@implementation OpenGLView
|
|
25
15
|
|
|
26
|
-
static const NSOpenGLPixelFormatAttribute DEFAULT[] =
|
|
27
|
-
{
|
|
28
|
-
//NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
|
29
|
-
NSOpenGLPFAAccelerated, NSOpenGLPFANoRecovery,
|
|
30
|
-
NSOpenGLPFADoubleBuffer,
|
|
31
|
-
NSOpenGLPFAColorSize, 32,
|
|
32
|
-
NSOpenGLPFADepthSize, 32,
|
|
33
|
-
};
|
|
34
|
-
static const NSOpenGLPixelFormatAttribute ANTIALIAS[] =
|
|
35
16
|
{
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
NSOpenGLPFASamples, (NSOpenGLPixelFormatAttribute) antialias_nsample,
|
|
39
|
-
};
|
|
40
|
-
static const size_t DEFAULT_SIZE = sizeof(DEFAULT) / sizeof(DEFAULT[0]);
|
|
41
|
-
static const size_t ANTIALIAS_SIZE = sizeof(ANTIALIAS) / sizeof(ANTIALIAS[0]);
|
|
42
|
-
|
|
43
|
-
std::vector<NSOpenGLPixelFormatAttribute> attr(
|
|
44
|
-
DEFAULT, DEFAULT + DEFAULT_SIZE);
|
|
45
|
-
if (antialias_nsample > 0)
|
|
46
|
-
attr.insert(attr.end(), ANTIALIAS, ANTIALIAS + ANTIALIAS_SIZE);
|
|
47
|
-
attr.push_back(0);
|
|
48
|
-
|
|
49
|
-
return [[[NSOpenGLPixelFormat alloc] initWithAttributes: &attr[0]] autorelease];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@implementation OpenGLView
|
|
17
|
+
bool setup_context_done;
|
|
18
|
+
}
|
|
54
19
|
|
|
55
20
|
- (id) initWithFrame: (NSRect) frame
|
|
56
21
|
{
|
|
@@ -59,30 +24,42 @@ make_pixelformat (int antialias_nsample = 0)
|
|
|
59
24
|
|
|
60
25
|
- (id) initWithFrame: (NSRect) frame antiAlias: (int) nsample
|
|
61
26
|
{
|
|
62
|
-
|
|
27
|
+
NSOpenGLContext* context = (NSOpenGLContext*) Rays::get_offscreen_context();
|
|
28
|
+
|
|
29
|
+
self = [super initWithFrame: frame pixelFormat: context.pixelFormat];
|
|
63
30
|
if (!self) return nil;
|
|
64
31
|
|
|
32
|
+
setup_context_done = false;
|
|
33
|
+
|
|
34
|
+
return self;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
- (void) setupContext
|
|
38
|
+
{
|
|
39
|
+
if (setup_context_done) return;
|
|
40
|
+
setup_context_done = true;
|
|
41
|
+
|
|
65
42
|
[self setWantsBestResolutionOpenGLSurface: YES];
|
|
66
|
-
|
|
43
|
+
|
|
44
|
+
NSOpenGLContext* context = (NSOpenGLContext*) Rays::get_offscreen_context();
|
|
45
|
+
[self setOpenGLContext: context];
|
|
67
46
|
|
|
68
47
|
GLint swapInterval = 1;
|
|
69
|
-
[
|
|
70
|
-
setValues: &swapInterval
|
|
71
|
-
forParameter: NSOpenGLCPSwapInterval];
|
|
48
|
+
[context setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval];
|
|
72
49
|
|
|
73
50
|
#ifdef TRANSPARENT_BACKGROUND
|
|
74
51
|
GLint opacity = 0;
|
|
75
|
-
[
|
|
76
|
-
setValues: &opacity
|
|
77
|
-
forParameter: NSOpenGLCPSurfaceOpacity];
|
|
52
|
+
[context setValues: &opacity forParameter: NSOpenGLCPSurfaceOpacity];
|
|
78
53
|
#endif
|
|
79
|
-
|
|
80
|
-
return self;
|
|
81
54
|
}
|
|
82
55
|
|
|
83
56
|
- (void) activateContext
|
|
84
57
|
{
|
|
85
|
-
[
|
|
58
|
+
[self setupContext];
|
|
59
|
+
|
|
60
|
+
NSOpenGLContext* context = self.openGLContext;
|
|
61
|
+
if (context.view != self) [context setView: self];
|
|
62
|
+
[context makeCurrentContext];
|
|
86
63
|
}
|
|
87
64
|
|
|
88
65
|
- (BOOL) acceptsFirstResponder
|
data/src/sdl/opengl.cpp
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include "opengl.h"
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
#include <rays/rays.h>
|
|
4
5
|
#include "reflex/exception.h"
|
|
5
6
|
|
|
6
7
|
|
|
@@ -27,9 +28,14 @@ namespace Reflex
|
|
|
27
28
|
invalid_state_error(__FILE__, __LINE__);
|
|
28
29
|
|
|
29
30
|
window = win;
|
|
30
|
-
context =
|
|
31
|
-
if (!context)
|
|
32
|
-
|
|
31
|
+
context = (SDL_GLContext) Rays::get_offscreen_context();
|
|
32
|
+
if (!context)// wasm build returns NULL
|
|
33
|
+
{
|
|
34
|
+
context = SDL_GL_CreateContext(win);
|
|
35
|
+
if (!context)
|
|
36
|
+
reflex_error(__FILE__, __LINE__, SDL_GetError());
|
|
37
|
+
owner = true;
|
|
38
|
+
}
|
|
33
39
|
|
|
34
40
|
make_current();
|
|
35
41
|
}
|
|
@@ -37,15 +43,17 @@ namespace Reflex
|
|
|
37
43
|
void
|
|
38
44
|
OpenGLContext::fin ()
|
|
39
45
|
{
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
if (context)
|
|
46
|
+
if (owner && context)
|
|
43
47
|
{
|
|
48
|
+
if (context == SDL_GL_GetCurrentContext())
|
|
49
|
+
SDL_GL_MakeCurrent(NULL, NULL);
|
|
50
|
+
|
|
44
51
|
SDL_GL_DeleteContext(context);
|
|
45
|
-
context = NULL;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
window
|
|
54
|
+
window = NULL;
|
|
55
|
+
context = NULL;
|
|
56
|
+
owner = false;
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
void
|
|
@@ -65,12 +73,6 @@ namespace Reflex
|
|
|
65
73
|
SDL_GL_SwapWindow(window);
|
|
66
74
|
}
|
|
67
75
|
|
|
68
|
-
bool
|
|
69
|
-
OpenGLContext::is_active () const
|
|
70
|
-
{
|
|
71
|
-
return *this && context == SDL_GL_GetCurrentContext();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
76
|
OpenGLContext::operator bool () const
|
|
75
77
|
{
|
|
76
78
|
return window && context;
|
data/src/sdl/opengl.h
CHANGED
|
@@ -28,8 +28,6 @@ namespace Reflex
|
|
|
28
28
|
|
|
29
29
|
void swap_buffers ();
|
|
30
30
|
|
|
31
|
-
bool is_active () const;
|
|
32
|
-
|
|
33
31
|
operator bool () const;
|
|
34
32
|
|
|
35
33
|
bool operator ! () const;
|
|
@@ -40,6 +38,8 @@ namespace Reflex
|
|
|
40
38
|
|
|
41
39
|
SDL_GLContext context = NULL;
|
|
42
40
|
|
|
41
|
+
bool owner = false;
|
|
42
|
+
|
|
43
43
|
};// OpenGLContext
|
|
44
44
|
|
|
45
45
|
|
data/src/sdl/window.cpp
CHANGED
|
@@ -22,6 +22,8 @@ namespace Reflex
|
|
|
22
22
|
|
|
23
23
|
SDL_Window* native = NULL;
|
|
24
24
|
|
|
25
|
+
bool need_rebind = false;
|
|
26
|
+
|
|
25
27
|
OpenGLContext context;
|
|
26
28
|
|
|
27
29
|
mutable String title_tmp;
|
|
@@ -47,6 +49,21 @@ namespace Reflex
|
|
|
47
49
|
|
|
48
50
|
context.init(native);
|
|
49
51
|
|
|
52
|
+
// Reflex::Window is not fully constructed yet,
|
|
53
|
+
// so cannot call ClassWrapper::retain().
|
|
54
|
+
win->Xot::template RefCountable<>::retain();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
void rebind (Window* win)
|
|
58
|
+
{
|
|
59
|
+
if (!need_rebind) return;
|
|
60
|
+
|
|
61
|
+
// deferred call of ClassWrapper::retain().
|
|
62
|
+
win->retain();
|
|
63
|
+
|
|
64
|
+
win->Xot::template RefCountable<>::release();
|
|
65
|
+
need_rebind = false;
|
|
66
|
+
|
|
50
67
|
Window_register(win);
|
|
51
68
|
}
|
|
52
69
|
|
|
@@ -54,15 +71,21 @@ namespace Reflex
|
|
|
54
71
|
{
|
|
55
72
|
if (!native) return;
|
|
56
73
|
|
|
57
|
-
context.fin();
|
|
58
|
-
|
|
59
74
|
Window* win = Window_from(native);
|
|
60
|
-
if (win)
|
|
75
|
+
if (win)
|
|
76
|
+
{
|
|
77
|
+
rebind(win);
|
|
78
|
+
Window_unregister(win);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
context.fin();
|
|
61
82
|
|
|
62
83
|
SDL_SetWindowData(native, WINDOW_DATA_KEY, NULL);
|
|
63
84
|
SDL_DestroyWindow(native);
|
|
64
85
|
native = NULL;
|
|
65
86
|
|
|
87
|
+
if (win) win->release();
|
|
88
|
+
|
|
66
89
|
if (Window_all().empty())
|
|
67
90
|
Reflex::app()->quit();
|
|
68
91
|
}
|
|
@@ -181,7 +204,11 @@ namespace Reflex
|
|
|
181
204
|
void
|
|
182
205
|
Window_initialize (Window* win)
|
|
183
206
|
{
|
|
184
|
-
get_data(win)
|
|
207
|
+
WindowData* self = get_data(win);
|
|
208
|
+
|
|
209
|
+
self->create(win);
|
|
210
|
+
|
|
211
|
+
self->need_rebind = true;
|
|
185
212
|
}
|
|
186
213
|
|
|
187
214
|
void
|
|
@@ -322,6 +349,8 @@ namespace Reflex
|
|
|
322
349
|
{
|
|
323
350
|
WindowData* self = get_data(win);
|
|
324
351
|
|
|
352
|
+
self->rebind(win);
|
|
353
|
+
|
|
325
354
|
switch (event.type)
|
|
326
355
|
{
|
|
327
356
|
case SDL_WINDOWEVENT:
|
|
@@ -329,7 +358,7 @@ namespace Reflex
|
|
|
329
358
|
switch (event.window.event)
|
|
330
359
|
{
|
|
331
360
|
case SDL_WINDOWEVENT_CLOSE:
|
|
332
|
-
|
|
361
|
+
win->close();
|
|
333
362
|
break;
|
|
334
363
|
|
|
335
364
|
case SDL_WINDOWEVENT_EXPOSED:
|
data/src/view.cpp
CHANGED
|
@@ -1890,11 +1890,9 @@ namespace Reflex
|
|
|
1890
1890
|
void
|
|
1891
1891
|
View::clear_children ()
|
|
1892
1892
|
{
|
|
1893
|
-
auto
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
for (auto& child : *children)
|
|
1897
|
-
remove_child(child);
|
|
1893
|
+
const auto& children = self->pchildren;
|
|
1894
|
+
while (children && !children->empty())
|
|
1895
|
+
remove_child(children->back());
|
|
1898
1896
|
}
|
|
1899
1897
|
|
|
1900
1898
|
View::ChildList
|
data/src/win32/opengl.cpp
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
#include "opengl.h"
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
#include <rays/rays.h>
|
|
4
5
|
#include "reflex/exception.h"
|
|
5
6
|
|
|
6
7
|
|
|
8
|
+
namespace Rays
|
|
9
|
+
{
|
|
10
|
+
|
|
11
|
+
const PIXELFORMATDESCRIPTOR* get_pixel_format_descriptor ();
|
|
12
|
+
|
|
13
|
+
}// Rays
|
|
14
|
+
|
|
15
|
+
|
|
7
16
|
namespace Reflex
|
|
8
17
|
{
|
|
9
18
|
|
|
@@ -31,22 +40,15 @@ namespace Reflex
|
|
|
31
40
|
if (!hdc)
|
|
32
41
|
system_error(__FILE__, __LINE__);
|
|
33
42
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
sizeof(PIXELFORMATDESCRIPTOR), 1,
|
|
37
|
-
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
|
|
38
|
-
PFD_TYPE_RGBA, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0,
|
|
39
|
-
PFD_MAIN_PLANE, 0, 0, 0, 0
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
int pf = ChoosePixelFormat(hdc, &PFD);
|
|
43
|
+
const auto* pfd = Rays::get_pixel_format_descriptor();
|
|
44
|
+
int pf = ChoosePixelFormat(hdc, pfd);
|
|
43
45
|
if (pf == 0)
|
|
44
46
|
system_error(__FILE__, __LINE__);
|
|
45
47
|
|
|
46
|
-
if (!SetPixelFormat(hdc, pf,
|
|
48
|
+
if (!SetPixelFormat(hdc, pf, pfd))
|
|
47
49
|
system_error(__FILE__, __LINE__);
|
|
48
50
|
|
|
49
|
-
hrc =
|
|
51
|
+
hrc = (HGLRC) Rays::get_offscreen_context();
|
|
50
52
|
if (!hrc)
|
|
51
53
|
system_error(__FILE__, __LINE__);
|
|
52
54
|
|
|
@@ -56,31 +58,12 @@ namespace Reflex
|
|
|
56
58
|
void
|
|
57
59
|
OpenGLContext::fin ()
|
|
58
60
|
{
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
if (hrc)
|
|
62
|
-
{
|
|
63
|
-
if (hrc == wglGetCurrentContext())
|
|
64
|
-
{
|
|
65
|
-
if (!wglMakeCurrent(NULL, NULL))
|
|
66
|
-
system_error(__FILE__, __LINE__);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!wglDeleteContext(hrc))
|
|
70
|
-
system_error(__FILE__, __LINE__);
|
|
71
|
-
|
|
72
|
-
hrc = NULL;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (hdc)
|
|
76
|
-
{
|
|
77
|
-
if (!ReleaseDC(hwnd, hdc))
|
|
78
|
-
system_error(__FILE__, __LINE__);
|
|
79
|
-
|
|
80
|
-
hdc = NULL;
|
|
81
|
-
}
|
|
61
|
+
if (hdc && !ReleaseDC(hwnd, hdc))
|
|
62
|
+
system_error(__FILE__, __LINE__);
|
|
82
63
|
|
|
83
64
|
hwnd = NULL;
|
|
65
|
+
hdc = NULL;
|
|
66
|
+
hrc = NULL;
|
|
84
67
|
}
|
|
85
68
|
|
|
86
69
|
void
|
|
@@ -101,12 +84,6 @@ namespace Reflex
|
|
|
101
84
|
system_error(__FILE__, __LINE__);
|
|
102
85
|
}
|
|
103
86
|
|
|
104
|
-
bool
|
|
105
|
-
OpenGLContext::is_active () const
|
|
106
|
-
{
|
|
107
|
-
return *this && hrc == wglGetCurrentContext();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
87
|
OpenGLContext::operator bool () const
|
|
111
88
|
{
|
|
112
89
|
return hwnd && hdc && hrc;
|
data/src/win32/opengl.h
CHANGED
data/src/win32/window.cpp
CHANGED
|
@@ -32,7 +32,9 @@ namespace Reflex
|
|
|
32
32
|
struct WindowData : public Window::Data
|
|
33
33
|
{
|
|
34
34
|
|
|
35
|
-
HWND hwnd
|
|
35
|
+
HWND hwnd = NULL;
|
|
36
|
+
|
|
37
|
+
bool need_rebind = false;
|
|
36
38
|
|
|
37
39
|
OpenGLContext context;
|
|
38
40
|
|
|
@@ -118,7 +120,25 @@ namespace Reflex
|
|
|
118
120
|
|
|
119
121
|
self->hwnd = hwnd;
|
|
120
122
|
self->context.init(hwnd);
|
|
123
|
+
|
|
124
|
+
// Reflex::Window is not fully constructed yet,
|
|
125
|
+
// so cannot call ClassWrapper::retain().
|
|
126
|
+
win->Xot::template RefCountable<>::retain();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static inline void
|
|
130
|
+
rebind (Window* win)
|
|
131
|
+
{
|
|
132
|
+
WindowData* self = get_data(win);
|
|
133
|
+
if (!self->need_rebind) return;
|
|
134
|
+
|
|
135
|
+
// deferred call of ClassWrapper::retain().
|
|
121
136
|
win->retain();
|
|
137
|
+
|
|
138
|
+
win->Xot::template RefCountable<>::release();
|
|
139
|
+
self->need_rebind = false;
|
|
140
|
+
|
|
141
|
+
Window_register(win);
|
|
122
142
|
}
|
|
123
143
|
|
|
124
144
|
static void
|
|
@@ -127,6 +147,9 @@ namespace Reflex
|
|
|
127
147
|
if (!*win)
|
|
128
148
|
Xot::invalid_state_error(__FILE__, __LINE__);
|
|
129
149
|
|
|
150
|
+
rebind(win);
|
|
151
|
+
Window_unregister(win);
|
|
152
|
+
|
|
130
153
|
WindowData* self = get_data(win);
|
|
131
154
|
|
|
132
155
|
if (window_has_wndproc(self->hwnd))
|
|
@@ -142,12 +165,13 @@ namespace Reflex
|
|
|
142
165
|
system_error(__FILE__, __LINE__);
|
|
143
166
|
}
|
|
144
167
|
|
|
145
|
-
if (self->context.is_active())
|
|
146
|
-
Rays::activate_offscreen_context();
|
|
147
|
-
|
|
148
168
|
self->context.fin();
|
|
149
169
|
self->hwnd = NULL;
|
|
170
|
+
|
|
150
171
|
win->release();
|
|
172
|
+
|
|
173
|
+
if (Window_all().empty())
|
|
174
|
+
Reflex::app()->quit();
|
|
151
175
|
}
|
|
152
176
|
|
|
153
177
|
void
|
|
@@ -456,25 +480,16 @@ namespace Reflex
|
|
|
456
480
|
CREATESTRUCT* cs = (CREATESTRUCT*) lp;
|
|
457
481
|
win = (Window*) cs->lpCreateParams;
|
|
458
482
|
setup_window(win, hwnd);
|
|
459
|
-
|
|
460
|
-
Window_register(win);
|
|
461
483
|
}
|
|
462
484
|
|
|
463
|
-
if (!win)
|
|
464
|
-
|
|
485
|
+
if (!win) win = get_window_from_hwnd(hwnd);
|
|
486
|
+
if (win) rebind(win);
|
|
465
487
|
|
|
466
488
|
LRESULT ret = window_proc(win, hwnd, msg, wp, lp);
|
|
467
489
|
|
|
468
490
|
if (msg == WM_NCDESTROY)
|
|
469
|
-
{
|
|
470
|
-
Window_unregister(win);
|
|
471
|
-
|
|
472
491
|
cleanup_window(win);
|
|
473
492
|
|
|
474
|
-
if (Window_all().empty())
|
|
475
|
-
Reflex::app()->quit();
|
|
476
|
-
}
|
|
477
|
-
|
|
478
493
|
return ret;
|
|
479
494
|
}
|
|
480
495
|
|
|
@@ -546,6 +561,8 @@ namespace Reflex
|
|
|
546
561
|
Window_initialize (Window* window)
|
|
547
562
|
{
|
|
548
563
|
create_window(window);
|
|
564
|
+
|
|
565
|
+
get_data(window)->need_rebind = true;
|
|
549
566
|
}
|
|
550
567
|
|
|
551
568
|
void
|
data/src/window.cpp
CHANGED
data/test/test_midi_event.rb
CHANGED
|
@@ -86,8 +86,8 @@ class TestMIDIEvent < Test::Unit::TestCase
|
|
|
86
86
|
assert_equal 5, event(0xC5, 1, 2, 3).channel
|
|
87
87
|
assert_equal 6, event(0xD6, 1, 2, 3).channel
|
|
88
88
|
assert_equal 7, event(0xE7, 1, 2, 3).channel
|
|
89
|
-
assert_equal
|
|
90
|
-
assert_equal
|
|
89
|
+
assert_equal(-1, event(0xF8, 1, 2, 3).channel)
|
|
90
|
+
assert_equal(-1, event(0x00, 1, 2, 3).channel)
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
end# TestMIDIEvent
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: reflexion
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- xordog
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: xot
|
|
@@ -16,42 +16,42 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 0.3.
|
|
19
|
+
version: 0.3.14
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 0.3.
|
|
26
|
+
version: 0.3.14
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rucy
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: 0.3.
|
|
33
|
+
version: 0.3.14
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: 0.3.
|
|
40
|
+
version: 0.3.14
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rays
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 0.3.
|
|
47
|
+
version: 0.3.15
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 0.3.
|
|
54
|
+
version: 0.3.15
|
|
55
55
|
description: This library helps you to develop interactive graphical user interface.
|
|
56
56
|
email: xordog@gmail.com
|
|
57
57
|
executables: []
|
|
@@ -305,6 +305,7 @@ files:
|
|
|
305
305
|
- samples/key.rb
|
|
306
306
|
- samples/layout.rb
|
|
307
307
|
- samples/model.rb
|
|
308
|
+
- samples/multi_window.rb
|
|
308
309
|
- samples/osx/hello/hello.xcodeproj/project.pbxproj
|
|
309
310
|
- samples/osx/hello/hello/Images.xcassets/AppIcon.appiconset/Contents.json
|
|
310
311
|
- samples/osx/hello/hello/en.lproj/Credits.rtf
|