diff --git a/disk_control_interface.c b/disk_control_interface.c index 6ca50e8e1b..63d4c90b27 100644 --- a/disk_control_interface.c +++ b/disk_control_interface.c @@ -752,10 +752,14 @@ bool disk_control_verify_initial_index(disk_control_interface_t *disk_control) RARCH_LOG("%s\n", msg); + /* Note: Do not flush message queue here, since + * it is likely other notifications will be + * generated before setting the disk index, and + * we do not want to 'overwrite' them */ runloop_msg_queue_push( msg, 0, msg_duration, - true, NULL, + false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); } diff --git a/libretro-common/include/queues/message_queue.h b/libretro-common/include/queues/message_queue.h index 492e3472dc..b18abae3cd 100644 --- a/libretro-common/include/queues/message_queue.h +++ b/libretro-common/include/queues/message_queue.h @@ -44,6 +44,16 @@ enum message_queue_category typedef struct msg_queue msg_queue_t; +typedef struct +{ + char msg[1024]; + char title[1024]; + unsigned duration; + unsigned prio; + enum message_queue_icon icon; + enum message_queue_category category; +} msg_queue_entry_t; + /** * msg_queue_new: * @size : maximum size of message @@ -82,6 +92,28 @@ void msg_queue_push(msg_queue_t *queue, const char *msg, **/ const char *msg_queue_pull(msg_queue_t *queue); +/** + * msg_queue_extract: + * @queue : pointer to queue object + * @queue_entry : pointer to external queue entry struct + * + * Removes highest priority message from queue, copying + * contents into queue_entry struct. + * + * Returns: false if no messages in queue, otherwise true + **/ +bool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry); + +/** + * msg_queue_size: + * @queue : pointer to queue object + * + * Fetches number of messages in queue. + * + * Returns: Number of messages in queue. + **/ +size_t msg_queue_size(msg_queue_t *queue); + /** * msg_queue_clear: * @queue : pointer to queue object diff --git a/libretro-common/queues/message_queue.c b/libretro-common/queues/message_queue.c index 9603335e51..6ef1812a8b 100644 --- a/libretro-common/queues/message_queue.c +++ b/libretro-common/queues/message_queue.c @@ -127,6 +127,9 @@ void msg_queue_push(msg_queue_t *queue, const char *msg, new_elem->prio = prio; new_elem->duration = duration; new_elem->msg = msg ? strdup(msg) : NULL; + new_elem->title = title ? strdup(title) : NULL; + new_elem->icon = icon; + new_elem->category = category; queue->elems[queue->ptr] = new_elem; @@ -165,6 +168,7 @@ void msg_queue_clear(msg_queue_t *queue) if (queue->elems[i]) { free(queue->elems[i]->msg); + free(queue->elems[i]->title); free(queue->elems[i]); queue->elems[i] = NULL; } @@ -203,9 +207,9 @@ const char *msg_queue_pull(msg_queue_t *queue) queue->tmp_msg = front->msg; front->msg = NULL; - front = (struct queue_elem*)queue->elems[1]; last = (struct queue_elem*)queue->elems[--queue->ptr]; queue->elems[1] = last; + free(front->title); free(front); for (;;) @@ -243,3 +247,100 @@ const char *msg_queue_pull(msg_queue_t *queue) return queue->tmp_msg; } + +/** + * msg_queue_extract: + * @queue : pointer to queue object + * @queue_entry : pointer to external queue entry struct + * + * Removes highest priority message from queue, copying + * contents into queue_entry struct. + * + * Returns: false if no messages in queue, otherwise true + **/ +bool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry) +{ + struct queue_elem *front = NULL, *last = NULL; + size_t tmp_ptr = 1; + + (void)tmp_ptr; + + /* Ensure arguments are valid and queue is not + * empty */ + if (!queue || queue->ptr == 1 || !queue_entry) + return false; + + front = (struct queue_elem*)queue->elems[1]; + last = (struct queue_elem*)queue->elems[--queue->ptr]; + queue->elems[1] = last; + + /* Copy element parameters */ + queue_entry->duration = front->duration; + queue_entry->prio = front->prio; + queue_entry->icon = front->icon; + queue_entry->category = front->category; + queue_entry->msg[0] = '\0'; + queue_entry->title[0] = '\0'; + + if (front->msg) + strlcpy(queue_entry->msg, front->msg, sizeof(queue_entry->msg)); + + if (front->title) + strlcpy(queue_entry->title, front->title, sizeof(queue_entry->title)); + + /* Delete element */ + free(front->msg); + free(front->title); + free(front); + + for (;;) + { + struct queue_elem *parent = NULL; + struct queue_elem *child = NULL; + size_t switch_index = tmp_ptr; + bool left = (tmp_ptr * 2 <= queue->ptr) + && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]); + bool right = (tmp_ptr * 2 + 1 <= queue->ptr) + && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]); + + if (!left && !right) + break; + + if (left && !right) + switch_index <<= 1; + else if (right && !left) + switch_index += switch_index + 1; + else + { + if (queue->elems[tmp_ptr * 2] + >= queue->elems[tmp_ptr * 2 + 1]) + switch_index <<= 1; + else + switch_index += switch_index + 1; + } + + parent = (struct queue_elem*)queue->elems[tmp_ptr]; + child = (struct queue_elem*)queue->elems[switch_index]; + queue->elems[tmp_ptr] = child; + queue->elems[switch_index] = parent; + tmp_ptr = switch_index; + } + + return true; +} + +/** + * msg_queue_size: + * @queue : pointer to queue object + * + * Fetches number of messages in queue. + * + * Returns: Number of messages in queue. + **/ +size_t msg_queue_size(msg_queue_t *queue) +{ + if (!queue || queue->ptr <= 1) + return 0; + + return queue->ptr - 1; +} diff --git a/retroarch.c b/retroarch.c index 7630ef2986..c0853cfb56 100644 --- a/retroarch.c +++ b/retroarch.c @@ -1087,6 +1087,7 @@ static retro_keyboard_event_t runloop_key_event = NULL; 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 size_t runloop_msg_queue_size = 0; static unsigned runloop_pending_windowed_scale = 0; static unsigned runloop_max_frames = 0; @@ -3741,7 +3742,8 @@ static void retroarch_msg_queue_deinit(void) _runloop_msg_queue_lock = NULL; #endif - runloop_msg_queue = NULL; + runloop_msg_queue = NULL; + runloop_msg_queue_size = 0; } static void retroarch_msg_queue_init(void) @@ -23597,14 +23599,57 @@ static void video_driver_frame(const void *data, unsigned width, video_driver_msg[0] = '\0'; - if (video_info.font_enable) + if (runloop_msg_queue_size > 0) { - const char *msg = NULL; - runloop_msg_queue_lock(); - msg = msg_queue_pull(runloop_msg_queue); - if (msg) - strlcpy(video_driver_msg, msg, sizeof(video_driver_msg)); - runloop_msg_queue_unlock(); + /* If widgets are currently enabled, then + * messages were pushed to the queue before + * widgets were initialised - in this case, the + * first item in the message queue should be + * extracted and pushed to the widget message + * queue instead */ +#if defined(HAVE_GFX_WIDGETS) + if (gfx_widgets_inited) + { + bool msg_found = false; + msg_queue_entry_t msg_entry; + + runloop_msg_queue_lock(); + msg_found = msg_queue_extract(runloop_msg_queue, &msg_entry); + runloop_msg_queue_size = msg_queue_size(runloop_msg_queue); + runloop_msg_queue_unlock(); + + if (msg_found) + gfx_widgets_msg_queue_push( + NULL, + msg_entry.msg, + roundf((float)msg_entry.duration / 60.0f * 1000.0f), + msg_entry.title, + msg_entry.icon, + msg_entry.category, + msg_entry.prio, + false, +#ifdef HAVE_MENU + menu_driver_alive +#else + false +#endif + ); + } + /* ...otherwise, just output message via + * regular OSD notification text (if enabled) */ + else if (video_info.font_enable) +#else + if (video_info.font_enable) +#endif + { + const char *msg = NULL; + runloop_msg_queue_lock(); + msg = msg_queue_pull(runloop_msg_queue); + runloop_msg_queue_size = msg_queue_size(runloop_msg_queue); + if (msg) + strlcpy(video_driver_msg, msg, sizeof(video_driver_msg)); + runloop_msg_queue_unlock(); + } } if (video_info.statistics_show) @@ -28570,6 +28615,8 @@ void runloop_msg_queue_push(const char *msg, msg_queue_push(runloop_msg_queue, msg, prio, duration, title, icon, category); + + runloop_msg_queue_size = msg_queue_size(runloop_msg_queue); } ui_companion_driver_msg_queue_push(msg,