mirror of
https://github.com/libretro/RetroArch
synced 2025-02-15 00:40:06 +00:00
Extended core message interface - add concept of message 'type'
This commit is contained in:
parent
fc8b76708a
commit
23916f88c7
@ -339,7 +339,6 @@ unsigned gfx_widgets_get_height(void)
|
||||
return simple_widget_height;
|
||||
}
|
||||
|
||||
|
||||
unsigned gfx_widgets_get_generic_message_height(void)
|
||||
{
|
||||
return generic_message_height;
|
||||
@ -355,6 +354,11 @@ unsigned gfx_widgets_get_last_video_height(void)
|
||||
return last_video_height;
|
||||
}
|
||||
|
||||
size_t gfx_widgets_get_msg_queue_size(void)
|
||||
{
|
||||
return current_msgs ? current_msgs->size : 0;
|
||||
}
|
||||
|
||||
/* Widgets list */
|
||||
const static gfx_widget_t* const widgets[] = {
|
||||
&gfx_widget_screenshot,
|
||||
@ -1500,6 +1504,7 @@ void gfx_widgets_frame(void *data)
|
||||
video_frame_info_t *video_info;
|
||||
bool framecount_show;
|
||||
bool memory_show;
|
||||
bool core_status_msg_show;
|
||||
void *userdata;
|
||||
unsigned video_width;
|
||||
unsigned video_height;
|
||||
@ -1521,6 +1526,7 @@ void gfx_widgets_frame(void *data)
|
||||
video_info = (video_frame_info_t*)data;
|
||||
framecount_show = video_info->framecount_show;
|
||||
memory_show = video_info->memory_show;
|
||||
core_status_msg_show = video_info->core_status_msg_show;
|
||||
userdata = video_info->userdata;
|
||||
video_width = video_info->width;
|
||||
video_height = video_info->height;
|
||||
@ -1705,26 +1711,11 @@ void gfx_widgets_frame(void *data)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Draw all messages */
|
||||
for (i = 0; i < current_msgs->size; i++)
|
||||
{
|
||||
menu_widget_msg_t *msg = (menu_widget_msg_t*)current_msgs->list[i].userdata;
|
||||
|
||||
if (!msg)
|
||||
continue;
|
||||
|
||||
if (msg->task_ptr)
|
||||
gfx_widgets_draw_task_msg(msg, userdata,
|
||||
video_width, video_height);
|
||||
else
|
||||
gfx_widgets_draw_regular_msg(msg, userdata,
|
||||
video_width, video_height);
|
||||
}
|
||||
|
||||
/* FPS Counter */
|
||||
if ( fps_show
|
||||
|| framecount_show
|
||||
|| memory_show
|
||||
|| core_status_msg_show
|
||||
)
|
||||
{
|
||||
const char *text = *gfx_widgets_fps_text == '\0' ? "N/A" : gfx_widgets_fps_text;
|
||||
@ -1798,6 +1789,22 @@ void gfx_widgets_frame(void *data)
|
||||
widget->frame(data);
|
||||
}
|
||||
|
||||
/* Draw all messages */
|
||||
for (i = 0; i < current_msgs->size; i++)
|
||||
{
|
||||
menu_widget_msg_t *msg = (menu_widget_msg_t*)current_msgs->list[i].userdata;
|
||||
|
||||
if (!msg)
|
||||
continue;
|
||||
|
||||
if (msg->task_ptr)
|
||||
gfx_widgets_draw_task_msg(msg, userdata,
|
||||
video_width, video_height);
|
||||
else
|
||||
gfx_widgets_draw_regular_msg(msg, userdata,
|
||||
video_width, video_height);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
/* Load content animation */
|
||||
if (load_content_animation_running)
|
||||
|
@ -113,6 +113,8 @@ float* gfx_widgets_get_backdrop_orig(void);
|
||||
unsigned gfx_widgets_get_last_video_width(void);
|
||||
unsigned gfx_widgets_get_last_video_height(void);
|
||||
unsigned gfx_widgets_get_generic_message_height(void);
|
||||
/* Warning: not thread safe! */
|
||||
size_t gfx_widgets_get_msg_queue_size(void);
|
||||
|
||||
float gfx_widgets_get_thumbnail_scale_factor(
|
||||
const float dst_width, const float dst_height,
|
||||
|
@ -95,6 +95,7 @@ static void gfx_widget_generic_message_frame(void* data)
|
||||
unsigned height = gfx_widgets_get_generic_message_height();
|
||||
unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f));
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
size_t msg_queue_size = gfx_widgets_get_msg_queue_size();
|
||||
|
||||
gfx_display_set_alpha(gfx_widgets_get_backdrop_orig(), state->alpha);
|
||||
|
||||
@ -111,6 +112,11 @@ static void gfx_widget_generic_message_frame(void* data)
|
||||
video_width, video_height,
|
||||
text_color, TEXT_ALIGN_CENTER,
|
||||
false);
|
||||
|
||||
/* If the message queue is active, must flush the
|
||||
* text here to avoid overlaps */
|
||||
if (msg_queue_size > 0)
|
||||
gfx_widgets_flush_text(video_width, video_height, font_regular);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,6 +103,7 @@ static void gfx_widget_libretro_message_frame(void *data)
|
||||
float* backdrop_orign = gfx_widgets_get_backdrop_orig();
|
||||
unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f));
|
||||
gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular();
|
||||
size_t msg_queue_size = gfx_widgets_get_msg_queue_size();
|
||||
|
||||
gfx_display_set_alpha(backdrop_orign, state->alpha);
|
||||
|
||||
@ -119,6 +120,11 @@ static void gfx_widget_libretro_message_frame(void *data)
|
||||
video_width, video_height,
|
||||
text_color, TEXT_ALIGN_LEFT,
|
||||
false);
|
||||
|
||||
/* If the message queue is active, must flush the
|
||||
* text here to avoid overlaps */
|
||||
if (msg_queue_size > 0)
|
||||
gfx_widgets_flush_text(video_width, video_height, font_regular);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2544,13 +2544,72 @@ enum retro_message_target
|
||||
RETRO_MESSAGE_TARGET_LOG
|
||||
};
|
||||
|
||||
enum retro_message_type
|
||||
{
|
||||
RETRO_MESSAGE_TYPE_NOTIFICATION = 0,
|
||||
RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,
|
||||
RETRO_MESSAGE_TYPE_STATUS
|
||||
};
|
||||
|
||||
struct retro_message_ext
|
||||
{
|
||||
const char *msg; /* Message to be displayed/logged */
|
||||
unsigned frames; /* Duration in frames of message when targeting OSD */
|
||||
unsigned priority; /* Message priority when targeting OSD */
|
||||
enum retro_log_level level; /* Message logging level (info, warn, etc.) */
|
||||
enum retro_message_target target; /* Message destination: OSD, logging interface or both */
|
||||
/* Message string to be displayed/logged */
|
||||
const char *msg;
|
||||
/* Duration (in ms) of message when targeting the OSD */
|
||||
unsigned duration;
|
||||
/* Message priority when targeting the OSD
|
||||
* > When multiple concurrent messages are sent to
|
||||
* the frontend and the frontend does not have the
|
||||
* capacity to display them all, messages with the
|
||||
* *highest* priority value should be shown
|
||||
* > There is no upper limit to a message priority
|
||||
* value (within the bounds of the unsigned data type)
|
||||
* > In the reference frontend (RetroArch), the same
|
||||
* priority values are used for frontend-generated
|
||||
* notifications, which are typically assigned values
|
||||
* between 0 and 3 depending upon importance */
|
||||
unsigned priority;
|
||||
/* Message logging level (info, warn, error, etc.) */
|
||||
enum retro_log_level level;
|
||||
/* Message destination: OSD, logging interface or both */
|
||||
enum retro_message_target target;
|
||||
/* Message 'type' when targeting the OSD
|
||||
* > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a
|
||||
* message should be handled in identical fashion to
|
||||
* a standard frontend-generated notification
|
||||
* > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that
|
||||
* message is a notification that requires user attention
|
||||
* or action, but that it should be displayed in a manner
|
||||
* that differs from standard frontend-generated notifications.
|
||||
* This would typically correspond to messages that should be
|
||||
* displayed immediately (independently from any internal
|
||||
* frontend message queue), and/or which should be visually
|
||||
* distinguishable from frontend-generated notifications.
|
||||
* For example, a core may wish to inform the user of
|
||||
* information related to a disk-change event. It is
|
||||
* expected that the frontend itself may provide a
|
||||
* notification in this case; if the core sends a
|
||||
* message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an
|
||||
* uncomfortable 'double-notification' may occur. A message
|
||||
* of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore
|
||||
* be presented such that visual conflict with regular
|
||||
* notifications does not occur
|
||||
* > RETRO_MESSAGE_TYPE_STATUS: Indicates that message
|
||||
* is not a standard notification. This typically
|
||||
* corresponds to 'status' indicators, such as a core's
|
||||
* internal FPS, which are intended to be displayed
|
||||
* either permanently while a core is running, or in
|
||||
* a manner that does not suggest user attention or action
|
||||
* is required. 'Status' type messages should therefore be
|
||||
* displayed in a different on-screen location and in a manner
|
||||
* easily distinguishable from both standard frontend-generated
|
||||
* notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT
|
||||
* NOTE: Message type is a *hint*, and may be ignored
|
||||
* by the frontend. If a frontend lacks support for
|
||||
* displaying messages via alternate means than standard
|
||||
* frontend-generated notifications, it will treat *all*
|
||||
* messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */
|
||||
enum retro_message_type type;
|
||||
};
|
||||
|
||||
/* Describes how the libretro implementation maps a libretro input bind
|
||||
|
127
retroarch.c
127
retroarch.c
@ -1446,6 +1446,14 @@ typedef struct runloop_ctx_msg_info
|
||||
bool flush;
|
||||
} runloop_ctx_msg_info_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char str[128];
|
||||
unsigned priority;
|
||||
float duration;
|
||||
bool set;
|
||||
} runloop_core_status_msg_t;
|
||||
|
||||
struct rarch_dir_list
|
||||
{
|
||||
struct string_list *list;
|
||||
@ -1772,6 +1780,14 @@ static retro_keyboard_event_t runloop_frontend_key_event = NULL;
|
||||
static core_option_manager_t *runloop_core_options = NULL;
|
||||
static msg_queue_t *runloop_msg_queue = NULL;
|
||||
|
||||
static runloop_core_status_msg_t runloop_core_status_msg =
|
||||
{
|
||||
"",
|
||||
0,
|
||||
0.0f,
|
||||
false
|
||||
};
|
||||
|
||||
static retro_usec_t runloop_frame_time_last = 0;
|
||||
|
||||
#ifdef HAVE_DISCORD
|
||||
@ -10324,7 +10340,8 @@ static bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_MESSAGE_EXT:
|
||||
{
|
||||
const struct retro_message_ext *msg = (const struct retro_message_ext*)data;
|
||||
const struct retro_message_ext *msg = (const struct retro_message_ext*)data;
|
||||
struct retro_system_av_info *av_info = &video_driver_av_info;
|
||||
|
||||
/* Log message, if required */
|
||||
if (msg->target != RETRO_MESSAGE_TARGET_OSD)
|
||||
@ -10356,15 +10373,60 @@ static bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
/* Display message via OSD, if required */
|
||||
if (msg->target != RETRO_MESSAGE_TARGET_LOG)
|
||||
{
|
||||
/* Handle 'status' messages */
|
||||
if (msg->type == RETRO_MESSAGE_TYPE_STATUS)
|
||||
{
|
||||
/* Note: We need to lock a mutex here. Strictly
|
||||
* speaking, runloop_core_status_msg is not part
|
||||
* of the message queue, but:
|
||||
* - It may be implemented as a queue in the future
|
||||
* - It seems unnecessary to create a new slock_t
|
||||
* object for this type of message when
|
||||
* _runloop_msg_queue_lock is already available
|
||||
* We therefore just call runloop_msg_queue_lock()/
|
||||
* runloop_msg_queue_unlock() in this case */
|
||||
runloop_msg_queue_lock();
|
||||
|
||||
/* If a message is already set, only overwrite
|
||||
* it if the new message has the same or higher
|
||||
* priority */
|
||||
if (!runloop_core_status_msg.set ||
|
||||
(runloop_core_status_msg.priority <= msg->priority))
|
||||
{
|
||||
if (!string_is_empty(msg->msg))
|
||||
{
|
||||
strlcpy(runloop_core_status_msg.str, msg->msg,
|
||||
sizeof(runloop_core_status_msg.str));
|
||||
|
||||
runloop_core_status_msg.duration = (float)msg->duration;
|
||||
runloop_core_status_msg.set = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ensure sane behaviour if core sends an
|
||||
* empty message */
|
||||
runloop_core_status_msg.str[0] = '\0';
|
||||
runloop_core_status_msg.priority = 0;
|
||||
runloop_core_status_msg.duration = 0.0f;
|
||||
runloop_core_status_msg.set = false;
|
||||
}
|
||||
}
|
||||
|
||||
runloop_msg_queue_unlock();
|
||||
}
|
||||
/* Handle 'alternate' non-queued notifications */
|
||||
#if defined(HAVE_GFX_WIDGETS)
|
||||
if (gfx_widgets_active())
|
||||
gfx_widget_set_libretro_message(msg->msg,
|
||||
roundf((float)msg->frames / 60.0f * 1000.0f));
|
||||
else
|
||||
else if ((msg->type == RETRO_MESSAGE_TYPE_NOTIFICATION_ALT) &&
|
||||
gfx_widgets_active())
|
||||
gfx_widget_set_libretro_message(msg->msg, msg->duration);
|
||||
#endif
|
||||
/* Handle standard (queued) notifications */
|
||||
else
|
||||
{
|
||||
enum message_queue_category category;
|
||||
unsigned duration_frames = 0;
|
||||
|
||||
/* Assign category */
|
||||
switch (msg->level)
|
||||
{
|
||||
case RETRO_LOG_WARN:
|
||||
@ -10380,8 +10442,13 @@ static bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get duration in frames */
|
||||
if (av_info)
|
||||
duration_frames = (unsigned)((av_info->timing.fps *
|
||||
(float)msg->duration / 1000.0f) + 0.5f);
|
||||
|
||||
runloop_msg_queue_push(msg->msg,
|
||||
msg->priority, msg->frames,
|
||||
msg->priority, duration_frames,
|
||||
true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
|
||||
category);
|
||||
}
|
||||
@ -22978,6 +23045,52 @@ static void video_driver_frame(const void *data, unsigned width,
|
||||
video_driver_window_title_update = true;
|
||||
}
|
||||
|
||||
/* Add core status message to 'fps_text' string
|
||||
* TODO/FIXME: fps_text is used for several status
|
||||
* parameters, not just FPS. It should probably be
|
||||
* renamed to reflect this... */
|
||||
if (video_info.core_status_msg_show)
|
||||
{
|
||||
/* Note: We need to lock a mutex here. Strictly
|
||||
* speaking, runloop_core_status_msg is not part
|
||||
* of the message queue, but:
|
||||
* - It may be implemented as a queue in the future
|
||||
* - It seems unnecessary to create a new slock_t
|
||||
* object for this type of message when
|
||||
* _runloop_msg_queue_lock is already available
|
||||
* We therefore just call runloop_msg_queue_lock()/
|
||||
* runloop_msg_queue_unlock() in this case */
|
||||
runloop_msg_queue_lock();
|
||||
|
||||
/* Check whether duration timer has elapsed */
|
||||
runloop_core_status_msg.duration -= gfx_animation_get_delta_time();
|
||||
|
||||
if (runloop_core_status_msg.duration < 0.0f)
|
||||
{
|
||||
runloop_core_status_msg.str[0] = '\0';
|
||||
runloop_core_status_msg.priority = 0;
|
||||
runloop_core_status_msg.duration = 0.0f;
|
||||
runloop_core_status_msg.set = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If 'fps_text' is already set, add status
|
||||
* message at the end */
|
||||
if (!string_is_empty(fps_text))
|
||||
{
|
||||
strlcat(fps_text,
|
||||
" || ", sizeof(fps_text));
|
||||
strlcat(fps_text,
|
||||
runloop_core_status_msg.str, sizeof(fps_text));
|
||||
}
|
||||
else
|
||||
strlcpy(fps_text, runloop_core_status_msg.str,
|
||||
sizeof(fps_text));
|
||||
}
|
||||
|
||||
runloop_msg_queue_unlock();
|
||||
}
|
||||
|
||||
/* Slightly messy code,
|
||||
* but we really need to do processing before blocking on VSync
|
||||
* for best possible scheduling.
|
||||
@ -23139,6 +23252,7 @@ static void video_driver_frame(const void *data, unsigned width,
|
||||
if ( video_info.fps_show
|
||||
|| video_info.framecount_show
|
||||
|| video_info.memory_show
|
||||
|| video_info.core_status_msg_show
|
||||
)
|
||||
{
|
||||
#if defined(HAVE_GFX_WIDGETS)
|
||||
@ -23289,6 +23403,7 @@ void video_driver_build_info(video_frame_info_t *video_info)
|
||||
video_info->memory_show = settings->bools.video_memory_show;
|
||||
video_info->statistics_show = settings->bools.video_statistics_show;
|
||||
video_info->framecount_show = settings->bools.video_framecount_show;
|
||||
video_info->core_status_msg_show = runloop_core_status_msg.set;
|
||||
video_info->aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
|
||||
video_info->post_filter_record = settings->bools.video_post_filter_record;
|
||||
video_info->input_menu_swap_ok_cancel_buttons = settings->bools.input_menu_swap_ok_cancel_buttons;
|
||||
|
@ -1098,6 +1098,7 @@ typedef struct video_frame_info
|
||||
bool memory_show;
|
||||
bool statistics_show;
|
||||
bool framecount_show;
|
||||
bool core_status_msg_show;
|
||||
bool post_filter_record;
|
||||
bool windowed_fullscreen;
|
||||
bool fullscreen;
|
||||
|
Loading…
x
Reference in New Issue
Block a user