Chromium Embedded Framework(CEF3) wrapper.
nimCEF consist of two parts:
-
First part: nimCEF is a thin wrapper for CEF3 written in Nim. Basically, nimCEF is CEF3 C API translated to Nim, therefore if you know how to use CEF3 C API, using First part is not much different.
-
Second part: Convenience layer added on top of C style API to ease the development in Nim style. Nim native datatypes will be used whenever possible. And many of the ref-count related issues already handled for you. The Convenience Layer heavily utilizing Nim macros to generate consistent and efficient wrapper.
No | Items | Win32 | Linux32 | Win64 | Linux64 | Mac64 | Nim Ver |
---|---|---|---|---|---|---|---|
1 | CEF3 C API | complete | complete | complete | complete | 90% | 0.14.2 |
2 | CEF3 C API example | yes | no | yes | no | no | 0.14.2 |
3 | Simple Client Example | yes | yes | yes | yes | no | 0.14.2 |
4 | CefClient Example | 20% | no | 20% | no | no | 0.14.2 |
5 | Convenience Layer | complete | complete | complete | complete | 60% | 0.14.2 |
Macro Name | Call Count | Description |
---|---|---|
wrapAPI | 116 | wrapper for cef object with ref count |
wrapCall | 811 | wrapper for ordinary cef methods |
wrapProc | 98 | wrapper for free proc |
wrapCallback | 52 | wrapper for cef callback object |
wrapMethod | 209 | wrapper for callback object's methods |
From your console command prompt type:
To build all examples:
nim e build.nims
To build individual example:
nim c test_client
nim c test_api
nim c test_parser
etc
- make sure your cef library binary bitness is compatible with your executable
- download prebuilt binary from here, or built from the source yourself
- place your binaries according to this layout
- run your executable
- First import your needed files, notably nc_util and nc_types
import nc_context_menu_handler, nc_browser, nc_types
import nc_util, nc_context_menu_params, nc_menu_model
- Then define your own handler type inherited from e.g. NCContextMenuHandler, but this is optional, you can use NCContextMenuHandler directly without inheriting it.
type
MyHandler = ref object of NCContextMenuHandler
- Next step use handlerImpl, with two parameters,
- first param is the typeDesc we already defined or the NCxxx type
- the second param is a list of your procs. The 'self' must have the same type with the first param
- the second param is optional, and default implementation will be used if no procs are defined
handlerImpl(MyHandler):
proc onBeforeContextMenu(self: MyHandler, browser: NCBrowser,
frame: NCFrame, params: NCContextMenuParams, model: NCMenuModel) =
discard
proc onContextMenuCommand(self: MyHandler, browser: NCBrowser,
frame: NCFrame, params: NCContextMenuParams, command_id: cef_menu_id,
event_flags: cef_event_flags): int =
discard
- if you want to create an instance of your handler, just call ncCreate with single param from handlerImpl first param
var cmhandler_inst = MyHandler.ncCreate()
If you use NCContextMenuModel and NCContextMenuHandler to create user defined menu entry, you also need to provide user defined menu id. You can simply use USER_MENU_ID with single integer parameter
const
MY_MENU_ID = USER_MENU_ID(1)
MY_QUIT_ID = USER_MENU_ID(2)
MY_PLUGIN_ID = USER_MENU_ID(3)
or better yet, you can use MENU_ID macro to guarantee you always get unique id for each identifier
MENU_ID:
MY_MENU_ID
MY_QUIT_ID
MY_PLUGIN_ID
- You can use handlerImpl to implement your own callback object derived from NCTask
- or you can use ncBindTask to help you do that in a much simpler way
proc continueOpenOnIOThread(fileId: int) =
NC_REQUIRE_IO_THREAD()
#do something in IO thread
proc openMyFile(fileId: int) =
# first param is the task's name
# second param is a proc that will be executed in target thread
ncBindTask(continueOpenTask, continueOpenOnIOThread)
discard ncPostTask(TID_IO, continueOpenTask(fileId))
How to resolve overloaded proc? You can give param to target proc to help compiler decide which one will be used
proc readFile(fileId: int) =
NC_REQUIRE_IO_THREAD()
#do something
proc readFile(fileId: int, mode: int) =
NC_REQUIRE_IO_THREAD()
#do something
proc readMyFile(fileId: int, mode: int) =
# help the compiler to choose between overloaded procs
ncBindTask(readMyFileTask, readFile(fileId, mode))
discard ncPostTask(TID_IO, readMyFileTask(fileId, mode))
You must be very careful when you post object across threads boundary for the reason below.
Nim memory model and C/C++ memory model is different. In C/C++, object can be freely posted to another thread via CefPostTask. While in Nim, ncPostTask should be used carefully. Every Nim thread has their own heap and GC. if you must post object across threads, you must create object in global heap, it means you must manually manage the object lifetime and you cannot use string or seq as usual(they must be manually marked by GC_ref/GC_unref). If you don't post object across threads boundary, you can call setupForeignThreadGC() before you create any object and use them as usual inside that thread only.