diff --git a/build/windows/LCUI/LCUI.vcxproj b/build/windows/LCUI/LCUI.vcxproj index 358465148..6dc910253 100644 --- a/build/windows/LCUI/LCUI.vcxproj +++ b/build/windows/LCUI/LCUI.vcxproj @@ -324,6 +324,7 @@ + @@ -423,6 +424,7 @@ + diff --git a/build/windows/LCUI/LCUI.vcxproj.filters b/build/windows/LCUI/LCUI.vcxproj.filters index b7446c0a5..872d6097e 100644 --- a/build/windows/LCUI/LCUI.vcxproj.filters +++ b/build/windows/LCUI/LCUI.vcxproj.filters @@ -123,6 +123,9 @@ 头文件\LCUI + + 头文件\LCUI + 头文件\LCUI @@ -440,6 +443,9 @@ 源文件 + + 源文件 + 源文件 diff --git a/build/windows/LCUITest/LCUITest.vcxproj b/build/windows/LCUITest/LCUITest.vcxproj index 700ccf22c..583b83851 100644 --- a/build/windows/LCUITest/LCUITest.vcxproj +++ b/build/windows/LCUITest/LCUITest.vcxproj @@ -193,6 +193,7 @@ + diff --git a/build/windows/LCUITest/LCUITest.vcxproj.filters b/build/windows/LCUITest/LCUITest.vcxproj.filters index 0d6a10fad..ace6f9966 100644 --- a/build/windows/LCUITest/LCUITest.vcxproj.filters +++ b/build/windows/LCUITest/LCUITest.vcxproj.filters @@ -21,6 +21,9 @@ 源文件 + + 源文件 + 源文件 diff --git a/build/windows/LCUIUWP/LCUIUWP.vcxproj b/build/windows/LCUIUWP/LCUIUWP.vcxproj index e5d638c88..45b90e081 100644 --- a/build/windows/LCUIUWP/LCUIUWP.vcxproj +++ b/build/windows/LCUIUWP/LCUIUWP.vcxproj @@ -69,6 +69,7 @@ + @@ -162,6 +163,7 @@ + diff --git a/build/windows/LCUIUWP/LCUIUWP.vcxproj.filters b/build/windows/LCUIUWP/LCUIUWP.vcxproj.filters index 2414f4b9d..df840d1a7 100644 --- a/build/windows/LCUIUWP/LCUIUWP.vcxproj.filters +++ b/build/windows/LCUIUWP/LCUIUWP.vcxproj.filters @@ -111,6 +111,9 @@ 头文件\LCUI + + 头文件\LCUI + 头文件\LCUI @@ -377,6 +380,9 @@ 源文件 + + 源文件 + 源文件 diff --git a/include/LCUI/Makefile.am b/include/LCUI/Makefile.am index 6e736344e..96fab821f 100755 --- a/include/LCUI/Makefile.am +++ b/include/LCUI/Makefile.am @@ -4,7 +4,7 @@ SUBDIRS=font draw gui util # Headers which are installed to support the library INSTINCLUDES=LCUI.h types.h painter.h display.h graph.h draw.h \ font.h surface.h ime.h input.h thread.h util.h timer.h main.h cursor.h \ -image.h worker.h +image.h settings.h worker.h EXTRA_DIST=platform.h \ platform/linux/linux_display.h \ platform/linux/linux_events.h \ diff --git a/include/LCUI/display.h b/include/LCUI/display.h index 865cd448b..539b231c1 100644 --- a/include/LCUI/display.h +++ b/include/LCUI/display.h @@ -116,9 +116,7 @@ LCUI_API size_t LCUIDisplay_Render(void); /** 呈现渲染后的内容 */ LCUI_API void LCUIDisplay_Present(void); -LCUI_API void LCUIDisplay_EnablePaintFlashing(LCUI_BOOL enable); - - /** 设置显示区域的尺寸,仅在窗口化、全屏模式下有效 */ +/** 设置显示区域的尺寸,仅在窗口化、全屏模式下有效 */ LCUI_API void LCUIDisplay_SetSize(int width, int height); /** 获取屏幕宽度 */ diff --git a/include/LCUI/main.h b/include/LCUI/main.h index 4217ca5d4..084db6f32 100644 --- a/include/LCUI/main.h +++ b/include/LCUI/main.h @@ -53,6 +53,7 @@ enum LCUI_SysEventType { LCUI_PAINT, LCUI_WIDGET, LCUI_QUIT, /**< 在 LCUI 退出前触发的事件 */ + LCUI_SETTINGS_CHANGE, LCUI_USER = 100 /**< 用户事件,可以把这个当成系统事件与用户事件的分界 */ }; @@ -203,7 +204,7 @@ LCUI_API void LCUI_RunFrame(void); LCUI_API void LCUI_RunFrameWithProfile(LCUI_FrameProfile profile); - /* 新建一个主循环 */ +/* 新建一个主循环 */ LCUI_API LCUI_MainLoop LCUIMainLoop_New(void); /* 运行目标循环 */ diff --git a/include/LCUI/settings.h b/include/LCUI/settings.h new file mode 100644 index 000000000..bd7e820e8 --- /dev/null +++ b/include/LCUI/settings.h @@ -0,0 +1,55 @@ +/* + * settings.h -- Functions for accessing and modifying global settings. + * + * Copyright (c) 2020, James Duong All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of LCUI nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LCUI_SETTINGS_H +#define LCUI_SETTINGS_H + +LCUI_BEGIN_HEADER + +typedef struct LCUI_SettingsRec_ { + int frame_rate_cap; + int parallel_rendering_threads; + LCUI_BOOL record_profile; + LCUI_BOOL fps_meter; + LCUI_BOOL paint_flashing; +} LCUI_SettingsRec, *LCUI_Settings; + +/* Initialize settings with the current global settings. */ +LCUI_API void Settings_Init(LCUI_Settings settings); + +/* Update global settings with the given input. */ +LCUI_API void LCUI_ApplySettings(LCUI_Settings settings); + +/* Reset global settings to their defaults. */ +LCUI_API void LCUI_ResetSettings(void); + +LCUI_END_HEADER + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 78c458bec..4c148acd6 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS=foreign AM_CFLAGS = -I$(abs_top_srcdir)/include $(CODE_COVERAGE_CFLAGS) LCUI_LDFLAGS = -version-info 2:0:0 -LCUI_SOURCES = graph.c ime.c cursor.c worker.c main.c timer.c painter.c display.c keyboard.c +LCUI_SOURCES = graph.c ime.c cursor.c worker.c main.c timer.c painter.c display.c keyboard.c settings.c LCUI_LIBADD = thread/libthread.la util/libutil.la platform/libplatform.la \ image/libimage.la draw/libdraw.la gui/libgui.la font/libfont.la \ font/in-core/libfont_incore.la $(PACKAGE_LIBS) diff --git a/src/display.c b/src/display.c index d77a89588..fe67a68bb 100644 --- a/src/display.c +++ b/src/display.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #ifdef LCUI_DISPLAY_H #include LCUI_DISPLAY_H #endif @@ -53,16 +55,6 @@ #define DEFAULT_WIDTH 800 #define DEFAULT_HEIGHT 600 -#ifdef USE_OPENMP -/** - * Parallel rendering threads - * We recommend that you set it to half the number of CPU logical cores - */ -#define PARALLEL_RENDERING_THREADS 4 -#else -#define PARALLEL_RENDERING_THREADS 1 -#endif - typedef struct FlashRectRec_ { int64_t paint_time; LCUI_Rect rect; @@ -85,11 +77,12 @@ typedef struct SurfaceRecordRec_ { static struct LCUI_DisplayModule { unsigned width, height; LCUI_BOOL active; - LCUI_BOOL enable_paint_flashing; LCUI_DisplayMode mode; LinkedList surfaces; LinkedList rects; LCUI_DisplayDriver driver; + LCUI_SettingsRec settings; + int settings_change_handler_id; } display; /* clang-format on */ @@ -113,8 +106,13 @@ static void OnDestroySurfaceRecord(void *data) free(record); } +static void OnSettingsChangeEvent(LCUI_SysEvent e, void *arg) +{ + Settings_Init(&display.settings); +} + static size_t LCUIDisplay_RenderFlashRect(SurfaceRecord record, - FlashRect flash_rect) + FlashRect flash_rect) { size_t count; int64_t period; @@ -202,7 +200,8 @@ static void GetRenderingLayerSize(int *width, int *height) *width = (int)(LCUIDisplay_GetWidth() * scale); *height = (int)(LCUIDisplay_GetHeight() * scale); - *height = max(200, *height / PARALLEL_RENDERING_THREADS + 1); + *height = + max(200, *height / display.settings.parallel_rendering_threads + 1); } static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects) @@ -221,12 +220,14 @@ static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects) LCUI_Rect rect; LCUI_Rect *sub_rect; DirtyLayer layer; - DirtyLayerRec layers[PARALLEL_RENDERING_THREADS]; + DirtyLayerRec *layers; LinkedListNode *node; GetRenderingLayerSize(&layer_width, &layer_height); max_dirty = (int)(0.8 * layer_width * layer_height); - for (i = 0; i < PARALLEL_RENDERING_THREADS; ++i) { + layers = malloc(sizeof(DirtyLayerRec) * + display.settings.parallel_rendering_threads); + for (i = 0; i < display.settings.parallel_rendering_threads; ++i) { layer = &layers[i]; layer->diry = 0; layer->rect.y = i * layer_height; @@ -238,7 +239,8 @@ static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects) sub_rect = malloc(sizeof(LCUI_Rect)); for (LinkedList_Each(node, &record->rects)) { rect = *(LCUI_Rect *)node->data; - for (i = 0; i < PARALLEL_RENDERING_THREADS; ++i) { + for (i = 0; i < display.settings.parallel_rendering_threads; + ++i) { layer = &layers[i]; if (layer->diry >= max_dirty) { continue; @@ -257,7 +259,7 @@ static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects) } } } - for (i = 0; i < PARALLEL_RENDERING_THREADS; ++i) { + for (i = 0; i < display.settings.parallel_rendering_threads; ++i) { layer = &layers[i]; if (layer->diry >= max_dirty) { RectList_AddEx(rects, &layer->rect, FALSE); @@ -268,6 +270,7 @@ static void SurfaceRecord_DumpRects(SurfaceRecord record, LinkedList *rects) } RectList_Clear(&record->rects); free(sub_rect); + free(layers); } static size_t LCUIDisplay_RenderSurfaceRect(SurfaceRecord record, @@ -288,7 +291,7 @@ static size_t LCUIDisplay_RenderSurfaceRect(SurfaceRecord record, omp_get_num_threads(), paint->rect.x, paint->rect.y, paint->rect.width, paint->rect.height); count = Widget_Render(record->widget, paint); - if (display.enable_paint_flashing) { + if (display.settings.paint_flashing) { LCUIDisplay_AppendFlashRects(record, &paint->rect); } if (display.mode != LCUI_DMODE_SEAMLESS) { @@ -622,11 +625,6 @@ int LCUIDisplay_GetMode(void) return display.mode; } -void LCUIDisplay_EnablePaintFlashing(LCUI_BOOL enable) -{ - display.enable_paint_flashing = enable; -} - /** 设置显示区域的尺寸,仅在窗口化、全屏模式下有效 */ void LCUIDisplay_SetSize(int width, int height) { @@ -948,6 +946,10 @@ int LCUI_InitDisplay(LCUI_DisplayDriver driver) display.active = TRUE; display.width = DEFAULT_WIDTH; display.height = DEFAULT_HEIGHT; + Settings_Init(&display.settings); + display.settings_change_handler_id = LCUI_BindEvent( + LCUI_SETTINGS_CHANGE, OnSettingsChangeEvent, NULL, NULL); + LinkedList_Init(&display.rects); LinkedList_Init(&display.surfaces); if (!display.driver) { @@ -984,5 +986,7 @@ int LCUI_FreeDisplay(void) if (display.driver) { LCUI_DestroyDisplayDriver(display.driver); } + LCUI_UnbindEvent(display.settings_change_handler_id); + display.settings_change_handler_id = -1; return 0; } diff --git a/src/main.c b/src/main.c index 5b4771d02..d93120450 100644 --- a/src/main.c +++ b/src/main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include #ifdef LCUI_EVENTS_H #include LCUI_EVENTS_H #endif @@ -107,12 +109,13 @@ static struct LCUI_App { LCUI_Worker main_worker; /**< 主工作线程 */ LCUI_Worker workers[LCUI_WORKER_NUM]; /**< 普通工作线程 */ int worker_next; /**< 下一个工作线程编号 */ + LCUI_SettingsRec settings; + LCUI_ProfileRec profile; + LCUI_FrameProfile frame; + int settings_change_handler_id; } MainApp; /* clang-format on */ - -#ifdef DEBUG - static void LCUIProfile_Init(LCUI_Profile profile) { memset(profile, 0, sizeof(LCUI_ProfileRec)); @@ -153,24 +156,25 @@ static void LCUIProfile_Print(LCUI_Profile profile) } } -static LCUI_FrameProfile LCUIProfile_BeginFrame(LCUI_Profile profile) +static LCUI_FrameProfile LCUIProfile_BeginFrame(LCUI_Profile profile, + LCUI_Settings settings) { LCUI_FrameProfile frame; frame = &profile->frames[profile->frames_count]; - if (profile->frames_count > LCUI_MAX_FRAMES_PER_SEC) { + if (profile->frames_count > settings->frame_rate_cap) { profile->frames_count = 0; } memset(frame, 0, sizeof(LCUI_FrameProfileRec)); return frame; } -static void LCUIProfile_EndFrame(LCUI_Profile profile) +static void LCUIProfile_EndFrame(LCUI_Profile profile, LCUI_Settings settings) { profile->frames_count += 1; profile->end_time = clock(); if (profile->end_time - profile->start_time >= CLOCKS_PER_SEC) { - if (profile->frames_count < LCUI_MAX_FRAMES_PER_SEC / 4) { + if (profile->frames_count < settings->frame_rate_cap / 4) { LCUIProfile_Print(profile); } profile->frames_count = 0; @@ -178,7 +182,11 @@ static void LCUIProfile_EndFrame(LCUI_Profile profile) } } -#endif +static void OnSettingsChangeEvent(LCUI_SysEvent e, void *arg) +{ + Settings_Init(&MainApp.settings); + StepTimer_SetFrameLimit(MainApp.timer, MainApp.settings.frame_rate_cap); +} void LCUI_RunFrameWithProfile(LCUI_FrameProfile profile) { @@ -279,6 +287,9 @@ int LCUI_UnbindEvent(int handler_id) int LCUI_TriggerEvent(LCUI_SysEvent e, void *arg) { + if (System.state != STATE_ACTIVE) { + return -1; + } int ret; SysEventPackRec pack; pack.arg = arg; @@ -385,10 +396,6 @@ LCUI_MainLoop LCUIMainLoop_New(void) /** 运行目标主循环 */ int LCUIMainLoop_Run(LCUI_MainLoop loop) { -#ifdef DEBUG - LCUI_ProfileRec profile; - LCUI_FrameProfile frame; -#endif LCUI_BOOL at_same_thread = FALSE; if (loop->state == STATE_RUNNING) { DEBUG_MSG("error: main-loop already running.\n"); @@ -409,17 +416,17 @@ int LCUIMainLoop_Run(LCUI_MainLoop loop) } DEBUG_MSG("loop: %p, enter\n", loop); MainApp.loop = loop; -#ifdef DEBUG - LCUIProfile_Init(&profile); -#endif while (loop->state != STATE_EXITED) { -#ifdef DEBUG - frame = LCUIProfile_BeginFrame(&profile); - LCUI_RunFrameWithProfile(frame); - LCUIProfile_EndFrame(&profile); -#else - LCUI_RunFrame(); -#endif + if (MainApp.settings.record_profile) { + MainApp.frame = LCUIProfile_BeginFrame( + &MainApp.profile, &MainApp.settings); + LCUI_RunFrameWithProfile(MainApp.frame); + LCUIProfile_EndFrame(&MainApp.profile, + &MainApp.settings); + } else { + LCUI_RunFrame(); + } + StepTimer_Remain(MainApp.timer); /* 如果当前运行的主循环不是自己 */ while (MainApp.loop != loop) { @@ -466,12 +473,17 @@ void LCUI_InitApp(LCUI_AppDriver app) LCUICond_Init(&MainApp.loop_changed); LCUIMutex_Init(&MainApp.loop_mutex); LinkedList_Init(&MainApp.loops); + LCUIProfile_Init(&MainApp.profile); + LCUI_ResetSettings(); + MainApp.settings_change_handler_id = LCUI_BindEvent( + LCUI_SETTINGS_CHANGE, OnSettingsChangeEvent, NULL, NULL); + Settings_Init(&MainApp.settings); MainApp.main_worker = LCUIWorker_New(); for (i = 0; i < LCUI_WORKER_NUM; ++i) { MainApp.workers[i] = LCUIWorker_New(); LCUIWorker_RunAsync(MainApp.workers[i]); } - StepTimer_SetFrameLimit(MainApp.timer, LCUI_MAX_FRAMES_PER_SEC); + StepTimer_SetFrameLimit(MainApp.timer, MainApp.settings.frame_rate_cap); if (!app) { app = LCUI_CreateAppDriver(); if (!app) { @@ -502,6 +514,8 @@ static void LCUI_FreeApp(void) LCUI_MainLoop loop; LinkedListNode *node; MainApp.active = FALSE; + LCUI_UnbindEvent(MainApp.settings_change_handler_id); + MainApp.settings_change_handler_id = -1; for (LinkedList_Each(node, &MainApp.loops)) { loop = node->data; LCUIMainLoop_Quit(loop); diff --git a/src/settings.c b/src/settings.c new file mode 100644 index 000000000..860bb3914 --- /dev/null +++ b/src/settings.c @@ -0,0 +1,69 @@ +/* settings.c -- global settings. + * + * Copyright (c) 2020, James Duong All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of LCUI nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +static LCUI_SettingsRec self; + +static void TriggerSettingsChangedEvent(void) +{ + LCUI_SysEventRec event = { 0 }; + event.type = LCUI_SETTINGS_CHANGE; + LCUI_TriggerEvent(&event, &self); +} + +/* Initialize settings with the current global settings. */ +void Settings_Init(LCUI_Settings settings) +{ + *settings = self; +} + +/* Update global settings with the given input. */ +void LCUI_ApplySettings(LCUI_Settings settings) +{ + self = *settings; + self.frame_rate_cap = max(self.frame_rate_cap, 1); + self.parallel_rendering_threads = + max(self.parallel_rendering_threads, 1); + TriggerSettingsChangedEvent(); +} + +/* Reset global settings to their defaults. */ +void LCUI_ResetSettings(void) +{ + self.frame_rate_cap = 120; + self.parallel_rendering_threads = 4; + self.record_profile = FALSE; + self.fps_meter = FALSE; + self.paint_flashing = FALSE; + TriggerSettingsChangedEvent(); +} diff --git a/test/Makefile.am b/test/Makefile.am index 79c100c9c..7e85effdd 100755 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -31,7 +31,8 @@ test_widget_rect.c \ test_widget_opacity.c \ test_widget_event.c \ test_textview_resize.c \ -test_textedit.c +test_textedit.c \ +test_settings.c test_LDADD = $(top_builddir)/src/libLCUI.la -lm $(CODE_COVERAGE_LIBS) diff --git a/test/test.c b/test/test.c index c1645bf47..fdc474025 100644 --- a/test/test.c +++ b/test/test.c @@ -15,6 +15,7 @@ int main(void) describe("test linkedlist", test_linkedlist); describe("test string", test_string); describe("test strpool", test_strpool); + describe("test settings", test_settings); describe("test object", test_object); describe("test thread", test_thread); describe("test font load", test_font_load); diff --git a/test/test.h b/test/test.h index f7c1e6d7b..8bee6c516 100644 --- a/test/test.h +++ b/test/test.h @@ -5,6 +5,7 @@ extern int tests_count; void test_charset(void); void test_string(void); void test_object(void); +void test_settings(void); void test_thread(void); void test_font_load(void); void test_xml_parser(void); diff --git a/test/test_settings.c b/test/test_settings.c new file mode 100644 index 000000000..74ef31d18 --- /dev/null +++ b/test/test_settings.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include "test.h" +#include "libtest.h" + +static int settings_change_count = 0; + +static void on_settings_change(LCUI_SysEvent object, void *data) +{ + ++settings_change_count; +} + +static void check_settings_frame_rate_cap(void *arg) +{ + char str[256]; + int fps_limit = *((int *)arg); + int fps = LCUI_GetFrameCount(); + + sprintf(str, "should work when frame cap is %d (actual %d)", fps_limit, + fps); + it_b(str, fps <= fps_limit && fps > fps_limit - 2, TRUE); + LCUI_Quit(); +} + +static void test_default_settings(void) +{ + LCUI_SettingsRec settings; + + LCUI_Init(); + LCUI_ResetSettings(); + Settings_Init(&settings); + + it_i("check default frame rate cap", settings.frame_rate_cap, 120); + it_i("check default parallel rendering threads", + settings.parallel_rendering_threads, 4); + it_b("check default record profile", settings.record_profile, FALSE); + it_b("check default fps meter", settings.fps_meter, FALSE); + it_b("check default paint flashing", settings.paint_flashing, FALSE); + LCUI_Destroy(); +} + +static void test_apply_settings(void) +{ + LCUI_SettingsRec settings; + + LCUI_Init(); + int handler = LCUI_BindEvent(LCUI_SETTINGS_CHANGE, on_settings_change, NULL, NULL); + + settings.frame_rate_cap = 60; + settings.parallel_rendering_threads = 2; + settings.record_profile = TRUE; + settings.fps_meter = TRUE; + settings.paint_flashing = TRUE; + + LCUI_ApplySettings(&settings); + Settings_Init(&settings); + it_i("check frame rate cap", settings.frame_rate_cap, 60); + it_i("check parallel rendering threads", + settings.parallel_rendering_threads, 2); + it_b("check record profile", settings.record_profile, TRUE); + it_b("check fps meter", settings.fps_meter, TRUE); + it_b("check paint flashing", settings.paint_flashing, TRUE); + + it_i("check settings change count", settings_change_count, 1); + + settings.frame_rate_cap = -1; + settings.parallel_rendering_threads = -1; + + LCUI_ApplySettings(&settings); + Settings_Init(&settings); + it_i("check frame rate cap minimum", settings.frame_rate_cap, 1); + it_i("check parallel rendering threads minimum", + settings.parallel_rendering_threads, 1); + it_i("check settings change count", settings_change_count, 2); + + LCUI_ResetSettings(); + it_i("check settings change count", settings_change_count, 3); + LCUI_UnbindEvent(handler); + LCUI_Destroy(); +} + +void test_settings_frame_rate_cap(void) +{ + LCUI_SettingsRec settings; + LCUI_Init(); + Settings_Init(&settings); + + settings.frame_rate_cap = 30; + LCUI_ApplySettings(&settings); + LCUI_SetTimeout(1000, check_settings_frame_rate_cap, + &settings.frame_rate_cap); + LCUI_Main(); + + LCUI_Init(); + settings.frame_rate_cap = 5; + LCUI_ApplySettings(&settings); + LCUI_SetTimeout(1000, check_settings_frame_rate_cap, + &settings.frame_rate_cap); + LCUI_Main(); + + LCUI_Init(); + settings.frame_rate_cap = 90; + LCUI_ApplySettings(&settings); + LCUI_SetTimeout(1000, check_settings_frame_rate_cap, + &settings.frame_rate_cap); + LCUI_Main(); + + LCUI_Init(); + settings.frame_rate_cap = 25; + LCUI_ApplySettings(&settings); + LCUI_SetTimeout(1000, check_settings_frame_rate_cap, + &settings.frame_rate_cap); + LCUI_Main(); +} + +void test_settings(void) +{ + describe("test default settings", test_default_settings); + describe("test apply settings", test_apply_settings); + describe("test settings.frame_rate_cap", test_settings_frame_rate_cap); +}