rb_sdl2 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/README.md +1 -1
- data/lib/rb_sdl2/audio/audio.rb +162 -0
- data/lib/rb_sdl2/audio/audio_buffer.rb +12 -19
- data/lib/rb_sdl2/audio/audio_device.rb +17 -23
- data/lib/rb_sdl2/audio/audio_spec.rb +38 -6
- data/lib/rb_sdl2/audio/audio_spec_reader.rb +10 -0
- data/lib/rb_sdl2/clipboard.rb +31 -31
- data/lib/rb_sdl2/cpu_info.rb +34 -17
- data/lib/rb_sdl2/cursor.rb +105 -24
- data/lib/rb_sdl2/display.rb +16 -16
- data/lib/rb_sdl2/display_mode.rb +1 -1
- data/lib/rb_sdl2/error.rb +11 -4
- data/lib/rb_sdl2/errors.rb +7 -0
- data/lib/rb_sdl2/event/event.rb +130 -0
- data/lib/rb_sdl2/event/event_filter.rb +34 -70
- data/lib/rb_sdl2/event/event_pointer.rb +26 -0
- data/lib/rb_sdl2/event/event_queue.rb +97 -120
- data/lib/rb_sdl2/event/event_type.rb +147 -205
- data/lib/rb_sdl2/filesystem.rb +8 -9
- data/lib/rb_sdl2/hint.rb +26 -24
- data/lib/rb_sdl2/keyboard/keyboard.rb +50 -0
- data/lib/rb_sdl2/keyboard/mod_state.rb +68 -0
- data/lib/rb_sdl2/keyboard/state.rb +39 -0
- data/lib/rb_sdl2/message_box.rb +69 -102
- data/lib/rb_sdl2/mouse/global_mouse.rb +10 -3
- data/lib/rb_sdl2/mouse/mouse.rb +64 -0
- data/lib/rb_sdl2/mouse/mouse_button.rb +13 -11
- data/lib/rb_sdl2/mouse/mouse_class.rb +9 -17
- data/lib/rb_sdl2/mouse/mouse_wheel.rb +21 -37
- data/lib/rb_sdl2/mouse/relative_mouse.rb +15 -1
- data/lib/rb_sdl2/palette.rb +12 -12
- data/lib/rb_sdl2/pixel_format_enum.rb +87 -55
- data/lib/rb_sdl2/platform.rb +1 -1
- data/lib/rb_sdl2/power_info.rb +34 -23
- data/lib/rb_sdl2/rect.rb +7 -1
- data/lib/rb_sdl2/ref_count_pointer.rb +25 -10
- data/lib/rb_sdl2/rw_ops/rw_file.rb +19 -0
- data/lib/rb_sdl2/rw_ops/rw_memory.rb +18 -0
- data/lib/rb_sdl2/rw_ops/rw_object.rb +126 -0
- data/lib/rb_sdl2/rw_ops/rw_ops.rb +104 -0
- data/lib/rb_sdl2/rw_ops/rw_ops_pointer.rb +14 -0
- data/lib/rb_sdl2/sdl.rb +67 -28
- data/lib/rb_sdl2/sdl_pointer.rb +22 -0
- data/lib/rb_sdl2/surface/blend_mode.rb +41 -41
- data/lib/rb_sdl2/surface/pixel_format.rb +34 -33
- data/lib/rb_sdl2/surface.rb +280 -265
- data/lib/rb_sdl2/text_input.rb +21 -15
- data/lib/rb_sdl2/timer.rb +36 -31
- data/lib/rb_sdl2/version.rb +3 -3
- data/lib/rb_sdl2/video.rb +17 -5
- data/lib/rb_sdl2/window/accessor.rb +135 -0
- data/lib/rb_sdl2/window/display.rb +8 -8
- data/lib/rb_sdl2/window/flash.rb +22 -0
- data/lib/rb_sdl2/window/hit_test.rb +22 -43
- data/lib/rb_sdl2/window/shape.rb +55 -40
- data/lib/rb_sdl2/window/state.rb +178 -0
- data/lib/rb_sdl2/window/window.rb +149 -0
- data/lib/rb_sdl2.rb +79 -17
- data/rb_sdl2.gemspec +4 -4
- metadata +31 -35
- data/lib/rb_sdl2/audio/audio_allowed_changes.rb +0 -17
- data/lib/rb_sdl2/audio/audio_format.rb +0 -23
- data/lib/rb_sdl2/audio.rb +0 -132
- data/lib/rb_sdl2/cursor/color_cursor.rb +0 -19
- data/lib/rb_sdl2/cursor/cursor_class.rb +0 -24
- data/lib/rb_sdl2/cursor/cursor_pointer.rb +0 -12
- data/lib/rb_sdl2/cursor/default_cursor.rb +0 -18
- data/lib/rb_sdl2/cursor/system_cursor.rb +0 -45
- data/lib/rb_sdl2/event.rb +0 -161
- data/lib/rb_sdl2/keyboard/key_mod.rb +0 -37
- data/lib/rb_sdl2/keyboard/keyboard_state.rb +0 -34
- data/lib/rb_sdl2/keyboard.rb +0 -50
- data/lib/rb_sdl2/mouse/window_mouse.rb +0 -17
- data/lib/rb_sdl2/mouse.rb +0 -74
- data/lib/rb_sdl2/rw_ops/rw_operator.rb +0 -105
- data/lib/rb_sdl2/rw_ops.rb +0 -149
- data/lib/rb_sdl2/screen_saver.rb +0 -11
- data/lib/rb_sdl2/window/dialog.rb +0 -19
- data/lib/rb_sdl2/window/grab.rb +0 -23
- data/lib/rb_sdl2/window/position.rb +0 -38
- data/lib/rb_sdl2/window/size.rb +0 -59
- data/lib/rb_sdl2/window/window_flags.rb +0 -78
- data/lib/rb_sdl2/window.rb +0 -242
data/lib/rb_sdl2/cursor.rb
CHANGED
@@ -1,39 +1,120 @@
|
|
1
1
|
module RbSDL2
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
class Cursor
|
3
|
+
class CursorPointer < ::FFI::AutoPointer
|
4
|
+
class << self
|
5
|
+
# カーソルポインターはいつでも(表示中であっても)安全に開放できる。
|
6
|
+
# SDL はカレントカーソルが開放されたときはデフォルトカーソルをカレントカーソルに設定する。
|
7
|
+
# デフォルトカーソルは FreeCursorを呼び出しても開放されない。
|
8
|
+
def release(ptr) = ::SDL.FreeCursor(ptr)
|
9
|
+
end
|
10
|
+
end
|
7
11
|
|
12
|
+
@current = nil # カレントカーソルのオブジェクトを GC に回収されないように保持するために使用。
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# nil を与えた場合デフォルトカーソルが設定されます。
|
8
16
|
def current=(cursor)
|
9
|
-
|
17
|
+
@current = if cursor.nil?
|
18
|
+
::SDL.SetCursor(::SDL.GetDefaultCursor) # => nil
|
19
|
+
elsif Cursor === cursor
|
20
|
+
::SDL.SetCursor(cursor)
|
21
|
+
cursor
|
22
|
+
else
|
23
|
+
raise TypeError
|
24
|
+
end
|
10
25
|
end
|
11
26
|
|
12
|
-
def current?(cursor)
|
13
|
-
::SDL2.SDL_GetCursor == cursor.to_ptr
|
14
|
-
end
|
27
|
+
def current?(cursor) = ::SDL.GetCursor == cursor.to_ptr
|
15
28
|
|
16
|
-
|
17
|
-
|
29
|
+
def hide
|
30
|
+
::SDL.ShowCursor(::SDL::DISABLE)
|
31
|
+
nil
|
32
|
+
end
|
18
33
|
|
19
|
-
def
|
34
|
+
def show
|
35
|
+
::SDL.ShowCursor(::SDL::ENABLE)
|
36
|
+
nil
|
37
|
+
end
|
20
38
|
|
21
|
-
def
|
39
|
+
def shown? = ::SDL.ShowCursor(::SDL::QUERY) == ::SDL::ENABLE
|
22
40
|
|
23
|
-
|
41
|
+
# カーソルの再描画を行います。
|
42
|
+
def update = ::SDL.SetCursor(nil); self
|
24
43
|
|
25
|
-
|
26
|
-
|
27
|
-
|
44
|
+
# obj が Surface オブジェクトの時はカラーカーソルを作成します。
|
45
|
+
# その際に hot 引数にカーソルの判定位置を与えることができます。値は [x, y] です。
|
46
|
+
# 引数に与えた Surface オブジェクトは SDL 側にコピーされるため呼び出し後に安全に開放できます。
|
47
|
+
# obj が Symbol の時はシステムカーソルを作成します。
|
48
|
+
# Symbol は :arrow, :i_beam, :wait, :crosshair, :wait_arrow, :size_nw_se, :size_ne_sw,
|
49
|
+
# :size_we, :sie_ns, :size_all, :no, :hand が指定できます。
|
50
|
+
# obj が nil の場合はデフォルトカーソルを作成します。
|
51
|
+
def new(obj = nil, hot: nil)
|
52
|
+
ptr = CursorPointer.new(
|
53
|
+
case obj
|
54
|
+
when Surface
|
55
|
+
hot_x, hot_y = hot
|
56
|
+
# SDL_CreateColorCursor() は与えられた surface をコピーする。
|
57
|
+
# 呼び出し後に引数に与えた surface オブジェクトは安全に開放できる。
|
58
|
+
::SDL.CreateColorCursor(obj, hot_x, hot_y)
|
59
|
+
when Symbol
|
60
|
+
id = case obj
|
61
|
+
when :arrow then ::SDL::SYSTEM_CURSOR_ARROW
|
62
|
+
when :i_beam then ::SDL::SYSTEM_CURSOR_IBEAM
|
63
|
+
when :wait then ::SDL::SYSTEM_CURSOR_WAIT
|
64
|
+
when :crosshair then ::SDL::SYSTEM_CURSOR_CROSSHAIR
|
65
|
+
when :wait_arrow then ::SDL::SYSTEM_CURSOR_WAITARROW
|
66
|
+
when :size_nw_se then ::SDL::SYSTEM_CURSOR_SIZENWSE
|
67
|
+
when :size_ne_sw then ::SDL::SYSTEM_CURSOR_SIZENESW
|
68
|
+
when :size_we then ::SDL::SYSTEM_CURSOR_SIZEWE
|
69
|
+
when :size_ns then ::SDL::SYSTEM_CURSOR_SIZENS
|
70
|
+
when :size_all then ::SDL::SYSTEM_CURSOR_SIZEALL
|
71
|
+
when :no then ::SDL::SYSTEM_CURSOR_NO
|
72
|
+
when :hand then ::SDL::SYSTEM_CURSOR_HAND
|
73
|
+
else raise ArgumentError
|
74
|
+
end
|
75
|
+
::SDL.CreateSystemCursor(id)
|
76
|
+
when nil
|
77
|
+
# SDL 側にあるデフォルトカーソルのポインターを戻す。このポインターはシングルトンである。
|
78
|
+
# ポインターを SDL_FreeCursor() へ与えても安全である。SDL 内部では開放されない。
|
79
|
+
::SDL.GetDefaultCursor
|
80
|
+
else
|
81
|
+
raise ArgumentError
|
82
|
+
end
|
83
|
+
)
|
84
|
+
raise RbSDL2Error if ptr.null?
|
85
|
+
super(ptr)
|
28
86
|
end
|
29
87
|
end
|
30
88
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
89
|
+
def initialize(ptr)
|
90
|
+
@ptr = ptr
|
91
|
+
end
|
92
|
+
|
93
|
+
def ==(other)
|
94
|
+
other.respond_to?(:to_ptr) && other.to_ptr == @ptr
|
95
|
+
end
|
96
|
+
|
97
|
+
# 自身をカレントカーソルに設定します。カーソルの表示状態は変更されません。
|
98
|
+
def current! = Cursor.current = self
|
99
|
+
|
100
|
+
# 自身がカレントカーソルの場合に true を戻します。
|
101
|
+
def current? = Cursor.current?(self)
|
102
|
+
|
103
|
+
# 自身がカレントカーソルの場合のみカーソルを非表示にします。
|
104
|
+
def hide
|
105
|
+
current? && Cursor.hide
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
# 自身を表示カーソルにします。この時カレントカーソルは自身に設定されています。
|
110
|
+
def show
|
111
|
+
current! && Cursor.show
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
# 自身がカレントカーソルの場合かつカーソル表示中の時に true を戻します。
|
116
|
+
def shown? = current? && Cursor.shown?
|
117
|
+
|
118
|
+
def to_ptr = @ptr
|
38
119
|
end
|
39
120
|
end
|
data/lib/rb_sdl2/display.rb
CHANGED
@@ -2,7 +2,7 @@ module RbSDL2
|
|
2
2
|
class Display
|
3
3
|
class << self
|
4
4
|
def displays
|
5
|
-
count = ::
|
5
|
+
count = ::SDL.GetNumVideoDisplays
|
6
6
|
raise RbSDL2Error if count < 0
|
7
7
|
count.times.map { |num| Display.new(num) }
|
8
8
|
end
|
@@ -14,7 +14,7 @@ module RbSDL2
|
|
14
14
|
|
15
15
|
def bounds
|
16
16
|
rect = Rect.new
|
17
|
-
err = ::
|
17
|
+
err = ::SDL.GetDisplayBounds(index, rect)
|
18
18
|
raise RbSDL2Error if err < 0
|
19
19
|
rect.to_a
|
20
20
|
end
|
@@ -24,7 +24,7 @@ module RbSDL2
|
|
24
24
|
def closest_display_mode(**display_mode)
|
25
25
|
mode ||= DisplayMode.new(**display_mode)
|
26
26
|
closest = DisplayMode.new
|
27
|
-
err = ::
|
27
|
+
err = ::SDL.GetClosestDisplayMode(self, mode, closest)
|
28
28
|
raise RbSDL2Error if err.null?
|
29
29
|
closest
|
30
30
|
# 利用可能なディスプレイモードが検索され, 要求と最も近いモードがclosestに代入される.
|
@@ -35,24 +35,24 @@ module RbSDL2
|
|
35
35
|
|
36
36
|
def current_display_mode
|
37
37
|
obj = DisplayMode.new
|
38
|
-
err = ::
|
38
|
+
err = ::SDL.GetCurrentDisplayMode(index, obj)
|
39
39
|
raise RbSDL2Error if err < 0
|
40
40
|
obj
|
41
41
|
end
|
42
42
|
|
43
43
|
def desktop_display_mode
|
44
44
|
obj = DisplayMode.new
|
45
|
-
err = ::
|
45
|
+
err = ::SDL.GetDesktopDisplayMode(index, obj)
|
46
46
|
raise RbSDL2Error if err < 0
|
47
47
|
obj
|
48
48
|
end
|
49
49
|
|
50
50
|
def display_modes
|
51
|
-
num = ::
|
51
|
+
num = ::SDL.GetNumDisplayModes(index)
|
52
52
|
raise RbSDL2Error if num < 0
|
53
53
|
num.times.map do |mode_index|
|
54
54
|
obj = DisplayMode.new
|
55
|
-
err = ::
|
55
|
+
err = ::SDL.GetDisplayMode(index, mode_index, obj)
|
56
56
|
raise RbSDL2Error if err < 0
|
57
57
|
obj
|
58
58
|
end
|
@@ -61,7 +61,7 @@ module RbSDL2
|
|
61
61
|
# ディスプレイピクセルの斜め、水平、垂直方向の DPI を配列で戻す。
|
62
62
|
def dpi
|
63
63
|
d_h_v_dpi = Array.new(3) { ::FFI::MemoryPointer.new(:float) }
|
64
|
-
err = ::
|
64
|
+
err = ::SDL.GetDisplayDPI(index, *d_h_v_dpi)
|
65
65
|
raise RbSDL2Error if err < 0
|
66
66
|
d_h_v_dpi.map { |v| v.read_float }
|
67
67
|
end
|
@@ -74,28 +74,28 @@ module RbSDL2
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def name
|
77
|
-
ptr = ::
|
77
|
+
ptr = ::SDL.GetDisplayName(index)
|
78
78
|
raise RbSDL2Error if ptr.null?
|
79
|
-
|
79
|
+
SDL.ptr_to_str(ptr)
|
80
80
|
end
|
81
81
|
alias to_s name
|
82
82
|
|
83
|
-
def orientation = ::
|
83
|
+
def orientation = ::SDL.GetDisplayOrientation(index)
|
84
84
|
|
85
85
|
module DisplayOrientation
|
86
|
-
def flipped_landscape? = ::
|
86
|
+
def flipped_landscape? = ::SDL::ORIENTATION_LANDSCAPE_FLIPPED == orientation
|
87
87
|
|
88
|
-
def flipped_portrait? = ::
|
88
|
+
def flipped_portrait? = ::SDL::ORIENTATION_PORTRAIT_FLIPPED == orientation
|
89
89
|
|
90
|
-
def landscape? = ::
|
90
|
+
def landscape? = ::SDL::ORIENTATION_LANDSCAPE == orientation
|
91
91
|
|
92
|
-
def portrait? = ::
|
92
|
+
def portrait? = ::SDL::ORIENTATION_PORTRAIT == orientation
|
93
93
|
end
|
94
94
|
include DisplayOrientation
|
95
95
|
|
96
96
|
def usable_bounds
|
97
97
|
rect = Rect.new
|
98
|
-
err = ::
|
98
|
+
err = ::SDL.GetDisplayUsableBounds(index, rect)
|
99
99
|
raise RbSDL2Error if err < 0
|
100
100
|
rect.to_a
|
101
101
|
end
|
data/lib/rb_sdl2/display_mode.rb
CHANGED
data/lib/rb_sdl2/error.rb
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
module RbSDL2
|
2
|
-
|
2
|
+
class Error < StandardError
|
3
3
|
class << self
|
4
4
|
# SDL が設定したエラーメッセージをクリアします。
|
5
|
-
def clear = ::
|
5
|
+
def clear = ::SDL.ClearError
|
6
6
|
|
7
7
|
# SDL からのエラーメッセージを文字列で返します。
|
8
|
-
# SDL
|
8
|
+
# SDL からエラーが通知されてもエラーメッセージがあるとは限りません。
|
9
9
|
# SDL の関数はエラーの状態を示してもエラーメッセージをセットしない場合があります。
|
10
|
-
def
|
10
|
+
def last_error_message = SDL.ptr_to_str(::SDL.GetError)
|
11
|
+
|
12
|
+
def last_error_message=(error_message)
|
13
|
+
# SDL_SetError() の第一引数は sprintf フォーマットである。
|
14
|
+
# このメソッドのデザインの都合上、可変長引数を与える方法が無い。
|
15
|
+
# "%" をエスケープすることで第二引数を無視させてメモリー参照を行わないようにする。
|
16
|
+
::SDL.SetError(SDL.str_to_sdl(error_message.gsub(/%/, "%%")))
|
17
|
+
end
|
11
18
|
end
|
12
19
|
end
|
13
20
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module RbSDL2
|
2
|
+
class Event
|
3
|
+
# SDL_SYSWMEVENT の msg メンバーの実装はしない。
|
4
|
+
# msg ポインターが指す SDL_SysWMmsg は構造体サイズが環境に依存するためコピーを行うことができない。
|
5
|
+
# SDL_SYSWMEVENT イベントの作成はできない、受け取りはできるが msg メンバーへのアクセスはできない。
|
6
|
+
# SDL は SDL_SYSWMEVENT にある SDL_SysWMmsg をマネージしている。
|
7
|
+
# イベントへの追加ではコピーを行い、取り出しの際にはテンポラリ領域へコピーしてからアプリケーションへ渡す。
|
8
|
+
# アプリケーションが SDL_SYSWMEVENT を無視してもメモリーリークはしない。
|
9
|
+
|
10
|
+
require 'forwardable'
|
11
|
+
extend SingleForwardable
|
12
|
+
|
13
|
+
require_relative 'event_filter'
|
14
|
+
def_single_delegators EventFilter, *%i(define_watch filter_callback_defined? undefine_watch)
|
15
|
+
|
16
|
+
require_relative 'event_queue'
|
17
|
+
def_single_delegators EventQueue, *%i(clear exist? poll pump wait)
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def quit?
|
21
|
+
pump
|
22
|
+
exist?(::SDL::QUIT)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require_relative 'event_type'
|
27
|
+
def_single_delegators EventType, *%i(disable enable ignore? register_events)
|
28
|
+
|
29
|
+
include EventType
|
30
|
+
|
31
|
+
require_relative 'event_pointer'
|
32
|
+
|
33
|
+
class << self
|
34
|
+
def new(type:, **members)
|
35
|
+
obj = super(EventPointer.new(type))
|
36
|
+
members.each_pair { |sym, val| obj[sym] = val }
|
37
|
+
obj
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_ptr(ptr)
|
41
|
+
obj = allocate
|
42
|
+
obj.__send__(:initialize, ptr)
|
43
|
+
obj
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(ptr)
|
48
|
+
@ptr = ptr
|
49
|
+
@entity = nil
|
50
|
+
@obj = if drop_file? || drop_text?
|
51
|
+
SDLPointer.new(entity[:file])
|
52
|
+
elsif text_editing_ext?
|
53
|
+
SDLPointer.new(entity[:text])
|
54
|
+
elsif sys_wm_event? && entity[:msg].null?
|
55
|
+
# msg に NULL があると SDL はこのポインターをチェックせずに読み出す。
|
56
|
+
raise TypeError
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# SDL_SYSWMEVENT の msg はポインターです。このポインターの取り扱いはアプリケーションに委ねられます。
|
61
|
+
# SDL_USEREVENT の data1, data2 はポインターです。このポインターの取り扱いはアプリケーションに委ねられます。
|
62
|
+
def [](sym)
|
63
|
+
obj = entity[sym]
|
64
|
+
case sym
|
65
|
+
when :data then obj.to_a
|
66
|
+
when :file then if drop_file? || drop_text?
|
67
|
+
SDL.ptr_to_str(obj)
|
68
|
+
else
|
69
|
+
# SDL_EVENTBEGIN, SDL_DROPCOMPLETE はこのメンバー使用しない。
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
when :keysym then { scancode: obj[:scancode], sym: obj[:sym], mod: obj[:mod] }
|
73
|
+
when :msg then obj
|
74
|
+
when :text then SDL.ptr_to_str(obj.to_ptr)
|
75
|
+
when :type then type
|
76
|
+
else obj
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# SDL_SYSWMEVENT の msg への書き込みはできません。
|
81
|
+
# SDL_USEREVENT の data1, data2 はポインターです。このポインターの取り扱いはアプリケーションに委ねられます。
|
82
|
+
def []=(sym, val)
|
83
|
+
raise FrozenError if frozen?
|
84
|
+
|
85
|
+
case sym
|
86
|
+
when :data then entity[sym].tap { |st| val.each.with_index { |v, i| st[i] = v } }
|
87
|
+
when :file then if drop_file? || drop_text?
|
88
|
+
entity[sym] = @obj = SDLPointer.from_string(val)
|
89
|
+
else
|
90
|
+
# SDL_EVENTBEGIN, SDL_DROPCOMPLETE はこのメンバー使用しない。
|
91
|
+
raise TypeError
|
92
|
+
end
|
93
|
+
when :keysym then entity[sym].tap { |st| val.each { |k, v| st[k] = v } }
|
94
|
+
when :msg then raise NotImplementedError
|
95
|
+
when :text then if text_editing_ext?
|
96
|
+
entity[sym] = @obj = SDLPointer.from_string(val)
|
97
|
+
else
|
98
|
+
::SDL.utf8strlcpy(entity[sym].to_ptr, SDL.str_to_sdl(val), entity[sym].size)
|
99
|
+
end
|
100
|
+
when :type then raise TypeError
|
101
|
+
else entity[sym] = val
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
private def entity = @entity ||= EventType::ENTITY_MAP[type].new(@ptr)
|
106
|
+
|
107
|
+
# clone, dup はディープコピーを行います。
|
108
|
+
def initialize_copy(obj)
|
109
|
+
super
|
110
|
+
initialize(EventPointer.copy(obj.to_ptr))
|
111
|
+
end
|
112
|
+
|
113
|
+
def inspect = "#<#{self.class.name}: #{name}>"
|
114
|
+
|
115
|
+
def member?(name) = members.include?(name)
|
116
|
+
|
117
|
+
def members = entity.members.grep_v(/\Apadding/)
|
118
|
+
|
119
|
+
def name = EventType.to_name(type)
|
120
|
+
|
121
|
+
def to_h = members.map { |sym| [sym, self[sym]] }.to_h
|
122
|
+
|
123
|
+
def to_ptr = @ptr
|
124
|
+
|
125
|
+
def to_s = name.to_s
|
126
|
+
|
127
|
+
def type = @ptr.type
|
128
|
+
alias to_i type
|
129
|
+
end
|
130
|
+
end
|
@@ -1,82 +1,46 @@
|
|
1
1
|
module RbSDL2
|
2
|
-
class
|
3
|
-
class EventFilter < ::FFI::Function
|
4
|
-
@filter_callback = nil, nil
|
5
|
-
@filter_mutex = Mutex.new
|
2
|
+
class EventFilter < ::FFI::Function
|
6
3
|
|
7
|
-
|
8
|
-
|
9
|
-
func = if Proc === obj
|
10
|
-
# イベントを削除する時にイベントメンバーのポインターを開放(Event#clear)する。
|
11
|
-
new { |event| obj.call(event) || (event.clear; nil) }
|
12
|
-
else
|
13
|
-
obj
|
14
|
-
end
|
15
|
-
# func, userdata の対の関係を保つ。
|
16
|
-
@filter_mutex.synchronize do
|
17
|
-
::SDL2.SDL_SetEventFilter(func, userdata)
|
18
|
-
@filter_callback = [func, userdata]
|
19
|
-
end
|
20
|
-
[obj, userdata]
|
21
|
-
end
|
4
|
+
class Releaser
|
5
|
+
def initialize(obj) = @obj = obj
|
22
6
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
# userdata ポインターが設定されていても SDL_GetEventFilter の戻り値に関与しない。
|
28
|
-
::SDL2.SDL_GetEventFilter(*_func_userdata) == ::SDL2::SDL_TRUE
|
29
|
-
end
|
30
|
-
end
|
7
|
+
def call(_id) = ::SDL.DelEventWatch(@obj, nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
@watches = []
|
31
11
|
|
32
|
-
|
33
|
-
|
12
|
+
class << self
|
13
|
+
def define_watch(func)
|
14
|
+
::SDL.AddEventWatch(func, nil)
|
15
|
+
@watches << func.__id__
|
16
|
+
ptr = ::FFI::Pointer.new(func.address)
|
17
|
+
ObjectSpace.define_finalizer(func, Releaser.new(ptr))
|
18
|
+
end
|
34
19
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
obj
|
41
|
-
end
|
42
|
-
obj_userdata = [obj, userdata]
|
43
|
-
@watch_mutex.synchronize do
|
44
|
-
::SDL2.SDL_AddEventWatch(func, userdata)
|
45
|
-
@watch_callbacks << [obj_userdata, func]
|
46
|
-
end
|
47
|
-
obj_userdata
|
48
|
-
end
|
20
|
+
def undefine_watch(func)
|
21
|
+
func_id = func.__id__
|
22
|
+
@watches.delete_if { |id| (id == func_id).tap { ::SDL.DelEventWatch(func, nil) } }
|
23
|
+
ObjectSpace.undefine_finalizer(func)
|
24
|
+
end
|
49
25
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
idx = @watch_callbacks.index { |obj| obj.first == obj_userdata }
|
54
|
-
if idx
|
55
|
-
_, func = @watch_callbacks.delete_at(idx)
|
56
|
-
::SDL2.SDL_DelEventWatch(func, userdata)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
obj_userdata
|
60
|
-
end
|
26
|
+
# SDL にフィルターコールバック関数が設定されている場合に true を戻す。
|
27
|
+
def filter_callback_defined?
|
28
|
+
::SDL.GetEventFilter(nil, nil) == ::SDL::TRUE
|
61
29
|
end
|
30
|
+
end
|
62
31
|
|
63
|
-
|
32
|
+
require_relative 'event'
|
33
|
+
require_relative 'event_pointer'
|
64
34
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
super(:int, [:pointer, :pointer]) do |_userdata, ptr|
|
75
|
-
obj = SimpleDelegator.new(Event.to_ptr(ptr))
|
76
|
-
yield(obj) ? 1 : 0
|
77
|
-
ensure
|
78
|
-
obj.__setobj__(nil)
|
79
|
-
end
|
35
|
+
# コールバックにはコピーしたイベントが与えられます。
|
36
|
+
# よって SDL のイベントキューにあるイベントを書き換えることはできません。
|
37
|
+
def initialize(proc)
|
38
|
+
# int EventFilter(void* userdata, SDL_Event* event);
|
39
|
+
super(:int, [:pointer, :pointer]) do |_userdata, ptr|
|
40
|
+
# SDL のイベントキューへの参照ポインターを受け取る場合は必ずコピーを取る必要がある。
|
41
|
+
# キューの状態は変化するため、次にアクセスする際にポインター先が存在する保証はない。
|
42
|
+
# SDL のイベントキューを参照している間は SDL がキューをロックしているためコピーは安全にできる。
|
43
|
+
proc.call( Event.to_ptr(EventPointer.copy(ptr)) ) ? 1 : 0
|
80
44
|
end
|
81
45
|
end
|
82
46
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RbSDL2
|
2
|
+
class EventPointer < ::FFI::MemoryPointer
|
3
|
+
class << self
|
4
|
+
def copy(ptr)
|
5
|
+
obj = malloc
|
6
|
+
::SDL.memcpy(obj, ptr, size)
|
7
|
+
type = obj.type
|
8
|
+
if ::SDL::DROPFILE == type || ::SDL::DROPTEXT == type
|
9
|
+
ref = obj + ::SDL::DropEvent.offset_of(:file)
|
10
|
+
str = ::SDL.strdup(ref.read_pointer)
|
11
|
+
raise NoMemoryError if str.null?
|
12
|
+
ref.write_pointer(str)
|
13
|
+
end
|
14
|
+
obj
|
15
|
+
end
|
16
|
+
|
17
|
+
def malloc = new(0)
|
18
|
+
|
19
|
+
def new(type) = super(size).write_uint32(type)
|
20
|
+
|
21
|
+
def size = ::SDL::Event.size
|
22
|
+
end
|
23
|
+
|
24
|
+
def type = read_uint32
|
25
|
+
end
|
26
|
+
end
|