1 /* 2 * Copyright RIME Developers 3 * Distributed under the BSD License 4 * 5 * 2011-08-08 GONG Chen <chen.sst@gmail.com> v0.9 6 * 2013-05-02 GONG Chen <chen.sst@gmail.com> v1.0 7 */ 8 #ifndef RIME_API_H_ 9 #define RIME_API_H_ 10 11 #ifdef __cplusplus 12 extern "C" { 13 #endif 14 15 #include <stddef.h> 16 #include <stdint.h> 17 18 #if defined(_WIN32) 19 #if defined(RIME_EXPORTS) 20 /* DLL export */ 21 #define RIME_API __declspec(dllexport) 22 #elif defined(RIME_IMPORTS) 23 /* DLL import */ 24 #define RIME_API __declspec(dllimport) 25 #else 26 /* static library */ 27 #define RIME_API 28 #endif 29 #else /* _WIN32 */ 30 #define RIME_API 31 #endif /* _WIN32 */ 32 33 typedef uintptr_t RimeSessionId; 34 35 typedef int Bool; 36 37 #ifndef False 38 #define False 0 39 #endif 40 #ifndef True 41 #define True 1 42 #endif 43 44 //! Define the max number of candidates 45 /*! 46 * \deprecated There is no limit to the number of candidates in RimeMenu 47 */ 48 #define RIME_MAX_NUM_CANDIDATES 10 49 50 // Version control 51 #define RIME_STRUCT_INIT(Type, var) ((var).data_size = sizeof(Type) - sizeof((var).data_size)) 52 #define RIME_STRUCT_HAS_MEMBER(var, member) ((int)(sizeof((var).data_size) + (var).data_size) > (char*)&member - (char*)&var) 53 #define RIME_STRUCT_CLEAR(var) memset((char*)&(var) + sizeof((var).data_size), 0, (var).data_size) 54 55 //! Define a variable of Type 56 #define RIME_STRUCT(Type, var) Type var = {0}; RIME_STRUCT_INIT(Type, var); 57 58 //! For passing pointer to capnproto builder as opaque pointer through C API. 59 #define RIME_PROTO_BUILDER void 60 61 //! Rime traits structure 62 /*! 63 * Should be initialized by calling RIME_STRUCT_INIT(Type, var) 64 */ 65 typedef struct rime_traits_t { 66 int data_size; 67 // v0.9 68 const char* shared_data_dir; 69 const char* user_data_dir; 70 const char* distribution_name; 71 const char* distribution_code_name; 72 const char* distribution_version; 73 // v1.0 74 /*! 75 * Pass a C-string constant in the format "rime.x" 76 * where 'x' is the name of your application. 77 * Add prefix "rime." to ensure old log files are automatically cleaned. 78 */ 79 const char* app_name; 80 81 //! A list of modules to load before initializing 82 const char** modules; 83 // v1.6 84 /*! Minimal level of logged messages. 85 * Value is passed to Glog library using FLAGS_minloglevel variable. 86 * 0 = INFO (default), 1 = WARNING, 2 = ERROR, 3 = FATAL 87 */ 88 int min_log_level; 89 /*! Directory of log files. 90 * Value is passed to Glog library using FLAGS_log_dir variable. 91 */ 92 const char* log_dir; 93 //! prebuilt data directory. defaults to ${shared_data_dir}/build 94 const char* prebuilt_data_dir; 95 //! staging directory. defaults to ${user_data_dir}/build 96 const char* staging_dir; 97 } RimeTraits; 98 99 typedef struct { 100 int length; 101 int cursor_pos; 102 int sel_start; 103 int sel_end; 104 char* preedit; 105 } RimeComposition; 106 107 typedef struct rime_candidate_t { 108 char* text; 109 char* comment; 110 void* reserved; 111 } RimeCandidate; 112 113 typedef struct { 114 int page_size; 115 int page_no; 116 Bool is_last_page; 117 int highlighted_candidate_index; 118 int num_candidates; 119 RimeCandidate* candidates; 120 char* select_keys; 121 } RimeMenu; 122 123 /*! 124 * Should be initialized by calling RIME_STRUCT_INIT(Type, var); 125 */ 126 typedef struct rime_commit_t { 127 int data_size; 128 // v0.9 129 char* text; 130 } RimeCommit; 131 132 /*! 133 * Should be initialized by calling RIME_STRUCT_INIT(Type, var); 134 */ 135 typedef struct rime_context_t { 136 int data_size; 137 // v0.9 138 RimeComposition composition; 139 RimeMenu menu; 140 // v0.9.2 141 char* commit_text_preview; 142 char** select_labels; 143 } RimeContext; 144 145 /*! 146 * Should be initialized by calling RIME_STRUCT_INIT(Type, var); 147 */ 148 typedef struct rime_status_t { 149 int data_size; 150 // v0.9 151 char* schema_id; 152 char* schema_name; 153 Bool is_disabled; 154 Bool is_composing; 155 Bool is_ascii_mode; 156 Bool is_full_shape; 157 Bool is_simplified; 158 Bool is_traditional; 159 Bool is_ascii_punct; 160 } RimeStatus; 161 162 typedef struct rime_candidate_list_iterator_t { 163 void *ptr; 164 int index; 165 RimeCandidate candidate; 166 } RimeCandidateListIterator; 167 168 typedef struct rime_config_t { 169 void* ptr; 170 } RimeConfig; 171 172 typedef struct rime_config_iterator_t { 173 void* list; 174 void* map; 175 int index; 176 const char* key; 177 const char* path; 178 } RimeConfigIterator; 179 180 typedef struct rime_schema_list_item_t { 181 char* schema_id; 182 char* name; 183 void* reserved; 184 } RimeSchemaListItem; 185 186 typedef struct rime_schema_list_t { 187 size_t size; 188 RimeSchemaListItem* list; 189 } RimeSchemaList; 190 191 typedef void (*RimeNotificationHandler)(void* context_object, 192 RimeSessionId session_id, 193 const char* message_type, 194 const char* message_value); 195 196 // Setup 197 198 /*! 199 * Call this function before accessing any other API. 200 */ 201 RIME_API void RimeSetup(RimeTraits *traits); 202 203 /*! 204 * Pass a C-string constant in the format "rime.x" 205 * where 'x' is the name of your application. 206 * Add prefix "rime." to ensure old log files are automatically cleaned. 207 * \deprecated Use RimeSetup() instead. 208 */ 209 RIME_API void RimeSetupLogging(const char* app_name); 210 211 //! Receive notifications 212 /*! 213 * - on loading schema: 214 * + message_type="schema", message_value="luna_pinyin/Luna Pinyin" 215 * - on changing mode: 216 * + message_type="option", message_value="ascii_mode" 217 * + message_type="option", message_value="!ascii_mode" 218 * - on deployment: 219 * + session_id = 0, message_type="deploy", message_value="start" 220 * + session_id = 0, message_type="deploy", message_value="success" 221 * + session_id = 0, message_type="deploy", message_value="failure" 222 * 223 * handler will be called with context_object as the first parameter 224 * every time an event occurs in librime, until RimeFinalize() is called. 225 * when handler is NULL, notification is disabled. 226 */ 227 RIME_API void RimeSetNotificationHandler(RimeNotificationHandler handler, 228 void* context_object); 229 230 // Entry and exit 231 232 RIME_API void RimeInitialize(RimeTraits *traits); 233 RIME_API void RimeFinalize(); 234 235 RIME_API Bool RimeStartMaintenance(Bool full_check); 236 237 //! \deprecated Use RimeStartMaintenance(full_check = False) instead. 238 RIME_API Bool RimeStartMaintenanceOnWorkspaceChange(); 239 RIME_API Bool RimeIsMaintenancing(); 240 RIME_API void RimeJoinMaintenanceThread(); 241 242 // Deployment 243 244 RIME_API void RimeDeployerInitialize(RimeTraits *traits); 245 RIME_API Bool RimePrebuildAllSchemas(); 246 RIME_API Bool RimeDeployWorkspace(); 247 RIME_API Bool RimeDeploySchema(const char *schema_file); 248 RIME_API Bool RimeDeployConfigFile(const char *file_name, const char *version_key); 249 250 RIME_API Bool RimeSyncUserData(); 251 252 // Session management 253 254 RIME_API RimeSessionId RimeCreateSession(); 255 RIME_API Bool RimeFindSession(RimeSessionId session_id); 256 RIME_API Bool RimeDestroySession(RimeSessionId session_id); 257 RIME_API void RimeCleanupStaleSessions(); 258 RIME_API void RimeCleanupAllSessions(); 259 260 // Input 261 262 RIME_API Bool RimeProcessKey(RimeSessionId session_id, int keycode, int mask); 263 /*! 264 * return True if there is unread commit text 265 */ 266 RIME_API Bool RimeCommitComposition(RimeSessionId session_id); 267 RIME_API void RimeClearComposition(RimeSessionId session_id); 268 269 // Output 270 271 RIME_API Bool RimeGetCommit(RimeSessionId session_id, RimeCommit* commit); 272 RIME_API Bool RimeFreeCommit(RimeCommit* commit); 273 RIME_API Bool RimeGetContext(RimeSessionId session_id, RimeContext* context); 274 RIME_API Bool RimeFreeContext(RimeContext* context); 275 RIME_API Bool RimeGetStatus(RimeSessionId session_id, RimeStatus* status); 276 RIME_API Bool RimeFreeStatus(RimeStatus* status); 277 278 // Accessing candidate list 279 RIME_API Bool RimeCandidateListBegin(RimeSessionId session_id, RimeCandidateListIterator* iterator); 280 RIME_API Bool RimeCandidateListNext(RimeCandidateListIterator* iterator); 281 RIME_API void RimeCandidateListEnd(RimeCandidateListIterator* iterator); 282 RIME_API Bool RimeCandidateListFromIndex(RimeSessionId session_id, 283 RimeCandidateListIterator* iterator, 284 int index); 285 286 // Runtime options 287 288 RIME_API void RimeSetOption(RimeSessionId session_id, const char* option, Bool value); 289 RIME_API Bool RimeGetOption(RimeSessionId session_id, const char* option); 290 291 RIME_API void RimeSetProperty(RimeSessionId session_id, const char* prop, const char* value); 292 RIME_API Bool RimeGetProperty(RimeSessionId session_id, const char* prop, char* value, size_t buffer_size); 293 294 RIME_API Bool RimeGetSchemaList(RimeSchemaList* schema_list); 295 RIME_API void RimeFreeSchemaList(RimeSchemaList* schema_list); 296 RIME_API Bool RimeGetCurrentSchema(RimeSessionId session_id, char* schema_id, size_t buffer_size); 297 RIME_API Bool RimeSelectSchema(RimeSessionId session_id, const char* schema_id); 298 299 // Configuration 300 301 // <schema_id>.schema.yaml 302 RIME_API Bool RimeSchemaOpen(const char* schema_id, RimeConfig* config); 303 // <config_id>.yaml 304 RIME_API Bool RimeConfigOpen(const char* config_id, RimeConfig* config); 305 // access config files in user data directory, eg. user.yaml and installation.yaml 306 RIME_API Bool RimeUserConfigOpen(const char* config_id, RimeConfig* config); 307 RIME_API Bool RimeConfigClose(RimeConfig* config); 308 RIME_API Bool RimeConfigInit(RimeConfig* config); 309 RIME_API Bool RimeConfigLoadString(RimeConfig* config, const char* yaml); 310 // Access config values 311 RIME_API Bool RimeConfigGetBool(RimeConfig *config, const char *key, Bool *value); 312 RIME_API Bool RimeConfigGetInt(RimeConfig *config, const char *key, int *value); 313 RIME_API Bool RimeConfigGetDouble(RimeConfig *config, const char *key, double *value); 314 RIME_API Bool RimeConfigGetString(RimeConfig *config, const char *key, 315 char *value, size_t buffer_size); 316 RIME_API const char* RimeConfigGetCString(RimeConfig *config, const char *key); 317 RIME_API Bool RimeConfigSetBool(RimeConfig *config, const char *key, Bool value); 318 RIME_API Bool RimeConfigSetInt(RimeConfig *config, const char *key, int value); 319 RIME_API Bool RimeConfigSetDouble(RimeConfig *config, const char *key, double value); 320 RIME_API Bool RimeConfigSetString(RimeConfig *config, const char *key, const char *value); 321 // Manipulate complex structures 322 RIME_API Bool RimeConfigGetItem(RimeConfig* config, const char* key, RimeConfig* value); 323 RIME_API Bool RimeConfigSetItem(RimeConfig* config, const char* key, RimeConfig* value); 324 RIME_API Bool RimeConfigClear(RimeConfig* config, const char* key); 325 RIME_API Bool RimeConfigCreateList(RimeConfig* config, const char* key); 326 RIME_API Bool RimeConfigCreateMap(RimeConfig* config, const char* key); 327 RIME_API size_t RimeConfigListSize(RimeConfig* config, const char* key); 328 RIME_API Bool RimeConfigBeginList(RimeConfigIterator* iterator, RimeConfig* config, const char* key); 329 RIME_API Bool RimeConfigBeginMap(RimeConfigIterator* iterator, RimeConfig* config, const char* key); 330 RIME_API Bool RimeConfigNext(RimeConfigIterator* iterator); 331 RIME_API void RimeConfigEnd(RimeConfigIterator* iterator); 332 // Utilities 333 RIME_API Bool RimeConfigUpdateSignature(RimeConfig* config, const char* signer); 334 335 // Testing 336 337 RIME_API Bool RimeSimulateKeySequence(RimeSessionId session_id, const char *key_sequence); 338 339 // Module 340 341 /*! 342 * Extend the structure to publish custom data/functions in your specific module 343 */ 344 typedef struct rime_custom_api_t { 345 int data_size; 346 } RimeCustomApi; 347 348 typedef struct rime_module_t { 349 int data_size; 350 351 const char* module_name; 352 void (*initialize)(); 353 void (*finalize)(); 354 RimeCustomApi* (*get_api)(); 355 } RimeModule; 356 357 RIME_API Bool RimeRegisterModule(RimeModule* module); 358 RIME_API RimeModule* RimeFindModule(const char* module_name); 359 360 //! Run a registered task 361 RIME_API Bool RimeRunTask(const char* task_name); 362 363 RIME_API const char* RimeGetSharedDataDir(); 364 RIME_API const char* RimeGetUserDataDir(); 365 RIME_API const char* RimeGetSyncDir(); 366 RIME_API const char* RimeGetUserId(); 367 368 /*! The API structure 369 * RimeApi is for rime v1.0+ 370 */ 371 typedef struct rime_api_t { 372 int data_size; 373 374 /*! setup 375 * Call this function before accessing any other API functions. 376 */ 377 void (*setup)(RimeTraits* traits); 378 379 /*! Set up the notification callbacks 380 * Receive notifications 381 * - on loading schema: 382 * + message_type="schema", message_value="luna_pinyin/Luna Pinyin" 383 * - on changing mode: 384 * + message_type="option", message_value="ascii_mode" 385 * + message_type="option", message_value="!ascii_mode" 386 * - on deployment: 387 * + session_id = 0, message_type="deploy", message_value="start" 388 * + session_id = 0, message_type="deploy", message_value="success" 389 * + session_id = 0, message_type="deploy", message_value="failure" 390 * 391 * handler will be called with context_object as the first parameter 392 * every time an event occurs in librime, until RimeFinalize() is called. 393 * when handler is NULL, notification is disabled. 394 */ 395 void (*set_notification_handler)(RimeNotificationHandler handler, 396 void* context_object); 397 398 // entry and exit 399 400 void (*initialize)(RimeTraits *traits); 401 void (*finalize)(); 402 403 Bool (*start_maintenance)(Bool full_check); 404 Bool (*is_maintenance_mode)(); 405 void (*join_maintenance_thread)(); 406 407 // deployment 408 409 void (*deployer_initialize)(RimeTraits *traits); 410 Bool (*prebuild)(); 411 Bool (*deploy)(); 412 Bool (*deploy_schema)(const char *schema_file); 413 Bool (*deploy_config_file)(const char *file_name, const char *version_key); 414 415 Bool (*sync_user_data)(); 416 417 // session management 418 419 RimeSessionId (*create_session)(); 420 Bool (*find_session)(RimeSessionId session_id); 421 Bool (*destroy_session)(RimeSessionId session_id); 422 void (*cleanup_stale_sessions)(); 423 void (*cleanup_all_sessions)(); 424 425 // input 426 427 Bool (*process_key)(RimeSessionId session_id, int keycode, int mask); 428 // return True if there is unread commit text 429 Bool (*commit_composition)(RimeSessionId session_id); 430 void (*clear_composition)(RimeSessionId session_id); 431 432 // output 433 434 Bool (*get_commit)(RimeSessionId session_id, RimeCommit* commit); 435 Bool (*free_commit)(RimeCommit* commit); 436 Bool (*get_context)(RimeSessionId session_id, RimeContext* context); 437 Bool (*free_context)(RimeContext* ctx); 438 Bool (*get_status)(RimeSessionId session_id, RimeStatus* status); 439 Bool (*free_status)(RimeStatus* status); 440 441 // runtime options 442 443 void (*set_option)(RimeSessionId session_id, const char* option, Bool value); 444 Bool (*get_option)(RimeSessionId session_id, const char* option); 445 446 void (*set_property)(RimeSessionId session_id, const char* prop, const char* value); 447 Bool (*get_property)(RimeSessionId session_id, const char* prop, char* value, size_t buffer_size); 448 449 Bool (*get_schema_list)(RimeSchemaList* schema_list); 450 void (*free_schema_list)(RimeSchemaList* schema_list); 451 452 Bool (*get_current_schema)(RimeSessionId session_id, char* schema_id, size_t buffer_size); 453 Bool (*select_schema)(RimeSessionId session_id, const char* schema_id); 454 455 // configuration 456 457 Bool (*schema_open)(const char *schema_id, RimeConfig* config); 458 Bool (*config_open)(const char *config_id, RimeConfig* config); 459 Bool (*config_close)(RimeConfig *config); 460 Bool (*config_get_bool)(RimeConfig *config, const char *key, Bool *value); 461 Bool (*config_get_int)(RimeConfig *config, const char *key, int *value); 462 Bool (*config_get_double)(RimeConfig *config, const char *key, double *value); 463 Bool (*config_get_string)(RimeConfig *config, const char *key, 464 char *value, size_t buffer_size); 465 const char* (*config_get_cstring)(RimeConfig *config, const char *key); 466 Bool (*config_update_signature)(RimeConfig* config, const char* signer); 467 Bool (*config_begin_map)(RimeConfigIterator* iterator, RimeConfig* config, const char* key); 468 Bool (*config_next)(RimeConfigIterator* iterator); 469 void (*config_end)(RimeConfigIterator* iterator); 470 471 // testing 472 473 Bool (*simulate_key_sequence)(RimeSessionId session_id, const char *key_sequence); 474 475 // module 476 477 Bool (*register_module)(RimeModule* module); 478 RimeModule* (*find_module)(const char* module_name); 479 480 Bool (*run_task)(const char* task_name); 481 const char* (*get_shared_data_dir)(); 482 const char* (*get_user_data_dir)(); 483 const char* (*get_sync_dir)(); 484 const char* (*get_user_id)(); 485 void (*get_user_data_sync_dir)(char* dir, size_t buffer_size); 486 487 //! initialize an empty config object 488 /*! 489 * should call config_close() to free the object 490 */ 491 Bool (*config_init)(RimeConfig* config); 492 //! deserialize config from a yaml string 493 Bool (*config_load_string)(RimeConfig* config, const char* yaml); 494 495 // configuration: setters 496 Bool (*config_set_bool)(RimeConfig *config, const char *key, Bool value); 497 Bool (*config_set_int)(RimeConfig *config, const char *key, int value); 498 Bool (*config_set_double)(RimeConfig *config, const char *key, double value); 499 Bool (*config_set_string)(RimeConfig *config, const char *key, const char *value); 500 501 // configuration: manipulating complex structures 502 Bool (*config_get_item)(RimeConfig* config, const char* key, RimeConfig* value); 503 Bool (*config_set_item)(RimeConfig* config, const char* key, RimeConfig* value); 504 Bool (*config_clear)(RimeConfig* config, const char* key); 505 Bool (*config_create_list)(RimeConfig* config, const char* key); 506 Bool (*config_create_map)(RimeConfig* config, const char* key); 507 size_t (*config_list_size)(RimeConfig* config, const char* key); 508 Bool (*config_begin_list)(RimeConfigIterator* iterator, RimeConfig* config, const char* key); 509 510 //! get raw input 511 /*! 512 * NULL is returned if session does not exist. 513 * the returned pointer to input string will become invalid upon editing. 514 */ 515 const char* (*get_input)(RimeSessionId session_id); 516 517 //! caret posistion in terms of raw input 518 size_t (*get_caret_pos)(RimeSessionId session_id); 519 520 //! select a candidate at the given index in candidate list. 521 Bool (*select_candidate)(RimeSessionId session_id, size_t index); 522 523 //! get the version of librime 524 const char* (*get_version)(); 525 526 //! set caret posistion in terms of raw input 527 void (*set_caret_pos)(RimeSessionId session_id, size_t caret_pos); 528 529 //! select a candidate from current page. 530 Bool (*select_candidate_on_current_page)(RimeSessionId session_id, size_t index); 531 532 //! access candidate list. 533 Bool (*candidate_list_begin)(RimeSessionId session_id, RimeCandidateListIterator* iterator); 534 Bool (*candidate_list_next)(RimeCandidateListIterator* iterator); 535 void (*candidate_list_end)(RimeCandidateListIterator* iterator); 536 537 //! access config files in user data directory, eg. user.yaml and installation.yaml 538 Bool (*user_config_open)(const char *config_id, RimeConfig* config); 539 540 Bool (*candidate_list_from_index)(RimeSessionId session_id, 541 RimeCandidateListIterator* iterator, 542 int index); 543 544 //! prebuilt data directory. 545 const char* (*get_prebuilt_data_dir)(); 546 //! staging directory, stores data files deployed to a Rime client. 547 const char* (*get_staging_dir)(); 548 549 //! capnproto API. 550 void (*commit_proto)(RimeSessionId session_id, RIME_PROTO_BUILDER* commit_builder); 551 void (*context_proto)(RimeSessionId session_id, RIME_PROTO_BUILDER* context_builder); 552 void (*status_proto)(RimeSessionId session_id, RIME_PROTO_BUILDER* status_builder); 553 } RimeApi; 554 555 //! API entry 556 /*! 557 * Acquire the version controlled RimeApi structure. 558 */ 559 RIME_API RimeApi* rime_get_api(); 560 561 //! Clients should test if an api function is available in the current version before calling it. 562 #define RIME_API_AVAILABLE(api, func) (RIME_STRUCT_HAS_MEMBER(*(api), (api)->func) && (api)->func) 563 564 // Initializer for MSVC and GCC. 565 // 2010 Joe Lowe. Released into the public domain. 566 #if defined(__GNUC__) 567 #define RIME_MODULE_INITIALIZER(f) \ 568 static void f(void) __attribute__((constructor)); \ 569 static void f(void) 570 #elif defined(_MSC_VER) 571 #pragma section(".CRT$XCU",read) 572 #define RIME_MODULE_INITIALIZER(f) \ 573 static void __cdecl f(void); \ 574 __declspec(allocate(".CRT$XCU")) void (__cdecl*f##_)(void) = f; \ 575 static void __cdecl f(void) 576 #endif 577 578 /*! 579 * Automatically register a rime module when the library is loaded. 580 * Clients should define functions called rime_<module_name>_initialize(), 581 * and rime_<module_name>_finalize(). 582 * \sa core_module.cc for an example. 583 */ 584 #define RIME_REGISTER_MODULE(name) \ 585 void rime_require_module_##name() {} \ 586 RIME_MODULE_INITIALIZER(rime_register_module_##name) { \ 587 static RimeModule module = {0}; \ 588 if (!module.data_size) { \ 589 RIME_STRUCT_INIT(RimeModule, module); \ 590 module.module_name = #name; \ 591 module.initialize = rime_##name##_initialize; \ 592 module.finalize = rime_##name##_finalize; \ 593 } \ 594 rime_get_api()->register_module(&module); \ 595 } 596 597 /*! 598 * Customize the module by assigning additional functions, eg. module->get_api. 599 */ 600 #define RIME_REGISTER_CUSTOM_MODULE(name) \ 601 void rime_require_module_##name() {} \ 602 static void rime_customize_module_##name(RimeModule* module); \ 603 RIME_MODULE_INITIALIZER(rime_register_module_##name) { \ 604 static RimeModule module = {0}; \ 605 if (!module.data_size) { \ 606 RIME_STRUCT_INIT(RimeModule, module); \ 607 module.module_name = #name; \ 608 module.initialize = rime_##name##_initialize; \ 609 module.finalize = rime_##name##_finalize; \ 610 rime_customize_module_##name(&module); \ 611 } \ 612 rime_get_api()->register_module(&module); \ 613 } \ 614 static void rime_customize_module_##name(RimeModule* module) 615 616 /*! 617 * Defines a constant for a list of module names. 618 */ 619 #define RIME_MODULE_LIST(var, ...) \ 620 const char* var[] = { \ 621 __VA_ARGS__, NULL \ 622 } \ 623 624 /*! 625 * Register a phony module which, when loaded, will load a list of modules. 626 * \sa setup.cc for an example. 627 */ 628 #define RIME_REGISTER_MODULE_GROUP(name, ...) \ 629 static RIME_MODULE_LIST(rime_##name##_module_group, __VA_ARGS__); \ 630 static void rime_##name##_initialize() { \ 631 rime::LoadModules(rime_##name##_module_group); \ 632 } \ 633 static void rime_##name##_finalize() { \ 634 } \ 635 RIME_REGISTER_MODULE(name) 636 637 #ifdef __cplusplus 638 } 639 #endif 640 641 #endif // RIME_API_H_ 642