indexing description: "[ Event loop for EiffelMedia ]" date: "$Date$" revision: "$Revision$" class EM_EVENT_LOOP inherit ANY EM_CONSTANTS export {NONE} all end EM_TIME_SINGLETON export {NONE} all end EM_SHARED_ERROR_HANDLER export {NONE} all end EM_SHARED_SUBSYSTEMS export {NONE} all end EM_SHARED_AUDIO_EVENTS export {NONE} all end FASTEVENTS_FUNCTIONS_EXTERNAL export {NONE} all end NET2_FUNCTIONS_EXTERNAL export {NONE} all end EM_AUDIO_FUNCTIONS_EXTERNAL export {NONE} all end create make_wait, make_poll feature -- Initialization make_wait is -- Create an event loop that waits for the next event. -- This kind of event loop does not provide the possibility to -- add subscribers that will be executed outside the actual -- event processing. do set_time_for_eventprocessing (Em_default_time_for_eventprocessing) init_events dispose := False wait := True end make_poll is -- Create an event loop that polls pending events, -- processes them and then executes the code of -- specific subscribers (`TBC') -- apart from the actual event processing. do set_time_for_eventprocessing (Em_default_time_for_eventprocessing) init_events dispose := False wait := False end feature -- Status set_time_for_eventprocessing (a_ms_value: INTEGER) is -- Set time maximal time during which the event loop -- processes events to `a_ms_value' (in milliseconds). require a_ms_value_valid: a_ms_value > 0 do time_for_event_processing:= a_ms_value end feature -- Event loop dispatch is -- Start processing events in the event loop until `Current' is stoped ('dispose'). local i: INTEGER event: SDL_EVENT_UNION do if wait then create event.make_new_shared from until dispose loop process_high_priority i := fe_wait_event_external (event.item) publish_event (event) end else from until dispose loop process_high_priority process_events end end end process_high_priority is -- Process high priority data that must be available regardless of the -- time that is available per eventloop. -- Use it only for polling really time critical data. -- This does nothing in the default implementation. do time.process_timed_procedures_in_same_thread end process_events is -- Process waiting events for some time. -- Should be called from time to time by event handlers that -- perform actions that take long time to -- keep the system interactive. local time_ticks, process_end_ticks: INTEGER event: SDL_EVENT_UNION do create event.make_new_unshared -- Ensure not to process longer than for `time_for_event_processing' milliseconds. process_end_ticks := time.ticks + time_for_event_processing from until time.ticks > process_end_ticks or else fe_poll_event_external (event.item) = 0 loop publish_event (event) end -- This is the event that allow the user to execute code outside the -- event loop (usually used to update the screen). update_event.publish ([default_pointer]) -- Some delay for giving OS some time, if time is left. time_ticks := time.ticks if time_ticks < process_end_ticks then time.delay (process_end_ticks - time_ticks) end end delay_and_process (milliseconds: INTEGER) is -- Let the event loop process waiting events -- for `milliseconds' time. local time_ticks, process_end_time: INTEGER sleep_and_process_end_time: INTEGER event: SDL_EVENT_UNION do create event.make_new_shared -- Process events until end time reached. from sleep_and_process_end_time := time.ticks + milliseconds until time.ticks > sleep_and_process_end_time loop from process_end_time := (time.ticks + time_for_event_processing).min (sleep_and_process_end_time) until time.ticks > process_end_time or else fe_poll_event_external (event.item) = 0 loop publish_event (event) create event.make_new_shared end if time.ticks < sleep_and_process_end_time then -- This is the event that allow the user to execute code outside the -- event loop. update_event.publish ([default_pointer]) end -- Some delay for giving OS some time, if time is left. process_end_time := process_end_time.min (sleep_and_process_end_time) time_ticks := time.ticks if time_ticks < process_end_time then time.delay (process_end_time - time_ticks) end end end stop is -- Stop the event loop. do dispose := True end start is -- Start the event loop do dispose := False end feature -- Events active_event: EM_EVENT_CHANNEL [TUPLE [EM_ACTIVE_EVENT]] -- Active event key_down_event: EM_EVENT_CHANNEL [TUPLE [EM_KEYBOARD_EVENT]] -- Key down event key_up_event: EM_EVENT_CHANNEL [TUPLE [EM_KEYBOARD_EVENT]] -- Key up event mouse_motion_event: EM_EVENT_CHANNEL [TUPLE [EM_MOUSE_EVENT]] -- Mouse motion event mouse_button_down_event: EM_EVENT_CHANNEL [TUPLE [EM_MOUSE_EVENT]] -- Mouse button down event mouse_button_up_event: EM_EVENT_CHANNEL [TUPLE [EM_MOUSE_EVENT]] -- Mouse button up event joystick_axis_event: EM_EVENT_CHANNEL [TUPLE [EM_JOYSTICK_AXIS_EVENT]] -- Joystick axis event joystick_ball_event: EM_EVENT_CHANNEL [TUPLE [EM_JOYSTICK_BALL_EVENT]] -- Joystick ball event joystick_button_down_event: EM_EVENT_CHANNEL [TUPLE [EM_JOYSTICK_BUTTON_EVENT]] -- Joystick button down event joystick_button_up_event: EM_EVENT_CHANNEL [TUPLE [EM_JOYSTICK_BUTTON_EVENT]] -- Joystick button up event joystick_hat_event: EM_EVENT_CHANNEL [TUPLE [EM_JOYSTICK_HAT_EVENT]] -- Joystick hat event resize_event: EM_EVENT_CHANNEL [TUPLE [EM_RESIZE_EVENT]] -- Resize event window_manager_event: EM_EVENT_CHANNEL [TUPLE [EM_WINDOWMANAGER_EVENT]] -- Window manager event user_event: EM_EVENT_CHANNEL [TUPLE [EM_USER_EVENT]] -- User event expose_event: EM_EVENT_CHANNEL [TUPLE [EM_EXPOSE_EVENT]] -- Expose event quit_event: EM_EVENT_CHANNEL [TUPLE [EM_QUIT_EVENT]] -- Quit event update_event: EM_EVENT_CHANNEL [TUPLE []] -- Update event, allows the user to do his own processing of actions other than the -- standard events that are handled feature {NONE} -- Implementation wait: BOOLEAN -- Is it a polling event loop or a waiting one? dispose: BOOLEAN -- Should event dispatching be stopped? init_events is -- Initializes the events. do create active_event create key_down_event create key_up_event create mouse_motion_event create mouse_button_down_event create mouse_button_up_event create joystick_axis_event create joystick_button_down_event create joystick_button_up_event create joystick_hat_event create joystick_ball_event create resize_event create window_manager_event create user_event create expose_event create quit_event create update_event end Sockets_shortcut: EM_SOCKETS is -- Sockets shortcut -- Saves one layer of indirection once Result := Network_subsystem.sockets end publish_event (an_event: SDL_EVENT_UNION) is -- Publish `an_event' from SDL to the corresponding events from EiffelMedia. require an_event_not_void: an_event /= Void local my_active_event: EM_ACTIVE_EVENT net2_error_string: EWG_ZERO_TERMINATED_STRING do inspect an_event.type when Em_active_event then create my_active_event.make (an_event.item) active_event.publish ([my_active_event]) when Em_key_down_event then key_down_event.publish ([create {EM_KEYBOARD_EVENT}.make (an_event.item)]) when Em_key_up_event then key_up_event.publish ([create {EM_KEYBOARD_EVENT}.make (an_event.item)]) when Em_mousemotion_event then mouse_motion_event.publish ([create {EM_MOUSEMOTION_EVENT}.make (an_event.item)]) when Em_mouse_button_down_event then mouse_button_down_event.publish ([create {EM_MOUSEBUTTON_EVENT}.make (an_event.item)]) when Em_mouse_button_up_event then mouse_button_up_event.publish ([create {EM_MOUSEBUTTON_EVENT}.make (an_event.item)]) when Em_joystick_axis_event then joystick_axis_event.publish ([create {EM_JOYSTICK_AXIS_EVENT}.make (an_event.item)]) when Em_joystick_ball_event then joystick_ball_event.publish ([create {EM_JOYSTICK_BALL_EVENT}.make (an_event.item)]) when Em_joystick_hat_event then joystick_hat_event.publish ([create {EM_JOYSTICK_HAT_EVENT}.make (an_event.item)]) when Em_joystick_button_down_event then joystick_button_down_event.publish ([create {EM_JOYSTICK_BUTTON_EVENT}.make (an_event.item)]) when Em_joystick_button_up_event then joystick_button_up_event.publish ([create {EM_JOYSTICK_BUTTON_EVENT}.make (an_event.item)]) when Em_quit_event then quit_event.publish ([create {EM_QUIT_EVENT}.make (an_event.item)]) when Em_window_manager_event then window_manager_event.publish ([create {EM_WINDOWMANAGER_EVENT}.make (an_event.item)]) when Em_resize_event then resize_event.publish ([create {EM_RESIZE_EVENT}.make (an_event.item)]) when Em_expose_event then expose_event.publish ([create {EM_EXPOSE_EVENT}.make (an_event.item)]) when Em_user_event then check user_event_code_in_range: not Network_subsystem.is_enabled implies get_sdl_user_event_type_external (an_event.item) > 8 user_event_code_in_range: not Audio_subsystem.is_enabled implies get_sdl_user_event_type_external (an_event.item) < 20 or get_sdl_user_event_type_external (an_event.item) > 21 end debug if not Network_subsystem.is_enabled and get_sdl_user_event_type_external (an_event.item) < 9 then Error_handler.raise_error (Error_handler.Em_error_user_event_code_used_by_network, [get_sdl_user_event_type_external (an_event.item)]) end if not Audio_subsystem.is_enabled and get_sdl_user_event_type_external (an_event.item) >= 20 or get_sdl_user_event_type_external (an_event.item) <= 21 then Error_handler.raise_error (Error_handler.Em_error_user_event_code_used_by_audio, [get_sdl_user_event_type_external (an_event.item)]) end end inspect -- net2_get_event_type_external (an_event.item) get_sdl_user_event_type_external (an_event.item) when Em_net_error_event then create net2_error_string.make_shared (net2_get_event_error_external (an_event.item)) Error_handler.raise_warning (Error_handler.Em_error_net2_error, [net2_error_string.string]) when Em_udp_receive_event then Sockets_shortcut.handle_udp_receive_event (net2_get_socket_external (an_event.item)) when Em_udp_send_event then Sockets_shortcut.handle_udp_send_event (net2_get_socket_external (an_event.item), net2_get_error_of_event_external (an_event.item)) when Em_tcp_connect_event then Sockets_shortcut.handle_tcp_connect_event (net2_get_socket_external (an_event.item), net2_get_ipaddress_of_event_external (an_event.item)) when Em_tcp_connect_failed_event then -- Here is a hack! get_socket returns first element of user-event data which is here an error-code Sockets_shortcut.handle_tcp_connect_failed_event (net2_get_socket_external (an_event.item), net2_get_ipaddress_of_event_external (an_event.item)) when Em_tcp_accept_event then Sockets_shortcut.handle_tcp_accept_event (net2_get_event_data_external (an_event.item), net2_get_socket_external (an_event.item)) when Em_tcp_close_event then Sockets_shortcut.handle_tcp_close_event (net2_get_socket_external (an_event.item)) when Em_tcp_receive_event then Sockets_shortcut.handle_tcp_receive_event (net2_get_socket_external (an_event.item)) when Em_resolve_finished_event then Sockets_shortcut.handle_resolve_finished_event (net2_get_socket_external(an_event.item)) when Em_audio_channel_finished_event then audio_events.channel_finished_event.publish ([get_audio_channel_external (an_event.item) + 1]) when Em_audio_music_finished_event then audio_events.music_finished_event.publish ([]) else user_event.publish ([create {EM_USER_EVENT}.make (an_event.item)]) end else Error_handler.raise_error (Error_handler.Em_error_unknown_event_type, [an_event.type]) end end time_for_event_processing: INTEGER -- Maximal time during which the event loop processes events -- in milliseconds. end