├── .gitignore ├── LICENSE ├── README.md ├── TODO.md ├── app.go ├── bytes.go ├── cgo-shared.go ├── cgo-static.go ├── cgo.go ├── cmd ├── gml-copy-dlls │ ├── .gitignore │ └── main.go └── gml │ ├── .gitignore │ ├── build.go │ ├── docker.go │ ├── main.go │ └── version.go ├── docker ├── Makefile ├── _unused │ ├── TODO.md │ ├── windows_32_static │ │ ├── Dockerfile │ │ └── Dockerfile.in │ ├── windows_64_static │ │ ├── Dockerfile │ │ └── Dockerfile.in │ └── windows_wine │ │ ├── Dockerfile │ │ ├── msys2-trusted │ │ ├── msys2.gpg │ │ ├── pacman-msys2.conf │ │ └── pacman.conf ├── android │ └── Dockerfile ├── common │ ├── base │ ├── deploy-dlls.sh │ ├── entrypoint.sh │ ├── windows │ └── windows_shared ├── generate.go ├── linux │ ├── Dockerfile │ └── Dockerfile.in ├── windows │ ├── Dockerfile │ └── Dockerfile.in ├── windows_32_shared │ ├── Dockerfile │ └── Dockerfile.in └── windows_64_shared │ ├── Dockerfile │ └── Dockerfile.in ├── error.go ├── errors.go ├── gml.go ├── go.mod ├── go.sum ├── image.go ├── imageitem.go ├── imageprovider.go ├── internal ├── binding │ ├── headers │ │ ├── gml.h │ │ ├── gml_app.h │ │ ├── gml_bytes.h │ │ ├── gml_cpp.h │ │ ├── gml_error.h │ │ ├── gml_global.h │ │ ├── gml_image.h │ │ ├── gml_image_item.h │ │ ├── gml_image_provider.h │ │ ├── gml_includes.h │ │ ├── gml_list_model.h │ │ ├── gml_object.h │ │ └── gml_variant.h │ └── sources │ │ ├── gml_app.cpp │ │ ├── gml_app.h │ │ ├── gml_bytes.cpp │ │ ├── gml_error.cpp │ │ ├── gml_error.h │ │ ├── gml_global.cpp │ │ ├── gml_image.cpp │ │ ├── gml_image_item.cpp │ │ ├── gml_image_item.h │ │ ├── gml_image_provider.cpp │ │ ├── gml_image_provider.h │ │ ├── gml_includes.h │ │ ├── gml_list_model.cpp │ │ ├── gml_list_model.h │ │ └── gml_variant.cpp ├── build │ ├── build.go │ ├── context.go │ ├── generate.go │ ├── generate_parse.go │ ├── qtproject.go │ ├── resources.go │ ├── template_c.go │ ├── template_cpp.go │ ├── template_funcs.go │ └── template_go.go ├── docker │ ├── context.go │ └── docker.go ├── json │ └── json.go └── utils │ ├── path.go │ ├── print.go │ ├── utils.go │ ├── utils_test.go │ ├── utils_unix.go │ └── utils_windows.go ├── listmodel.go ├── object.go ├── pointer └── pointer.go ├── utils.go └── variant.go /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore backups of editors 2 | *~ 3 | 4 | # ignore project files of IDEs 5 | .idea/ 6 | .vscode/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Roland Singer [roland.singer@deserbit.com] 4 | Copyright (c) 2018 Sebastian Borchers [sebastian@deserbit.com] 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go QML Bindings 2 | 3 | ## Pre-Alpha 4 | 5 | Please note that this project is in pre-alpha phase. Documentation is missing and some bugs need to be fixed. Right now, we do not recommend anyone to use anything you find here ;) 6 | 7 | ## Install 8 | 9 | ``` 10 | go get -u github.com/desertbit/gml/cmd/gml 11 | ``` 12 | 13 | ## Samples 14 | 15 | See the **[GML Samples Repo](https://github.com/desertbit/gml-samples)**. 16 | 17 | ## Docker Build Containers 18 | 19 | The docker image url is: `desertbit/gml` 20 | **[DockerHub Link](https://hub.docker.com/r/desertbit/gml)** 21 | 22 | | Image Tag | Host OS | Target OS | Qt Link Type | Note | 23 | |:------------------|:-------------|:---------------|:-------------|-----------------------| 24 | | linux | Linux x86_64 | Linux x86_64 | dynamic | | 25 | | windows_32_shared | Linux x86_64 | Windows i686 | dynamic | | 26 | | windows_64_shared | Linux x86_64 | Windows x86_64 | dynamic | | 27 | | android | Linux x86_64 | Android | - | Not usable - See TODO | 28 | 29 | ## Build Tags 30 | 31 | - static: run pkg-config with the static flag. Required for static Qt builds. 32 | 33 | ## Debugging 34 | 35 | To debug windows problems, use the [MSYS2](https://www.msys2.org/) console. 36 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | - Implement hot reloading 3 | 4 | ## Go 5 | - remove the app completly. 6 | 7 | ## Code Gen 8 | - use the direct type instead of interface{} -> properties don't return a QVariant. 9 | - test variant as return type and in functions 10 | - test a qmodel as properties 11 | - package names must be unique if code generation is applied to that package. Fix this or prevent this as compiler check. 12 | - test code generation for keep alives 13 | 14 | ## C++ Binding 15 | - add qml support for int64 16 | - don't use C.CString instead use the direct byte buffer? (UTF-8 encoding?) 17 | - use everyhwere constData instead of data (strings). 18 | 19 | ## Docker 20 | - deploy-dlls.sh adds common required Qt plugins. This should be configurable instead? 21 | - Finish the windows static build containers. See the TODO in the docker folder. 22 | - Finish the Android docker containers. 23 | 24 | - vor dem bauen committen und taggen, damit das bauen funktioniert 25 | - erst windows bauen und hochladen, bevor 32/64_shared -------------------------------------------------------------------------------- /bytes.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | // #include 31 | import "C" 32 | import ( 33 | "fmt" 34 | "unsafe" 35 | ) 36 | 37 | type bytes struct { 38 | ptr C.gml_bytes 39 | } 40 | 41 | func newBytes() (b *bytes) { 42 | b = &bytes{ 43 | ptr: C.gml_bytes_new(), 44 | } 45 | 46 | // This should never happen. Signalizes a fatal error. 47 | if b.ptr == nil { 48 | panic(fmt.Errorf("failed to create gml bytes: C pointer is nil")) 49 | } 50 | return 51 | } 52 | 53 | func (b *bytes) Free() { 54 | C.gml_bytes_free(b.ptr) 55 | } 56 | 57 | func (b *bytes) Bytes() []byte { 58 | var size C.int 59 | buf := C.gml_bytes_get(b.ptr, &size) 60 | if size <= 0 { 61 | return nil 62 | } 63 | return C.GoBytes(unsafe.Pointer(buf), size) 64 | } 65 | 66 | func (b *bytes) String() []byte { 67 | buf := b.Bytes() 68 | // Remove if null-terminated. 69 | if len(buf) > 0 && buf[len(buf)-1] == 0 { 70 | buf = buf[:len(buf)-1] 71 | } 72 | return buf 73 | } 74 | -------------------------------------------------------------------------------- /cgo-shared.go: -------------------------------------------------------------------------------- 1 | // +build !static 2 | 3 | /* 4 | * GML - Go QML 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Copyright (c) 2019 Roland Singer 9 | * Copyright (c) 2019 Sebastian Borchers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | */ 29 | 30 | package gml 31 | 32 | // #cgo pkg-config: Qt5Core Qt5Qml Qt5Quick Qt5Widgets 33 | import "C" 34 | -------------------------------------------------------------------------------- /cgo-static.go: -------------------------------------------------------------------------------- 1 | // +build static 2 | 3 | /* 4 | * GML - Go QML 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Copyright (c) 2019 Roland Singer 9 | * Copyright (c) 2019 Sebastian Borchers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | */ 29 | 30 | package gml 31 | 32 | // #cgo pkg-config: --static Qt5Core Qt5Qml Qt5Quick Qt5Widgets 33 | import "C" 34 | -------------------------------------------------------------------------------- /cgo.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | // #cgo CFLAGS: -I${SRCDIR}/internal/binding/headers 31 | // #cgo LDFLAGS: -lstdc++ 32 | import "C" 33 | -------------------------------------------------------------------------------- /cmd/gml-copy-dlls/.gitignore: -------------------------------------------------------------------------------- 1 | /gml-copy-dlls -------------------------------------------------------------------------------- /cmd/gml-copy-dlls/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package main 29 | 30 | import ( 31 | "flag" 32 | "fmt" 33 | "log" 34 | "os" 35 | "os/exec" 36 | "path/filepath" 37 | "strings" 38 | 39 | "github.com/desertbit/gml/internal/utils" 40 | ) 41 | 42 | var ( 43 | inputBin string 44 | objdumpBin string 45 | destDir string 46 | srcDir string 47 | enforceDirsStr string 48 | enforceDirs []string 49 | 50 | allDeps = make(map[string]string) 51 | deps = make(map[string]string) 52 | ) 53 | 54 | func main() { 55 | err := prepareFlags() 56 | if err != nil { 57 | log.Fatalln(err) 58 | } 59 | 60 | err = prepareAllDeps() 61 | if err != nil { 62 | log.Fatalln(err) 63 | } 64 | 65 | err = findDeps() 66 | if err != nil { 67 | log.Fatalln(err) 68 | } 69 | 70 | err = copyDeps() 71 | if err != nil { 72 | log.Fatalln(err) 73 | } 74 | 75 | err = copyEnforcedDirs() 76 | if err != nil { 77 | log.Fatalln(err) 78 | } 79 | } 80 | 81 | func prepareFlags() (err error) { 82 | flag.StringVar(&inputBin, "input", "", "input binary") 83 | flag.StringVar(&destDir, "dest", "", "destination output directory") 84 | flag.StringVar(&srcDir, "src", "", "source directory (recursively searched)") 85 | flag.StringVar(&enforceDirsStr, "enforce", "", "add additional directories (flat copy; comma separated)") 86 | flag.StringVar(&objdumpBin, "objdump", "objdump", "objdump binary") 87 | flag.Parse() 88 | 89 | // Input Binary. 90 | if inputBin == "" { 91 | return fmt.Errorf("no input binary specified") 92 | } 93 | e, err := utils.Exists(inputBin) 94 | if err != nil { 95 | return 96 | } else if !e { 97 | return fmt.Errorf("input binary does not exists") 98 | } 99 | 100 | // Dest Dir. 101 | destDir, err = filepath.Abs(destDir) 102 | if err != nil { 103 | return 104 | } 105 | err = os.MkdirAll(destDir, 0755) 106 | if err != nil { 107 | return 108 | } 109 | 110 | // Source Dir. 111 | srcDir, err = filepath.Abs(srcDir) 112 | if err != nil { 113 | return 114 | } 115 | e, err = utils.Exists(srcDir) 116 | if err != nil { 117 | return 118 | } else if !e { 119 | return fmt.Errorf("source directory does not exists") 120 | } 121 | 122 | // Enforce dirs. 123 | enforceDirs = strings.Split(enforceDirsStr, ",") 124 | 125 | return 126 | } 127 | 128 | func prepareAllDeps() (err error) { 129 | err = filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error { 130 | if err != nil { 131 | return err 132 | } else if info.IsDir() || !strings.HasSuffix(strings.ToLower(info.Name()), ".dll") { 133 | return nil 134 | } 135 | dep := strings.ToLower(info.Name()) 136 | allDeps[dep] = path 137 | return nil 138 | }) 139 | return 140 | } 141 | 142 | func findDeps() (err error) { 143 | inputs := []string{inputBin} 144 | 145 | for _, d := range enforceDirs { 146 | err = filepath.Walk(d, func(path string, info os.FileInfo, err error) error { 147 | if err != nil { 148 | return err 149 | } else if info.IsDir() || !strings.HasSuffix(strings.ToLower(info.Name()), ".dll") { 150 | return nil 151 | } 152 | inputs = append(inputs, path) 153 | return nil 154 | }) 155 | if err != nil { 156 | return 157 | } 158 | } 159 | 160 | for _, input := range inputs { 161 | err = findRecursiveDeps(input) 162 | if err != nil { 163 | return 164 | } 165 | } 166 | return 167 | } 168 | 169 | func findRecursiveDeps(path string) (err error) { 170 | out, err := exec.Command(objdumpBin, "-p", path).Output() 171 | if err != nil { 172 | return 173 | } 174 | 175 | lines := strings.Split(string(out), "\n") 176 | for _, line := range lines { 177 | line = strings.TrimSpace(line) 178 | if !strings.HasPrefix(line, "DLL Name:") { 179 | continue 180 | } 181 | 182 | line = strings.ToLower(strings.TrimSpace(strings.TrimPrefix(line, "DLL Name:"))) 183 | if _, ok := deps[line]; ok { 184 | continue 185 | } 186 | 187 | depPath := allDeps[line] 188 | deps[line] = depPath 189 | 190 | if depPath == "" { 191 | continue 192 | } 193 | 194 | err = findRecursiveDeps(depPath) 195 | if err != nil { 196 | return 197 | } 198 | } 199 | 200 | return 201 | } 202 | 203 | func copyDeps() (err error) { 204 | for _, path := range deps { 205 | if path == "" { 206 | continue 207 | } 208 | 209 | err = utils.CopyFile(path, filepath.Join(destDir, filepath.Base(path)), false) 210 | if err != nil { 211 | return 212 | } 213 | } 214 | return 215 | } 216 | 217 | func copyEnforcedDirs() error { 218 | for _, src := range enforceDirs { 219 | dest := filepath.Join(destDir, filepath.Base(src)) 220 | e, err := utils.Exists(dest) 221 | if err != nil { 222 | return err 223 | } else if e { 224 | err = os.RemoveAll(dest) 225 | if err != nil { 226 | return err 227 | } 228 | } 229 | 230 | err = utils.CopyDir(src, dest, false) 231 | if err != nil { 232 | return err 233 | } 234 | } 235 | return nil 236 | } 237 | -------------------------------------------------------------------------------- /cmd/gml/.gitignore: -------------------------------------------------------------------------------- 1 | /gml -------------------------------------------------------------------------------- /cmd/gml/build.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package main 29 | 30 | import ( 31 | "github.com/desertbit/gml/internal/build" 32 | "github.com/desertbit/gml/internal/docker" 33 | "github.com/desertbit/grumble" 34 | ) 35 | 36 | func init() { 37 | BuildCmd := &grumble.Command{ 38 | Name: "build", 39 | Help: "build a gml project", 40 | Flags: func(f *grumble.Flags) { 41 | f.Bool("c", "clean", false, "clean build files first") 42 | f.BoolL("no-strip", false, "don't strip the final binary") 43 | f.BoolL("debug", false, "build a debug binary (disables strip)") 44 | f.BoolL("race", false, "enable data race detection") 45 | f.StringL("buildvcs", "auto", "value of go build -buildvcs flag") 46 | f.String("r", "root-dir", "./", "root directory containing the go.mod file") 47 | f.String("s", "source-dir", "./", "source directory, relative to root-directory") 48 | f.String("b", "build-dir", "build", "build directory, relative to root-directory") 49 | f.String("d", "dest-dir", "./", "destination directorty") 50 | f.String("t", "tags", "", "go build tags") 51 | f.String("m", "qt-modules", "", "comma separated list of qt modules added to the project") 52 | }, 53 | Run: runBuild, 54 | } 55 | App.AddCommand(BuildCmd) 56 | 57 | BuildCmd.AddCommand(&grumble.Command{ 58 | Name: "docker", 59 | Help: "build a gml project with docker", 60 | Flags: func(f *grumble.Flags) { 61 | // TODO: Copied from parent command because of grumble change with flag handling 62 | f.Bool("c", "clean", false, "clean build files first") 63 | f.BoolL("no-strip", false, "don't strip the final binary") 64 | f.BoolL("debug", false, "build a debug binary (disables strip)") 65 | f.BoolL("race", false, "enable data race detection") 66 | f.StringL("buildvcs", "auto", "value of go build -buildvcs flag") 67 | f.String("r", "root-dir", "./", "root directory containing the go.mod file") 68 | f.String("s", "source-dir", "./", "source directory, relative to root-directory") 69 | f.String("b", "build-dir", "build", "build directory, relative to root-directory") 70 | f.String("d", "dest-dir", "./", "destination directory") 71 | f.String("t", "tags", "", "go build tags") 72 | f.String("m", "qt-modules", "", "comma separated list of qt modules added to the project") 73 | 74 | f.BoolL("custom", false, "use a custom docker image") 75 | f.StringL("args", "", "pass additional arguments to docker") 76 | }, 77 | Args: func(a *grumble.Args) { 78 | a.String("container", "the name of the container used for building") 79 | }, 80 | Run: runBuildDocker, 81 | }) 82 | } 83 | 84 | func runBuild(c *grumble.Context) error { 85 | return build.Build( 86 | c.Flags.String("root-dir"), 87 | c.Flags.String("source-dir"), 88 | c.Flags.String("build-dir"), 89 | c.Flags.String("dest-dir"), 90 | c.Flags.String("qt-modules"), 91 | c.Flags.Bool("clean"), 92 | c.Flags.Bool("no-strip"), 93 | c.Flags.Bool("debug"), 94 | c.Flags.Bool("race"), 95 | c.Flags.String("tags"), 96 | c.Flags.String("buildvcs"), 97 | ) 98 | } 99 | 100 | func runBuildDocker(c *grumble.Context) error { 101 | return docker.Build( 102 | c.Args.String("container"), 103 | c.Flags.String("root-dir"), 104 | c.Flags.String("source-dir"), 105 | c.Flags.String("build-dir"), 106 | c.Flags.String("dest-dir"), 107 | c.Flags.String("qt-modules"), 108 | c.Flags.Bool("clean"), 109 | c.Flags.Bool("no-strip"), 110 | c.Flags.Bool("debug"), 111 | c.Flags.Bool("race"), 112 | c.Flags.Bool("custom"), 113 | c.Flags.String("tags"), 114 | c.Flags.String("args"), 115 | c.Flags.String("buildvcs"), 116 | ) 117 | } 118 | -------------------------------------------------------------------------------- /cmd/gml/docker.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package main 29 | 30 | import ( 31 | "fmt" 32 | 33 | "github.com/desertbit/gml/internal/docker" 34 | "github.com/desertbit/grumble" 35 | ) 36 | 37 | func init() { 38 | DockerCmd := &grumble.Command{ 39 | Name: "docker", 40 | Help: "manage gml docker containers", 41 | Run: runDocker, 42 | } 43 | App.AddCommand(DockerCmd) 44 | 45 | DockerCmd.AddCommand(&grumble.Command{ 46 | Name: "pull", 47 | Help: "pull latest docker container", 48 | Args: func(a *grumble.Args) { 49 | a.String("container", "the name of the container to pull") 50 | }, 51 | Run: runDockerPull, 52 | }) 53 | } 54 | 55 | func runDocker(c *grumble.Context) error { 56 | containers := docker.Containers() 57 | for _, c := range containers { 58 | fmt.Println(c) 59 | } 60 | return nil 61 | } 62 | 63 | func runDockerPull(c *grumble.Context) error { 64 | if len(c.Args) == 0 { 65 | return fmt.Errorf("invalid args: pass a docker container") 66 | } else if len(c.Args) > 1 { 67 | return fmt.Errorf("too many args") 68 | } 69 | 70 | return docker.Pull(c.Args.String("container")) 71 | } 72 | -------------------------------------------------------------------------------- /cmd/gml/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package main 29 | 30 | import ( 31 | "fmt" 32 | "os" 33 | 34 | "github.com/desertbit/gml/internal/utils" 35 | "github.com/desertbit/grumble" 36 | "github.com/fatih/color" 37 | ) 38 | 39 | var App = grumble.New(&grumble.Config{ 40 | Name: "gml", 41 | Description: "go qml tool", 42 | PromptColor: color.New(color.FgGreen, color.Bold), 43 | 44 | Flags: func(f *grumble.Flags) { 45 | f.Bool("v", "verbose", false, "verbose mode") 46 | }, 47 | }) 48 | 49 | func init() { 50 | App.SetPrintASCIILogo(func(a *grumble.App) { 51 | fmt.Println(` ___ __ __ __ `) 52 | fmt.Println(` / __)( \/ )( ) `) 53 | fmt.Println(`( (_-. ) ( )(__ `) 54 | fmt.Println(` \___/(_/\/\_)(____)`) 55 | fmt.Println() 56 | }) 57 | 58 | App.OnInit(func(a *grumble.App, f grumble.FlagMap) error { 59 | utils.Verbose = f.Bool("verbose") 60 | return nil 61 | }) 62 | } 63 | 64 | func main() { 65 | err := App.Run() 66 | if err != nil { 67 | fmt.Println(err) 68 | os.Exit(1) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /cmd/gml/version.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package main 29 | 30 | import ( 31 | "fmt" 32 | 33 | "github.com/desertbit/grumble" 34 | ) 35 | 36 | const Version = "v0.0.31" 37 | 38 | func init() { 39 | versionCmd := &grumble.Command{ 40 | Name: "version", 41 | Help: "print the version of gml", 42 | Run: runVersion, 43 | } 44 | App.AddCommand(versionCmd) 45 | } 46 | 47 | func runVersion(c *grumble.Context) error { 48 | fmt.Printf("GML %s\n", Version) 49 | return nil 50 | } 51 | -------------------------------------------------------------------------------- /docker/Makefile: -------------------------------------------------------------------------------- 1 | CROSSBUILD_IMAGES = linux android windows windows_64_shared windows_32_shared 2 | 3 | $(CROSSBUILD_IMAGES): %: generate 4 | docker build --pull --no-cache ./ -f $@/Dockerfile -t desertbit/gml:$@ 5 | 6 | generate: 7 | go run generate.go 8 | 9 | .PHONY: $(CROSSBUILD_IMAGES) -------------------------------------------------------------------------------- /docker/_unused/TODO.md: -------------------------------------------------------------------------------- 1 | # Docker TODO 2 | 3 | ## Windows Static Builds 4 | 5 | ```cpp 6 | Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) // TODO: only if windows build. 7 | Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin) 8 | Q_IMPORT_PLUGIN(QGifPlugin) 9 | Q_IMPORT_PLUGIN(QICOPlugin) 10 | Q_IMPORT_PLUGIN(QJpegPlugin) 11 | Q_IMPORT_PLUGIN(QGenericEnginePlugin) 12 | Q_IMPORT_PLUGIN(QtQuick2Plugin) 13 | Q_IMPORT_PLUGIN(QtQuickLayoutsPlugin) 14 | Q_IMPORT_PLUGIN(QtQuickControls2Plugin) 15 | // ... 16 | ``` 17 | 18 | Generate this dynamically and prepend it to the docker ENV: 19 | 20 | ``` 21 | // #cgo LDFLAGS: -lstdc++ /mxe/usr/x86_64-w64-mingw32.static/qt5/qml/QtQuick/Controls.2/libqtquickcontrols2plugin.a /mxe/usr/x86_64-w64-mingw32.static/qt5/qml/QtQuick.2/libqtquick2plugin.a /mxe/usr/x86_64-w64-mingw32.static/qt5/qml/QtQuick/Layouts/libqquicklayoutsplugin.a -L/mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/platforms -lqminimal -lqwindows -ldwmapi -lwinspool -lwtsapi32 -lQt5EventDispatcherSupport -L/mxe/usr/x86_64-w64-mingw32.static/lib/../lib -lQt5FontDatabaseSupport -lQt5ThemeSupport -lQt5AccessibilitySupport -lQt5WindowsUIAutomationSupport -lQt5Gui -lharfbuzz -lcairo -lgobject-2.0 -lfontconfig -lfreetype -lm -lusp10 -lmsimg32 -lpixman-1 -lffi -lexpat -lbz2 -lpng16 -lharfbuzz_too -lfreetype_too -lglib-2.0 -lshlwapi -lpcre -lintl -liconv -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lopengl32 -lQt5Core -lmpr -lnetapi32 -luserenv -lversion -lws2_32 -lkernel32 -luser32 -lshell32 -luuid -lole32 -ladvapi32 -lwinmm -lz -lpcre2-16 -lopengl32 -L/mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/platforms /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/platforms/libqminimal.a -L/mxe/usr/x86_64-w64-mingw32.static/qt5/lib /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libQt5EventDispatcherSupport.a -L/mxe/usr/x86_64-w64-mingw32.static/lib /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libQt5FontDatabaseSupport.a -L/mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/imageformats /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/imageformats/libqgif.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/imageformats/libqico.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/imageformats/libqjpeg.a -ljpeg -L/mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_debugger.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_inspector.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_local.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_messages.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_native.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_nativedebugger.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_preview.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_profiler.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_quickprofiler.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_server.a /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libQt5PacketProtocol.a /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/qmltooling/libqmldbg_tcp.a -L/mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/bearer /mxe/usr/x86_64-w64-mingw32.static/qt5/plugins/bearer/libqgenericbearer.a /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libQt5Quick.a /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libQt5Gui.a -lharfbuzz -lcairo -lgobject-2.0 -lfontconfig -lfreetype -lm -lusp10 -lmsimg32 -lpixman-1 -lffi -lexpat -lbz2 -lpng16 -lharfbuzz_too -lfreetype_too -lglib-2.0 -lshlwapi -lpcre -lintl -liconv -lcomdlg32 -loleaut32 -limm32 -lopengl32 /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libQt5Qml.a /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libQt5Network.a -ldnsapi -liphlpapi -lssl -lcrypto -lgdi32 -lcrypt32 /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libQt5Core.a -lmpr -lnetapi32 -luserenv -lversion -lws2_32 -lkernel32 -luser32 -lshell32 -luuid -lole32 -ladvapi32 -lwinmm -lz -lpcre2-16 -lopengl32 -lmingw32 /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libqtmain.a -L/mxe/usr/x86_64-w64-mingw32.static/qt5/lib /mxe/usr/x86_64-w64-mingw32.static/qt5/lib/libQt5Core.a -lmpr -lnetapi32 -luserenv -lversion -lws2_32 -lkernel32 -luser32 -lshell32 -luuid -lole32 -ladvapi32 -lwinmm -lz -lpcre2-16 22 | ``` -------------------------------------------------------------------------------- /docker/_unused/windows_32_static/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM desertbit/gml:windows 2 | MAINTAINER team@desertbit.com 3 | 4 | ENV CROSS_TRIPLE="i686-w64-mingw32.static" \ 5 | GOOS=windows \ 6 | GOARCH=386 7 | 8 | RUN cd /mxe && \ 9 | export NUM_CORES="$(grep -c processor /proc/cpuinfo)" && \ 10 | make -j${NUM_CORES} MXE_TARGETS="${CROSS_TRIPLE}" qtbase qtquickcontrols qtquickcontrols2 qtimageformats qtlocation 11 | 12 | ENV PATH="/mxe/usr/bin:/mxe/usr/${CROSS_TRIPLE}/qt5/bin:$PATH" \ 13 | PKG_CONFIG="/mxe/usr/bin/${CROSS_TRIPLE}-pkg-config" \ 14 | PKG_CONFIG_PATH="/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig:$PKG_CONFIG_PATH" \ 15 | CC="${CROSS_TRIPLE}-gcc" \ 16 | CXX="${CROSS_TRIPLE}-g++" 17 | 18 | # Patch to include some missing libraries for cgo. Otherwise the linker fails. 19 | RUN sed -i "s|Libs.private:|Libs.private: -lstdc++ |g" "/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig/Qt5Core.pc" 20 | 21 | -------------------------------------------------------------------------------- /docker/_unused/windows_32_static/Dockerfile.in: -------------------------------------------------------------------------------- 1 | FROM desertbit/gml:windows 2 | MAINTAINER team@desertbit.com 3 | 4 | ENV CROSS_TRIPLE="i686-w64-mingw32.static" \ 5 | GOOS=windows \ 6 | GOARCH=386 7 | 8 | #import common/windows 9 | -------------------------------------------------------------------------------- /docker/_unused/windows_64_static/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM desertbit/gml:windows 2 | MAINTAINER team@desertbit.com 3 | 4 | ENV CROSS_TRIPLE="x86_64-w64-mingw32.static" \ 5 | GOOS=windows \ 6 | GOARCH=amd64 7 | 8 | RUN cd /mxe && \ 9 | export NUM_CORES="$(grep -c processor /proc/cpuinfo)" && \ 10 | make -j${NUM_CORES} MXE_TARGETS="${CROSS_TRIPLE}" qtbase qtquickcontrols qtquickcontrols2 qtimageformats qtlocation 11 | 12 | ENV PATH="/mxe/usr/bin:/mxe/usr/${CROSS_TRIPLE}/qt5/bin:$PATH" \ 13 | PKG_CONFIG="/mxe/usr/bin/${CROSS_TRIPLE}-pkg-config" \ 14 | PKG_CONFIG_PATH="/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig:$PKG_CONFIG_PATH" \ 15 | CC="${CROSS_TRIPLE}-gcc" \ 16 | CXX="${CROSS_TRIPLE}-g++" 17 | 18 | # Patch to include some missing libraries for cgo. Otherwise the linker fails. 19 | RUN sed -i "s|Libs.private:|Libs.private: -lstdc++ |g" "/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig/Qt5Core.pc" 20 | 21 | -------------------------------------------------------------------------------- /docker/_unused/windows_64_static/Dockerfile.in: -------------------------------------------------------------------------------- 1 | FROM desertbit/gml:windows 2 | MAINTAINER team@desertbit.com 3 | 4 | ENV CROSS_TRIPLE="x86_64-w64-mingw32.static" \ 5 | GOOS=windows \ 6 | GOARCH=amd64 7 | 8 | #import common/windows 9 | -------------------------------------------------------------------------------- /docker/_unused/windows_wine/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM archlinux/base:latest 2 | MAINTAINER team@desertbit.com 3 | 4 | ENV WINEPATH=C:\\mingw64\\bin;C:\\usr\\bin 5 | ENV WINEPREFIX=/wine 6 | ENV WINEROOT=/wine/drive_c 7 | 8 | RUN mkdir -p ${WINEPREFIX} && \ 9 | mkdir -p ${WINEROOT}/var/lib/pacman 10 | 11 | # Copy our pacman configs. 12 | COPY windows_wine/pacman.conf /etc/pacman.conf 13 | COPY windows_wine/pacman-msys2.conf /etc/pacman-msys2.conf 14 | 15 | # Install dependencies. 16 | RUN pacman-key --init && \ 17 | pacman -Syu --noconfirm \ 18 | sudo \ 19 | git \ 20 | tar \ 21 | xz \ 22 | unzip \ 23 | nano \ 24 | awk \ 25 | wget \ 26 | wine \ 27 | winetricks \ 28 | mpg123 \ 29 | lib32-mpg123 \ 30 | ncurses \ 31 | lib32-ncurses \ 32 | xorg-server-xvfb && \ 33 | pacman -Scc --noconfirm 34 | 35 | # Setup wine. 36 | RUN WINEDLLOVERRIDES="mscoree,mshtml=" xvfb-run wineboot && wineserver -w && \ 37 | xvfb-run winetricks -q vcrun2015 38 | 39 | # Install the msys2 gpg keys. 40 | # https://github.com/Alexpux/MSYS2-keyring 41 | COPY windows_wine/msys2.gpg /usr/share/pacman/keyrings/ 42 | COPY windows_wine/msys2-trusted /usr/share/pacman/keyrings/ 43 | RUN pacman-key --populate msys2 44 | 45 | # TODO: Install pacman first? 46 | # TODO: Also add a mssy2 install command? (Without -Sy) 47 | 48 | # Install msys2 packages. 49 | RUN pacman --config /etc/pacman-msys2.conf -Sy \ 50 | --noconfirm \ 51 | --noscriptlet \ 52 | base-devel \ 53 | msys2-devel \ 54 | git \ 55 | go \ 56 | mingw-w64-x86_64-qt5 57 | 58 | # Install msys2. 59 | #RUN export MSYS2_VERSION="20190524" && \ 60 | # export MSYS2_CHECKSUM="168e156fa9f00d90a8445676c023c63be6e82f71487f4e2688ab5cb13b345383" && \ 61 | # mkdir -p /tmp/msys2 && \ 62 | # cd /tmp/msys2 && \ 63 | # wget -O msys2.tar.xz http://repo.msys2.org/distrib/x86_64/msys2-base-x86_64-${MSYS2_VERSION}.tar.xz && \ 64 | # echo "${MSYS2_CHECKSUM} msys2.tar.xz" | sha256sum -c && \ 65 | # tar -xvf msys2.tar.xz && \ 66 | # mv msys64 ${WINEROOT}/msys64 && \ 67 | # rm -rf /tmp/msys2 68 | 69 | #RUN mkdir /work 70 | #VOLUME /work 71 | #WORKDIR /work 72 | -------------------------------------------------------------------------------- /docker/_unused/windows_wine/msys2-trusted: -------------------------------------------------------------------------------- 1 | D55E7A6D7CE9BA1587C0ACACF40D263ECA25678A:4: 2 | 123D4D51A1793859C2BE916BBBE514E53E0D0813:4: 3 | B91BCF3303284BF90CC043CA9F418C233E652008:4: 4 | 9DD0D4217D75A33B896159E6DA7EF2ABAEEA755C:4: 5 | -------------------------------------------------------------------------------- /docker/_unused/windows_wine/pacman-msys2.conf: -------------------------------------------------------------------------------- 1 | [options] 2 | RootDir = /wine/drive_c 3 | Architecture = x86_64 4 | CheckSpace 5 | SigLevel = Required DatabaseOptional 6 | LocalFileSigLevel = Optional 7 | 8 | [msys] 9 | Server = http://repo.msys2.org/msys/$arch/ 10 | 11 | [mingw64] 12 | Server = http://repo.msys2.org/mingw/$arch/ 13 | -------------------------------------------------------------------------------- /docker/_unused/windows_wine/pacman.conf: -------------------------------------------------------------------------------- 1 | [options] 2 | HoldPkg = pacman glibc 3 | Architecture = auto 4 | CheckSpace 5 | SigLevel = Required DatabaseOptional 6 | LocalFileSigLevel = Optional 7 | 8 | [core] 9 | Include = /etc/pacman.d/mirrorlist 10 | 11 | [extra] 12 | Include = /etc/pacman.d/mirrorlist 13 | 14 | [community] 15 | Include = /etc/pacman.d/mirrorlist 16 | 17 | [multilib] 18 | Include = /etc/pacman.d/mirrorlist 19 | -------------------------------------------------------------------------------- /docker/android/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM desertbit/gml:linux 2 | MAINTAINER team@desertbit.com 3 | 4 | # Install dependencies. 5 | # http://doc.qt.io/qt-5/android-getting-started.html 6 | RUN dpkg --add-architecture i386 && \ 7 | apt-get -y update && \ 8 | apt-get -y install unzip \ 9 | libstdc++6:i386 libgcc1:i386 zlib1g:i386 libncurses5:i386 && \ 10 | apt-get -y clean 11 | 12 | # Install android NDK. 13 | # https://developer.android.com/ndk/downloads/ 14 | RUN mkdir /tmp/ndk && cd /tmp/ndk && \ 15 | export NDK_CHECKSUM="f02ad84cb5b6e1ff3eea9e6168037c823408c8ac" && \ 16 | wget -O ndk.zip https://dl.google.com/android/repository/android-ndk-r19-linux-x86_64.zip && \ 17 | echo "${NDK_CHECKSUM} ndk.zip" | sha1sum -c && \ 18 | unzip ndk.zip && \ 19 | mv android-ndk-r19 /ndk && \ 20 | rm -rf /tmp/ndk 21 | ENV PATH="/ndk:$PATH" 22 | 23 | # Patch NDK for gomobile. 24 | # https://github.com/golang/go/issues/29706 25 | RUN sed -i "s|flags = '-target {} -stdlib=libc++'.format(target)|flags = '-target {}'.format(target)|g" /ndk/build/tools/make_standalone_toolchain.py 26 | 27 | # Install gomobile. 28 | # https://github.com/golang/go/wiki/Mobile 29 | ENV GOPATH="$GOPATH:/gomobile" \ 30 | PATH="/gomobile/bin:$PATH" 31 | RUN mkdir -p /gomobile && cd /gomobile && \ 32 | export GOPATH="/gomobile" && \ 33 | go get golang.org/x/mobile/cmd/gomobile && \ 34 | gomobile init -ndk /ndk 35 | 36 | # TODO: Finish this -------------------------------------------------------------------------------- /docker/common/base: -------------------------------------------------------------------------------- 1 | # Install the Go compiler. 2 | RUN export GO_VERSION="1.23.3" && \ 3 | export GO_CHECKSUM="a0afb9744c00648bafb1b90b4aba5bdb86f424f02f9275399ce0c20b93a2c3a8" && \ 4 | mkdir -p /tmp/go && \ 5 | cd /tmp/go && \ 6 | wget -O go.tar.gz https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz && \ 7 | echo "${GO_CHECKSUM} go.tar.gz" | sha256sum -c && \ 8 | tar -xvf go.tar.gz && \ 9 | mv go /usr/local && \ 10 | rm -rf /tmp/go 11 | ENV PATH="$PATH:/usr/local/go/bin" \ 12 | GOROOT=/usr/local/go \ 13 | CGO_ENABLED=1 14 | 15 | # Install the gml tool. 16 | RUN export GOPATH="/tmp/gml/go" && \ 17 | export GOOS=linux && \ 18 | export GOARCH=amd64 && \ 19 | export VERSION="v0.0.40" && \ 20 | mkdir -p "${GOPATH}/bin" && \ 21 | cd /tmp/gml && \ 22 | go install "github.com/desertbit/gml/cmd/gml@${VERSION}" && \ 23 | go install "github.com/desertbit/gml/cmd/gml-copy-dlls@${VERSION}" && \ 24 | mv "${GOPATH}/bin/gml" /bin/gml && \ 25 | mv "${GOPATH}/bin/gml-copy-dlls" /bin/gml-copy-dlls && \ 26 | rm -rf /tmp/gml 27 | 28 | RUN mkdir /work 29 | VOLUME /work 30 | WORKDIR /work 31 | 32 | ADD common/entrypoint.sh /entrypoint 33 | RUN chmod +x /entrypoint 34 | ENTRYPOINT ["/entrypoint"] 35 | CMD ["gml"] 36 | -------------------------------------------------------------------------------- /docker/common/deploy-dlls.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | input="$GML_DEST_BINARY" 6 | destDir="$GML_DEST_DIR/deps" 7 | 8 | if [[ "$input" == "" ]]; then 9 | echo "no executable" 10 | exit 1 11 | elif [[ "$destDir" == "" ]]; then 12 | echo "no target directory specified" 13 | exit 1 14 | fi 15 | 16 | if [[ -d "$destDir" ]]; then 17 | rm -rf "$destDir" 18 | fi 19 | 20 | gml-copy-dlls \ 21 | -input "$input" \ 22 | -dest "$destDir" \ 23 | -src "/mxe/usr/${CROSS_TRIPLE}" \ 24 | -enforce "/mxe/usr/${CROSS_TRIPLE}/qt5/qml,/mxe/usr/${CROSS_TRIPLE}/qt5/plugins/platforms,/mxe/usr/${CROSS_TRIPLE}/qt5/plugins/imageformats,/mxe/usr/${CROSS_TRIPLE}/qt5/plugins/position,/mxe/usr/${CROSS_TRIPLE}/qt5/plugins/geoservices" \ 25 | -objdump "/mxe/usr/bin/${CROSS_TRIPLE}-objdump" 26 | 27 | mv -f "$destDir/qml/"* "$destDir/" 28 | rm -rf "$destDir/qml" -------------------------------------------------------------------------------- /docker/common/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | # If we are running docker natively, we want to create a user in the container 6 | # with the same UID and GID as the user on the host machine, so that any files 7 | # created are owned by that user. Without this they are all owned by root. 8 | if [[ -n $UID ]] && [[ -n $GID ]]; then 9 | export HOME="/home/builder" 10 | groupadd -o -g $GID builder 2> /dev/null 11 | useradd -d "${HOME}" -o -m -g $GID -u $UID -s /bin/bash builder 2> /dev/null 12 | chown builder:builder /work 13 | 14 | # Copy SSH known hosts from root if present. 15 | if [ -f /root/.ssh/known_hosts ]; then 16 | mkdir -p "${HOME}/.ssh" 17 | cp /root/.ssh/known_hosts "${HOME}/.ssh/known_hosts" 18 | chown -R builder:builder "${HOME}/.ssh" 19 | fi 20 | 21 | # Run the command as the specified user/group. 22 | exec sudo -E -H -u builder \ 23 | env "PATH=$PATH" \ 24 | env "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" \ 25 | "$@" 26 | else 27 | # Just run the command as root. 28 | exec "$@" 29 | fi -------------------------------------------------------------------------------- /docker/common/windows: -------------------------------------------------------------------------------- 1 | # TODO: Remove DONT_CHECK_REQUIREMENTS=1 2 | # See https://github.com/mxe/mxe/issues/2907 why this is necessary now. 3 | RUN cd /mxe && \ 4 | export NUM_CORES="$(grep -c processor /proc/cpuinfo)" && \ 5 | make -j${NUM_CORES} MXE_TARGETS="${CROSS_TRIPLE}" qtbase qtquickcontrols qtquickcontrols2 qtimageformats qtlocation qtcharts qtgraphicaleffects qtvirtualkeyboard DONT_CHECK_REQUIREMENTS=1 6 | 7 | ENV PATH="/mxe/usr/bin:/mxe/usr/${CROSS_TRIPLE}/qt5/bin:$PATH" \ 8 | PKG_CONFIG="/mxe/usr/bin/${CROSS_TRIPLE}-pkg-config" \ 9 | PKG_CONFIG_PATH="/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig:$PKG_CONFIG_PATH" \ 10 | CC="${CROSS_TRIPLE}-gcc" \ 11 | CXX="${CROSS_TRIPLE}-g++" 12 | 13 | # Patch to include some missing libraries for cgo. Otherwise the linker fails. 14 | RUN sed -i "s|Libs.private:|Libs.private: -lstdc++ |g" "/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig/Qt5Core.pc" -------------------------------------------------------------------------------- /docker/common/windows_shared: -------------------------------------------------------------------------------- 1 | ADD common/deploy-dlls.sh /bin/deploy-dlls 2 | RUN chmod +x /bin/deploy-dlls 3 | ENV GML_BUILD_POST_HOOKS="/bin/deploy-dlls" -------------------------------------------------------------------------------- /docker/generate.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package main 29 | 30 | import ( 31 | "fmt" 32 | "io/ioutil" 33 | "log" 34 | "os" 35 | "path/filepath" 36 | "strings" 37 | 38 | "github.com/desertbit/gml/internal/utils" 39 | ) 40 | 41 | const ( 42 | ImportPrefix = "#import" 43 | ) 44 | 45 | func main() { 46 | // Prepare the base dir. 47 | baseDir, err := os.Getwd() 48 | if err != nil { 49 | log.Fatalln("failed to get current working dir:", err) 50 | } 51 | 52 | // Generate all Dockerfiles from Dockerfile.in files. 53 | err = generate(baseDir) 54 | if err != nil { 55 | log.Fatalln("failed to generate Dockerfiles:", err) 56 | } 57 | } 58 | 59 | func generate(baseDir string) (err error) { 60 | var ( 61 | e bool 62 | data []byte 63 | ) 64 | 65 | entries, err := ioutil.ReadDir(baseDir) 66 | if err != nil { 67 | return 68 | } 69 | 70 | for _, fi := range entries { 71 | if !fi.IsDir() { 72 | continue 73 | } 74 | t := filepath.Base(fi.Name()) 75 | 76 | dockerFile := filepath.Join(baseDir, t, "Dockerfile") 77 | dockerFileIn := dockerFile + ".in" 78 | 79 | e, err = utils.Exists(dockerFileIn) 80 | if err != nil { 81 | return 82 | } else if !e { 83 | continue 84 | } 85 | 86 | fmt.Println("> generating:", t) 87 | 88 | data, err = ioutil.ReadFile(dockerFileIn) 89 | if err != nil { 90 | return 91 | } 92 | 93 | var out *os.File 94 | out, err = os.Create(dockerFile) 95 | if err != nil { 96 | return 97 | } 98 | defer out.Close() 99 | 100 | lines := strings.Split(string(data), "\n") 101 | for _, line := range lines { 102 | if !strings.HasPrefix(strings.TrimSpace(line), ImportPrefix) { 103 | _, err = out.WriteString(line + "\n") 104 | if err != nil { 105 | return 106 | } 107 | continue 108 | } 109 | 110 | line = strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(line), ImportPrefix)) 111 | if len(line) == 0 { 112 | return fmt.Errorf("invalid import command: %s", line) 113 | } 114 | 115 | importFile := filepath.Join(baseDir, line) 116 | e, err = utils.Exists(importFile) 117 | if err != nil { 118 | return 119 | } else if !e { 120 | return fmt.Errorf("invalid import command: %s", line) 121 | } 122 | 123 | data, err = ioutil.ReadFile(importFile) 124 | if err != nil { 125 | return 126 | } 127 | 128 | _, err = out.WriteString(string(data) + "\n") 129 | if err != nil { 130 | return 131 | } 132 | } 133 | 134 | } 135 | return 136 | } 137 | -------------------------------------------------------------------------------- /docker/linux/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | MAINTAINER team@desertbit.com 3 | 4 | # Install dependencies. 5 | RUN export DEBIAN_FRONTEND=noninteractive && \ 6 | apt-get -y update && \ 7 | apt-get -y install build-essential sudo git wget nano make pkg-config \ 8 | qt5-default qttools5-dev-tools qtdeclarative5-dev libqt5charts5-dev libqt5charts5 && \ 9 | apt-get -y clean 10 | 11 | # Install the Go compiler. 12 | RUN export GO_VERSION="1.23.3" && \ 13 | export GO_CHECKSUM="a0afb9744c00648bafb1b90b4aba5bdb86f424f02f9275399ce0c20b93a2c3a8" && \ 14 | mkdir -p /tmp/go && \ 15 | cd /tmp/go && \ 16 | wget -O go.tar.gz https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz && \ 17 | echo "${GO_CHECKSUM} go.tar.gz" | sha256sum -c && \ 18 | tar -xvf go.tar.gz && \ 19 | mv go /usr/local && \ 20 | rm -rf /tmp/go 21 | ENV PATH="$PATH:/usr/local/go/bin" \ 22 | GOROOT=/usr/local/go \ 23 | CGO_ENABLED=1 24 | 25 | # Install the gml tool. 26 | RUN export GOPATH="/tmp/gml/go" && \ 27 | export GOOS=linux && \ 28 | export GOARCH=amd64 && \ 29 | export VERSION="v0.0.40" && \ 30 | mkdir -p "${GOPATH}/bin" && \ 31 | cd /tmp/gml && \ 32 | go install "github.com/desertbit/gml/cmd/gml@${VERSION}" && \ 33 | go install "github.com/desertbit/gml/cmd/gml-copy-dlls@${VERSION}" && \ 34 | mv "${GOPATH}/bin/gml" /bin/gml && \ 35 | mv "${GOPATH}/bin/gml-copy-dlls" /bin/gml-copy-dlls && \ 36 | rm -rf /tmp/gml 37 | 38 | RUN mkdir /work 39 | VOLUME /work 40 | WORKDIR /work 41 | 42 | ADD common/entrypoint.sh /entrypoint 43 | RUN chmod +x /entrypoint 44 | ENTRYPOINT ["/entrypoint"] 45 | CMD ["gml"] 46 | 47 | -------------------------------------------------------------------------------- /docker/linux/Dockerfile.in: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | MAINTAINER team@desertbit.com 3 | 4 | # Install dependencies. 5 | RUN export DEBIAN_FRONTEND=noninteractive && \ 6 | apt-get -y update && \ 7 | apt-get -y install build-essential sudo git wget nano make pkg-config \ 8 | qt5-default qttools5-dev-tools qtdeclarative5-dev libqt5charts5-dev libqt5charts5 && \ 9 | apt-get -y clean 10 | 11 | #import common/base -------------------------------------------------------------------------------- /docker/windows/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | MAINTAINER team@desertbit.com 3 | 4 | # Install dependencies. 5 | # https://mxe.cc/#requirements 6 | RUN export DEBIAN_FRONTEND=noninteractive && \ 7 | apt-get -y update && \ 8 | apt-get -y install \ 9 | sudo \ 10 | nano \ 11 | autoconf \ 12 | automake \ 13 | autopoint \ 14 | bash \ 15 | bison \ 16 | bzip2 \ 17 | flex \ 18 | g++ \ 19 | g++-multilib \ 20 | gettext \ 21 | git \ 22 | gperf \ 23 | intltool \ 24 | libc6-dev-i386 \ 25 | libgdk-pixbuf2.0-dev \ 26 | libltdl-dev \ 27 | libssl-dev \ 28 | libtool-bin \ 29 | libxml-parser-perl \ 30 | lzip \ 31 | make \ 32 | openssl \ 33 | p7zip-full \ 34 | patch \ 35 | perl \ 36 | pkg-config \ 37 | python \ 38 | python3-mako \ 39 | ruby \ 40 | sed \ 41 | unzip \ 42 | wget \ 43 | xz-utils && \ 44 | apt-get -y clean 45 | 46 | # Install the Go compiler. 47 | RUN export GO_VERSION="1.23.3" && \ 48 | export GO_CHECKSUM="a0afb9744c00648bafb1b90b4aba5bdb86f424f02f9275399ce0c20b93a2c3a8" && \ 49 | mkdir -p /tmp/go && \ 50 | cd /tmp/go && \ 51 | wget -O go.tar.gz https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz && \ 52 | echo "${GO_CHECKSUM} go.tar.gz" | sha256sum -c && \ 53 | tar -xvf go.tar.gz && \ 54 | mv go /usr/local && \ 55 | rm -rf /tmp/go 56 | ENV PATH="$PATH:/usr/local/go/bin" \ 57 | GOROOT=/usr/local/go \ 58 | CGO_ENABLED=1 59 | 60 | # Install the gml tool. 61 | RUN export GOPATH="/tmp/gml/go" && \ 62 | export GOOS=linux && \ 63 | export GOARCH=amd64 && \ 64 | export VERSION="v0.0.40" && \ 65 | mkdir -p "${GOPATH}/bin" && \ 66 | cd /tmp/gml && \ 67 | go install "github.com/desertbit/gml/cmd/gml@${VERSION}" && \ 68 | go install "github.com/desertbit/gml/cmd/gml-copy-dlls@${VERSION}" && \ 69 | mv "${GOPATH}/bin/gml" /bin/gml && \ 70 | mv "${GOPATH}/bin/gml-copy-dlls" /bin/gml-copy-dlls && \ 71 | rm -rf /tmp/gml 72 | 73 | RUN mkdir /work 74 | VOLUME /work 75 | WORKDIR /work 76 | 77 | ADD common/entrypoint.sh /entrypoint 78 | RUN chmod +x /entrypoint 79 | ENTRYPOINT ["/entrypoint"] 80 | CMD ["gml"] 81 | 82 | 83 | # https://mxe.cc 84 | # https://stackoverflow.com/questions/14170590/building-qt-5-on-linux-for-windows/14170591#14170591 85 | # Version Master 86 | RUN export MXE_COMMIT="6f1727478aeb8981eaf5a9b82c8bc87c5fd3e20c" && \ 87 | git clone https://github.com/mxe/mxe.git /mxe && \ 88 | cd /mxe && \ 89 | git checkout "${MXE_COMMIT}" 90 | 91 | -------------------------------------------------------------------------------- /docker/windows/Dockerfile.in: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | MAINTAINER team@desertbit.com 3 | 4 | # Install dependencies. 5 | # https://mxe.cc/#requirements 6 | RUN export DEBIAN_FRONTEND=noninteractive && \ 7 | apt-get -y update && \ 8 | apt-get -y install \ 9 | sudo \ 10 | nano \ 11 | autoconf \ 12 | automake \ 13 | autopoint \ 14 | bash \ 15 | bison \ 16 | bzip2 \ 17 | flex \ 18 | g++ \ 19 | g++-multilib \ 20 | gettext \ 21 | git \ 22 | gperf \ 23 | intltool \ 24 | libc6-dev-i386 \ 25 | libgdk-pixbuf2.0-dev \ 26 | libltdl-dev \ 27 | libssl-dev \ 28 | libtool-bin \ 29 | libxml-parser-perl \ 30 | lzip \ 31 | make \ 32 | openssl \ 33 | p7zip-full \ 34 | patch \ 35 | perl \ 36 | pkg-config \ 37 | python \ 38 | python3-mako \ 39 | ruby \ 40 | sed \ 41 | unzip \ 42 | wget \ 43 | xz-utils && \ 44 | apt-get -y clean 45 | 46 | #import common/base 47 | 48 | # https://mxe.cc 49 | # https://stackoverflow.com/questions/14170590/building-qt-5-on-linux-for-windows/14170591#14170591 50 | # Version Master 51 | RUN export MXE_COMMIT="6f1727478aeb8981eaf5a9b82c8bc87c5fd3e20c" && \ 52 | git clone https://github.com/mxe/mxe.git /mxe && \ 53 | cd /mxe && \ 54 | git checkout "${MXE_COMMIT}" 55 | -------------------------------------------------------------------------------- /docker/windows_32_shared/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM desertbit/gml:windows 2 | MAINTAINER team@desertbit.com 3 | 4 | ENV CROSS_TRIPLE="i686-w64-mingw32.shared" \ 5 | GOOS=windows \ 6 | GOARCH=386 7 | 8 | # TODO: Remove DONT_CHECK_REQUIREMENTS=1 9 | # See https://github.com/mxe/mxe/issues/2907 why this is necessary now. 10 | RUN cd /mxe && \ 11 | export NUM_CORES="$(grep -c processor /proc/cpuinfo)" && \ 12 | make -j${NUM_CORES} MXE_TARGETS="${CROSS_TRIPLE}" qtbase qtquickcontrols qtquickcontrols2 qtimageformats qtlocation qtcharts qtgraphicaleffects qtvirtualkeyboard DONT_CHECK_REQUIREMENTS=1 13 | 14 | ENV PATH="/mxe/usr/bin:/mxe/usr/${CROSS_TRIPLE}/qt5/bin:$PATH" \ 15 | PKG_CONFIG="/mxe/usr/bin/${CROSS_TRIPLE}-pkg-config" \ 16 | PKG_CONFIG_PATH="/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig:$PKG_CONFIG_PATH" \ 17 | CC="${CROSS_TRIPLE}-gcc" \ 18 | CXX="${CROSS_TRIPLE}-g++" 19 | 20 | # Patch to include some missing libraries for cgo. Otherwise the linker fails. 21 | RUN sed -i "s|Libs.private:|Libs.private: -lstdc++ |g" "/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig/Qt5Core.pc" 22 | ADD common/deploy-dlls.sh /bin/deploy-dlls 23 | RUN chmod +x /bin/deploy-dlls 24 | ENV GML_BUILD_POST_HOOKS="/bin/deploy-dlls" 25 | 26 | -------------------------------------------------------------------------------- /docker/windows_32_shared/Dockerfile.in: -------------------------------------------------------------------------------- 1 | FROM desertbit/gml:windows 2 | MAINTAINER team@desertbit.com 3 | 4 | ENV CROSS_TRIPLE="i686-w64-mingw32.shared" \ 5 | GOOS=windows \ 6 | GOARCH=386 7 | 8 | #import common/windows 9 | #import common/windows_shared 10 | -------------------------------------------------------------------------------- /docker/windows_64_shared/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM desertbit/gml:windows 2 | MAINTAINER team@desertbit.com 3 | 4 | ENV CROSS_TRIPLE="x86_64-w64-mingw32.shared" \ 5 | GOOS=windows \ 6 | GOARCH=amd64 7 | 8 | # TODO: Remove DONT_CHECK_REQUIREMENTS=1 9 | # See https://github.com/mxe/mxe/issues/2907 why this is necessary now. 10 | RUN cd /mxe && \ 11 | export NUM_CORES="$(grep -c processor /proc/cpuinfo)" && \ 12 | make -j${NUM_CORES} MXE_TARGETS="${CROSS_TRIPLE}" qtbase qtquickcontrols qtquickcontrols2 qtimageformats qtlocation qtcharts qtgraphicaleffects qtvirtualkeyboard DONT_CHECK_REQUIREMENTS=1 13 | 14 | ENV PATH="/mxe/usr/bin:/mxe/usr/${CROSS_TRIPLE}/qt5/bin:$PATH" \ 15 | PKG_CONFIG="/mxe/usr/bin/${CROSS_TRIPLE}-pkg-config" \ 16 | PKG_CONFIG_PATH="/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig:$PKG_CONFIG_PATH" \ 17 | CC="${CROSS_TRIPLE}-gcc" \ 18 | CXX="${CROSS_TRIPLE}-g++" 19 | 20 | # Patch to include some missing libraries for cgo. Otherwise the linker fails. 21 | RUN sed -i "s|Libs.private:|Libs.private: -lstdc++ |g" "/mxe/usr/${CROSS_TRIPLE}/qt5/lib/pkgconfig/Qt5Core.pc" 22 | ADD common/deploy-dlls.sh /bin/deploy-dlls 23 | RUN chmod +x /bin/deploy-dlls 24 | ENV GML_BUILD_POST_HOOKS="/bin/deploy-dlls" 25 | 26 | -------------------------------------------------------------------------------- /docker/windows_64_shared/Dockerfile.in: -------------------------------------------------------------------------------- 1 | FROM desertbit/gml:windows 2 | MAINTAINER team@desertbit.com 3 | 4 | ENV CROSS_TRIPLE="x86_64-w64-mingw32.shared" \ 5 | GOOS=windows \ 6 | GOARCH=amd64 7 | 8 | #import common/windows 9 | #import common/windows_shared 10 | -------------------------------------------------------------------------------- /error.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | // #include 31 | import "C" 32 | import "errors" 33 | 34 | type apiError struct { 35 | err C.gml_error 36 | } 37 | 38 | func newAPIError() *apiError { 39 | return &apiError{ 40 | err: C.gml_error_new(), 41 | } 42 | } 43 | 44 | func (e *apiError) Free() { 45 | C.gml_error_free(e.err) 46 | } 47 | 48 | func (e *apiError) String() string { 49 | return C.GoString(C.gml_error_get_msg(e.err)) 50 | } 51 | 52 | func (e *apiError) Reset() { 53 | C.gml_error_reset(e.err) 54 | } 55 | 56 | func (e *apiError) Err(prefix ...string) error { 57 | s := e.String() 58 | if len(prefix) > 0 { 59 | if len(s) == 0 { 60 | s = prefix[0] 61 | } else { 62 | s = prefix[0] + ": " + s 63 | } 64 | } else if len(s) == 0 { 65 | s = "unknown error" 66 | } 67 | return errors.New(s) 68 | } 69 | -------------------------------------------------------------------------------- /errors.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | const ( 31 | errorPoolSize = 50 32 | ) 33 | 34 | var ( 35 | errorPool = newAPIErrorPool(errorPoolSize) 36 | ) 37 | 38 | type apiErrorPool struct { 39 | pool chan *apiError 40 | } 41 | 42 | func newAPIErrorPool(poolSize int) *apiErrorPool { 43 | return &apiErrorPool{ 44 | pool: make(chan *apiError, poolSize), 45 | } 46 | } 47 | 48 | // Get an error from the pool. 49 | // Allocates new memory if the pool is empty. 50 | func (p *apiErrorPool) Get() (e *apiError) { 51 | select { 52 | case e = <-p.pool: 53 | default: 54 | e = newAPIError() 55 | } 56 | return 57 | } 58 | 59 | // Put an error back to the pool. 60 | func (p *apiErrorPool) Put(e *apiError) { 61 | // Reset the error message. 62 | e.Reset() 63 | 64 | select { 65 | case p.pool <- e: 66 | default: 67 | // Just let it go. The pool is full. 68 | e.Free() 69 | } 70 | } 71 | 72 | // Reset empties the pool. 73 | func (p *apiErrorPool) Reset() { 74 | var e *apiError 75 | for { 76 | select { 77 | case e = <-p.pool: 78 | e.Free() 79 | default: 80 | return 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /gml.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | // #include 31 | import "C" 32 | import ( 33 | "fmt" 34 | "log" 35 | "os" 36 | "unsafe" 37 | ) 38 | 39 | // Global app variable. 40 | var gapp *app 41 | 42 | func init() { 43 | // Right now there is only support for one global app. 44 | // This simplifies the gml API. 45 | var err error 46 | gapp, err = newApp() 47 | if err != nil { 48 | log.Fatalf("gml: failed to create global application: %v", err) 49 | } 50 | 51 | SetSearchPaths("qml", []string{":/qml"}) 52 | SetSearchPaths("res", []string{":/resources"}) 53 | } 54 | 55 | // Must exits the application with a fatal log if the error is present. 56 | func Must(err error) { 57 | if err != nil { 58 | log.Fatalf("gml must: %v", err) 59 | } 60 | } 61 | 62 | // RunMain runs the function on the applications main thread. 63 | func RunMain(f func()) { 64 | gapp.RunMain(f) 65 | } 66 | 67 | // Exec load the root QML file located at url, 68 | // executes the application and returns the exit code. 69 | // This method is blocking. 70 | // Hint: Must be called within main thread. 71 | func Exec(url string) (retCode int, err error) { 72 | return gapp.Exec(url) 73 | } 74 | 75 | // ExecExit load the root QML file located at url, 76 | // executes the app, prints errors and exits 77 | // the application with the specific exit code. 78 | func ExecExit(url string) { 79 | ret, err := gapp.Exec(url) 80 | if err != nil { 81 | fmt.Println(err) 82 | } 83 | os.Exit(ret) 84 | } 85 | 86 | // Quit the application. 87 | func Quit() { 88 | gapp.Quit() 89 | } 90 | 91 | func SetApplicationName(name string) { 92 | gapp.SetApplicationName(name) 93 | } 94 | 95 | func SetOrganizationName(name string) { 96 | gapp.SetOrganizationName(name) 97 | } 98 | 99 | func SetApplicationVersion(version string) { 100 | gapp.SetApplicationVersion(version) 101 | } 102 | 103 | func SetWindowIcon(name string) { 104 | gapp.SetWindowIcon(name) 105 | } 106 | 107 | // AddImageProvider adds the image provider to the app engine for the given id. 108 | func AddImageProvider(id string, ip *ImageProvider) error { 109 | return gapp.AddImageProvider(id, ip) 110 | } 111 | 112 | func SetContextProperty(name string, v interface{}) error { 113 | return gapp.SetContextProperty(name, v) 114 | } 115 | 116 | func SwitchLanguage(lang string) error { 117 | return gapp.SwitchLanguage(lang) 118 | } 119 | 120 | // AddImportPath adds the given import path to the app engine. 121 | // Hint: Must be called within main thread. 122 | func AddImportPath(path string) { 123 | gapp.AddImportPath(path) 124 | } 125 | 126 | // SetSearchPaths sets or replaces Qt's search paths for file names with the prefix prefix to searchPaths. 127 | // To specify a prefix for a file name, prepend the prefix followed by a single colon (e.g., "images:undo.png", "xmldocs:books.xml"). prefix can only contain letters or numbers (e.g., it cannot contain a colon, nor a slash). 128 | // Qt uses this search path to locate files with a known prefix. The search path entries are tested in order, starting with the first entry. 129 | func SetSearchPaths(prefix string, searchPaths []string) { 130 | if len(prefix) == 0 || len(searchPaths) == 0 { 131 | return 132 | } 133 | 134 | prefixC := C.CString(prefix) 135 | defer C.free(unsafe.Pointer(prefixC)) 136 | 137 | pathsC := toCharArray(searchPaths) 138 | defer freeCharArray(pathsC, len(searchPaths)) 139 | 140 | C.gml_global_set_search_paths(prefixC, pathsC, C.int(len(searchPaths))) 141 | } 142 | 143 | // SetIconThemeName sets the current icon theme to name. 144 | func SetIconThemeName(name string) { 145 | nameC := C.CString(name) 146 | defer C.free(unsafe.Pointer(nameC)) 147 | 148 | C.gml_global_set_icon_theme_name(nameC) 149 | } 150 | 151 | // SetIconThemeSearchPaths sets the search paths for icon themes to paths. 152 | func SetIconThemeSearchPaths(searchPaths ...string) { 153 | if len(searchPaths) == 0 { 154 | return 155 | } 156 | 157 | pathsC := toCharArray(searchPaths) 158 | defer freeCharArray(pathsC, len(searchPaths)) 159 | 160 | C.gml_global_set_icon_theme_search_paths(pathsC, C.int(len(searchPaths))) 161 | } 162 | 163 | /* 164 | func ExecDev(basePath, url string) (retCode int, err error) { 165 | AddImportPath(basePath) 166 | 167 | w := watcher.New() 168 | w.SetMaxEvents(1) 169 | 170 | go func() { 171 | for { 172 | select { 173 | case event := <-w.Event: 174 | RunMain(func() { 175 | fmt.Println(event) // Print the event's info. TODO: log 176 | gapp.ClearComponentCache() 177 | }) 178 | 179 | case err := <-w.Error: 180 | log.Println("dev file watcher error: %v", err) 181 | 182 | case <-w.Closed: 183 | return 184 | } 185 | } 186 | }() 187 | 188 | err = w.AddRecursive(filepath.Join(basePath, "qml")) 189 | if err != nil { 190 | return 191 | } 192 | 193 | go func() { 194 | err := w.Start(time.Millisecond * 250) 195 | if err != nil { 196 | log.Println("dev file watcher failed: %v", err) 197 | } 198 | }() 199 | 200 | return Exec(url) 201 | } 202 | 203 | func ExecDevExit(basePath, url string) { 204 | ret, err := ExecDev(basePath, url) 205 | if err != nil { 206 | fmt.Println(err) 207 | } 208 | os.Exit(ret) 209 | } 210 | */ 211 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/desertbit/gml 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/desertbit/closer/v3 v3.1.3 7 | github.com/desertbit/go-shlex v0.1.1 8 | github.com/desertbit/grumble v1.1.3 9 | github.com/fatih/color v1.14.1 10 | github.com/hashicorp/go-multierror v1.1.1 // indirect 11 | github.com/json-iterator/go v1.1.12 12 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 13 | github.com/stretchr/objx v0.2.0 // indirect 14 | golang.org/x/crypto v0.6.0 15 | golang.org/x/sys v0.5.0 16 | ) 17 | -------------------------------------------------------------------------------- /image.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | // #include 31 | import "C" 32 | import ( 33 | "errors" 34 | "fmt" 35 | "image" 36 | "image/draw" 37 | "runtime" 38 | "unsafe" 39 | ) 40 | 41 | type Image struct { 42 | freed bool 43 | ptr C.gml_image 44 | } 45 | 46 | func NewImage() (img *Image) { 47 | return newImage(C.gml_image_new(), true) 48 | } 49 | 50 | func newImage(imgC C.gml_image, free bool) (img *Image) { 51 | // Check if something failed. 52 | // This should never happen is signalizes a fatal error. 53 | if imgC == nil { 54 | panic(fmt.Errorf("gml image: C pointer is nil")) 55 | } 56 | 57 | img = &Image{ 58 | freed: !free, 59 | ptr: imgC, 60 | } 61 | 62 | // Always free the C++ value if defined so. 63 | if free { 64 | runtime.SetFinalizer(img, freeImage) 65 | } 66 | 67 | return 68 | } 69 | 70 | func freeImage(img *Image) { 71 | if img.freed { 72 | return 73 | } 74 | img.freed = true 75 | C.gml_image_free(img.ptr) 76 | } 77 | 78 | func (img *Image) Free() { 79 | freeImage(img) 80 | } 81 | 82 | // Reset the image to an empty image. 83 | func (img *Image) Reset() { 84 | C.gml_image_reset(img.ptr) 85 | 86 | // Prevent the GC from freeing. Go issue 13347 87 | runtime.KeepAlive(img) 88 | } 89 | 90 | func (img *Image) Copy(dst *Image, x, y, width, height int) { 91 | // Copy the image. 92 | C.gml_image_copy(img.ptr, dst.ptr, C.int(x), C.int(y), C.int(width), C.int(height)) 93 | 94 | // Prevent the GC from freeing. Go issue 13347 95 | runtime.KeepAlive(img) 96 | runtime.KeepAlive(dst) 97 | } 98 | 99 | // SetTo performs a shallow copy. 100 | func (img *Image) SetTo(other *Image) { 101 | C.gml_image_set_to(img.ptr, other.ptr) 102 | 103 | // Prevent the GC from freeing. Go issue 13347 104 | runtime.KeepAlive(img) 105 | runtime.KeepAlive(other) 106 | } 107 | 108 | func (img *Image) LoadFromGoImage(gimg image.Image) error { 109 | b := gimg.Bounds() 110 | 111 | // Get the RGBA image if present. 112 | // Otherwise convert to RGBA. 113 | imgRGBA, ok := gimg.(*image.RGBA) 114 | if !ok { 115 | imgRGBA = image.NewRGBA(b) 116 | draw.Draw(imgRGBA, b, gimg, b.Min, draw.Src) 117 | } 118 | 119 | // Ensure the image is not empty. 120 | if len(imgRGBA.Pix) == 0 { 121 | return errors.New("empty rgba image") 122 | } 123 | 124 | apiErr := errorPool.Get() 125 | defer errorPool.Put(apiErr) 126 | 127 | ret := C.gml_image_load_from_rgba( 128 | img.ptr, 129 | (*C.char)(unsafe.Pointer(&imgRGBA.Pix[0])), 130 | C.int(len(imgRGBA.Pix)), 131 | C.int(b.Dx()), 132 | C.int(b.Dy()), 133 | C.int(imgRGBA.Stride), 134 | apiErr.err, 135 | ) 136 | if ret != 0 { 137 | return apiErr.Err("failed to load from data") 138 | } 139 | 140 | // Prevent the GC from freeing. Go issue 13347 141 | runtime.KeepAlive(img) 142 | runtime.KeepAlive(gimg) 143 | runtime.KeepAlive(imgRGBA) 144 | 145 | return nil 146 | } 147 | 148 | func (img *Image) LoadFromFile(filename string) error { 149 | if len(filename) == 0 { 150 | return fmt.Errorf("empty filename") 151 | } 152 | 153 | filenameC := C.CString(filename) 154 | defer C.free(unsafe.Pointer(filenameC)) 155 | 156 | apiErr := errorPool.Get() 157 | defer errorPool.Put(apiErr) 158 | 159 | ret := C.gml_image_load_from_file(img.ptr, filenameC, apiErr.err) 160 | if ret != 0 { 161 | return apiErr.Err("failed to load from file") 162 | } 163 | 164 | // Prevent the GC from freeing. Go issue 13347 165 | runtime.KeepAlive(img) 166 | 167 | return nil 168 | } 169 | 170 | func (img *Image) LoadFromData(data []byte) error { 171 | if len(data) == 0 { 172 | return fmt.Errorf("empty data") 173 | } 174 | 175 | apiErr := errorPool.Get() 176 | defer errorPool.Put(apiErr) 177 | 178 | ret := C.gml_image_load_from_data(img.ptr, (*C.char)(unsafe.Pointer(&data[0])), C.int(len(data)), apiErr.err) 179 | if ret != 0 { 180 | return apiErr.Err("failed to load from data") 181 | } 182 | 183 | // Prevent the GC from freeing. Go issue 13347 184 | runtime.KeepAlive(img) 185 | runtime.KeepAlive(data) 186 | 187 | return nil 188 | } 189 | 190 | func (img *Image) Height() (height int) { 191 | height = int(C.gml_image_height(img.ptr)) 192 | 193 | // Prevent the GC from freeing. Go issue 13347 194 | runtime.KeepAlive(img) 195 | return 196 | } 197 | 198 | func (img *Image) Width() (width int) { 199 | width = int(C.gml_image_width(img.ptr)) 200 | 201 | // Prevent the GC from freeing. Go issue 13347 202 | runtime.KeepAlive(img) 203 | return 204 | } 205 | 206 | func (img *Image) IsEmpty() (empty bool) { 207 | empty = (C.gml_image_is_empty(img.ptr) != 0) 208 | 209 | // Prevent the GC from freeing. Go issue 13347 210 | runtime.KeepAlive(img) 211 | return 212 | } 213 | -------------------------------------------------------------------------------- /imageitem.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | // #include 31 | // 32 | // extern void gml_image_item_request_go_slot(char* id, gml_image img); 33 | // static void gml_image_item_init() { 34 | // gml_image_item_request_cb_register(gml_image_item_request_go_slot); 35 | // } 36 | import "C" 37 | import ( 38 | "log" 39 | "sync" 40 | "unsafe" 41 | ) 42 | 43 | var ( 44 | imageItemsMutex sync.Mutex 45 | imageItems = make(map[string]*ImageItem) 46 | ) 47 | 48 | func init() { 49 | C.gml_image_item_init() 50 | } 51 | 52 | //#################// 53 | //### ImageItem ###// 54 | //#################// 55 | 56 | type ImageItem struct { 57 | id string 58 | idC *C.char 59 | 60 | mutex sync.Mutex 61 | released bool 62 | img *Image 63 | } 64 | 65 | func NewImageItem(id string) (i *ImageItem) { 66 | i = &ImageItem{ 67 | id: id, 68 | idC: C.CString(id), 69 | img: NewImage(), 70 | } 71 | 72 | old := setImageItem(id, i) 73 | if old != nil { 74 | old.release(true) 75 | } 76 | 77 | // Hint: Does not need a finalizer, because it is always in the map 78 | // and Release must be called. 79 | return 80 | } 81 | 82 | // SetImage sets the image by doing a shallow copy. 83 | func (i *ImageItem) SetImage(img *Image) { 84 | i.mutex.Lock() 85 | i.img.SetTo(img) 86 | i.mutex.Unlock() 87 | 88 | // Notify the change to QML. 89 | // Don't need RunMain, because this emits only a signal. 90 | C.gml_image_item_emit_changed(i.idC) 91 | } 92 | 93 | func (i *ImageItem) ResetImage() { 94 | i.mutex.Lock() 95 | i.img.Reset() 96 | i.mutex.Unlock() 97 | 98 | // Notify the change to QML. 99 | // Don't need RunMain, because this emits only a signal. 100 | C.gml_image_item_emit_changed(i.idC) 101 | } 102 | 103 | // Release this image item. 104 | // Don't use it anymore after this call, because memory is freed. 105 | func (i *ImageItem) Release() { 106 | i.release(false) 107 | } 108 | 109 | func (i *ImageItem) release(skipMapDelete bool) { 110 | i.mutex.Lock() 111 | defer i.mutex.Unlock() 112 | 113 | if i.released { 114 | return 115 | } 116 | i.released = true 117 | 118 | if !skipMapDelete { 119 | deleteImageItem(i.id) 120 | } 121 | 122 | C.free(unsafe.Pointer(i.idC)) 123 | i.img.Free() 124 | } 125 | 126 | //######################// 127 | //### Image Item Map ###// 128 | //######################// 129 | 130 | func getImageItem(id string) (i *ImageItem) { 131 | imageItemsMutex.Lock() 132 | i = imageItems[id] 133 | imageItemsMutex.Unlock() 134 | return 135 | } 136 | 137 | func setImageItem(id string, i *ImageItem) (old *ImageItem) { 138 | imageItemsMutex.Lock() 139 | old = imageItems[id] 140 | imageItems[id] = i 141 | imageItemsMutex.Unlock() 142 | return 143 | } 144 | 145 | func deleteImageItem(id string) { 146 | imageItemsMutex.Lock() 147 | delete(imageItems, id) 148 | imageItemsMutex.Unlock() 149 | } 150 | 151 | //#####################// 152 | //### Exported to C ###// 153 | //#####################// 154 | 155 | //export gml_image_item_request_go_slot 156 | func gml_image_item_request_go_slot( 157 | idC *C.char, 158 | imgC C.gml_image, 159 | ) { 160 | id := C.GoString(idC) 161 | img := newImage(imgC, false) // Don't free the image. We are not the owner of the pointer. 162 | 163 | i := getImageItem(id) 164 | if i == nil { 165 | log.Println("gml: image item not registered for source ID:", id) 166 | return 167 | } 168 | 169 | i.mutex.Lock() 170 | img.SetTo(i.img) 171 | i.mutex.Unlock() 172 | } 173 | -------------------------------------------------------------------------------- /imageprovider.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | // #include 31 | // 32 | // extern void gml_image_provider_request_go_slot(void* goPtr, gml_image_response img_resp, char* id, gml_image img); 33 | // static void gml_image_provider_init() { 34 | // gml_image_provider_request_cb_register(gml_image_provider_request_go_slot); 35 | // } 36 | import "C" 37 | import ( 38 | "fmt" 39 | "runtime" 40 | "unsafe" 41 | 42 | "github.com/desertbit/gml/pointer" 43 | ) 44 | 45 | type AspectRatioMode int 46 | 47 | const ( 48 | IgnoreAspectRatio AspectRatioMode = C.GML_IGNORE_ASPECT_RATIO 49 | KeepAspectRatio AspectRatioMode = C.GML_KEEP_ASPECT_RATIO 50 | KeepAspectRatioByExpanding AspectRatioMode = C.GML_KEEP_ASPECT_RATIO_BY_EXPANDING 51 | ) 52 | 53 | type TransformationMode int 54 | 55 | const ( 56 | FastTransformation TransformationMode = C.GML_FAST_TRANSFORMATION 57 | SmoothTransformation TransformationMode = C.GML_SMOOTH_TRANSFORMATION 58 | ) 59 | 60 | func init() { 61 | C.gml_image_provider_init() 62 | } 63 | 64 | type ImageProviderCallback func(id string, img *Image) error 65 | 66 | type ImageProvider struct { 67 | freed bool 68 | ptr C.gml_image_provider 69 | goPtr unsafe.Pointer 70 | 71 | callback ImageProviderCallback 72 | } 73 | 74 | func NewImageProvider( 75 | aspectRatioMode AspectRatioMode, 76 | transformMode TransformationMode, 77 | callback ImageProviderCallback, 78 | ) *ImageProvider { 79 | ip := &ImageProvider{ 80 | callback: callback, 81 | } 82 | ip.goPtr = pointer.Save(ip) 83 | ip.ptr = C.gml_image_provider_new(ip.goPtr, C.int(aspectRatioMode), C.int(transformMode)) 84 | 85 | // Always free the C++ value. 86 | runtime.SetFinalizer(ip, freeImageProvider) 87 | 88 | // Check if something failed. 89 | // This should never happen. Otherwise this signalizes a fatal error. 90 | if ip.ptr == nil { 91 | panic(fmt.Errorf("failed to create gml imageprovider: C pointer is nil")) 92 | } 93 | 94 | return ip 95 | } 96 | 97 | func freeImageProvider(ip *ImageProvider) { 98 | if ip.freed { 99 | return 100 | } 101 | ip.freed = true 102 | C.gml_image_provider_free(ip.ptr) 103 | pointer.Unref(ip.goPtr) 104 | } 105 | 106 | func (ip *ImageProvider) Free() { 107 | freeImageProvider(ip) 108 | } 109 | 110 | //#####################// 111 | //### Exported to C ###// 112 | //#####################// 113 | 114 | //export gml_image_provider_request_go_slot 115 | func gml_image_provider_request_go_slot( 116 | goPtr unsafe.Pointer, 117 | imgResp C.gml_image_response, 118 | idc *C.char, 119 | imgC C.gml_image, 120 | ) { 121 | ip := (pointer.Restore(goPtr)).(*ImageProvider) 122 | id := C.GoString(idc) 123 | 124 | img := newImage(imgC, false) // Don't free the image. We are not the owner of the pointer. 125 | 126 | // Run in a new goroutine. 127 | go func() { 128 | var errStr string 129 | 130 | // Call the callback. 131 | err := ip.callback(id, img) 132 | if err != nil { 133 | errStr = err.Error() 134 | } 135 | 136 | // Convert the go string to a C string. 137 | errStrC := C.CString(errStr) 138 | defer C.free(unsafe.Pointer(errStrC)) 139 | 140 | // Emit the finished signal on the image response. 141 | // Must always be triggered! 142 | C.gml_image_response_emit_finished(imgResp, errStrC) 143 | }() 144 | } 145 | -------------------------------------------------------------------------------- /internal/binding/headers/gml.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_H 29 | #define GML_HEADER_H 30 | 31 | #include "gml_global.h" 32 | #include "gml_app.h" 33 | #include "gml_bytes.h" 34 | #include "gml_error.h" 35 | #include "gml_image.h" 36 | #include "gml_image_item.h" 37 | #include "gml_image_provider.h" 38 | #include "gml_includes.h" 39 | #include "gml_list_model.h" 40 | #include "gml_object.h" 41 | #include "gml_variant.h" 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /internal/binding/headers/gml_app.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_APP_H 29 | #define GML_HEADER_APP_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #include "gml_error.h" 36 | #include "gml_object.h" 37 | #include "gml_image_provider.h" 38 | #include "gml_variant.h" 39 | 40 | typedef void* gml_app; 41 | 42 | typedef void (*gml_app_run_main_cb_t)(void* go_ptr); 43 | void gml_app_run_main_cb_register(gml_app_run_main_cb_t cb); 44 | 45 | gml_app gml_app_new (int argv, char** argc, gml_error err); 46 | void gml_app_free(gml_app app); 47 | int gml_app_exec(gml_app app, gml_error err); 48 | void gml_app_quit(gml_app app); 49 | int gml_app_run_main(gml_app app, void* go_ptr); 50 | 51 | int gml_app_load (gml_app app, const char* url, gml_error err); 52 | int gml_app_load_data(gml_app app, const char* data, gml_error err); 53 | void gml_app_add_import_path(gml_app app, const char* path); 54 | int gml_app_add_imageprovider(gml_app app, const char* id, gml_image_provider ip, gml_error err); 55 | 56 | int gml_app_set_root_context_property_object(gml_app app, const char* name, gml_object obj, gml_error err); 57 | int gml_app_set_root_context_property_variant(gml_app app, const char* name, gml_variant gml_v, gml_error err); 58 | void gml_app_set_application_name(gml_app app, const char* name); 59 | void gml_app_set_organization_name(gml_app app, const char* name); 60 | void gml_app_set_application_version(gml_app app, const char* version); 61 | void gml_app_set_window_icon(gml_app app, const char* name); 62 | 63 | int gml_app_switch_language(gml_app app, const char* language, gml_error err); 64 | 65 | double gml_app_get_dp(gml_app app, gml_error err); 66 | 67 | #ifdef __cplusplus 68 | } 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /internal/binding/headers/gml_bytes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_BYTES_H 29 | #define GML_HEADER_BYTES_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | typedef void* gml_bytes; 36 | 37 | gml_bytes gml_bytes_new (); 38 | void gml_bytes_free(gml_bytes b); 39 | const char* gml_bytes_get (gml_bytes b, int* size); 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /internal/binding/headers/gml_cpp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_CPP_H 29 | #define GML_HEADER_CPP_H 30 | 31 | #include "../sources/gml_app.h" 32 | #include "../sources/gml_error.h" 33 | #include "../sources/gml_image_item.h" 34 | #include "../sources/gml_image_provider.h" 35 | #include "../sources/gml_list_model.h" 36 | 37 | #endif -------------------------------------------------------------------------------- /internal/binding/headers/gml_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_ERROR_H 29 | #define GML_HEADER_ERROR_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | typedef void* gml_error; 36 | 37 | gml_error gml_error_new(); 38 | void gml_error_free (gml_error err); 39 | void gml_error_reset (gml_error err); 40 | const char* gml_error_get_msg(gml_error err); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /internal/binding/headers/gml_global.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_GLOBAL_H 29 | #define GML_GLOBAL_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #include "gml_error.h" 36 | 37 | void gml_global_set_search_paths(const char* prefix, const char** paths, int paths_size); 38 | void gml_global_set_icon_theme_name(const char* name); 39 | void gml_global_set_icon_theme_search_paths(const char** paths, int paths_size); 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /internal/binding/headers/gml_image.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_IMAGE_H 29 | #define GML_HEADER_IMAGE_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #include "gml_error.h" 36 | 37 | typedef void* gml_image; 38 | 39 | gml_image gml_image_new(); 40 | void gml_image_free(gml_image img); 41 | void gml_image_reset(gml_image img); 42 | void gml_image_copy(gml_image img, gml_image dst, int x, int y, int width, int height); 43 | void gml_image_set_to(gml_image img, gml_image other); 44 | int gml_image_load_from_file(gml_image img, const char* filename, gml_error err); 45 | int gml_image_load_from_rgba(gml_image img, const char* data, int size, int width, int height, int stride, gml_error err); 46 | int gml_image_load_from_data(gml_image img, const char* data, int size, gml_error err); 47 | int gml_image_height(gml_image img); 48 | int gml_image_width(gml_image img); 49 | int gml_image_is_empty(gml_image img); 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif -------------------------------------------------------------------------------- /internal/binding/headers/gml_image_item.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_IMAGE_ITEM_H 29 | #define GML_HEADER_IMAGE_ITEM_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | typedef void (*gml_image_item_request_cb_t)( 36 | char* id, 37 | gml_image img 38 | ); 39 | void gml_image_item_request_cb_register(gml_image_item_request_cb_t cb); 40 | 41 | void gml_image_item_emit_changed(const char* id); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif -------------------------------------------------------------------------------- /internal/binding/headers/gml_image_provider.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_IMAGEPROVIDER_H 29 | #define GML_HEADER_IMAGEPROVIDER_H 30 | 31 | #define GML_IGNORE_ASPECT_RATIO 0 32 | #define GML_KEEP_ASPECT_RATIO 1 33 | #define GML_KEEP_ASPECT_RATIO_BY_EXPANDING 2 34 | 35 | #define GML_FAST_TRANSFORMATION 0 36 | #define GML_SMOOTH_TRANSFORMATION 1 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | #include "gml_image.h" 43 | 44 | typedef void* gml_image_provider; 45 | typedef void* gml_image_response; 46 | 47 | gml_image_provider gml_image_provider_new( 48 | void* go_ptr, 49 | int aspect_ratio_mode, 50 | int transformation_mode 51 | ); 52 | void gml_image_provider_free(gml_image_provider ip); 53 | 54 | typedef void (*gml_image_provider_request_cb_t)( 55 | void* go_ptr, 56 | gml_image_response img_resp, 57 | char* id, 58 | gml_image img 59 | ); 60 | void gml_image_provider_request_cb_register(gml_image_provider_request_cb_t cb); 61 | 62 | void gml_image_response_emit_finished( 63 | gml_image_response img_resp, 64 | char* error_string 65 | ); 66 | 67 | #ifdef __cplusplus 68 | } 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /internal/binding/headers/gml_includes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_INCLUDES_H 29 | #define GML_HEADER_INCLUDES_H 30 | 31 | #include 32 | #include 33 | 34 | #if defined(_WIN32) 35 | typedef uint8_t u_int8_t; 36 | typedef uint16_t u_int16_t; 37 | typedef uint32_t u_int32_t; 38 | typedef uint64_t u_int64_t; 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /internal/binding/headers/gml_list_model.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_LIST_MODEL_H 29 | #define GML_HEADER_LIST_MODEL_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #include "gml_variant.h" 36 | 37 | typedef void* gml_list_model; 38 | 39 | gml_list_model gml_list_model_new(void* go_ptr); 40 | void gml_list_model_free(gml_list_model lm); 41 | 42 | typedef int (*gml_list_model_row_count_cb_t)( 43 | void* go_ptr 44 | ); 45 | typedef gml_variant (*gml_list_model_data_cb_t)( 46 | void* go_ptr, 47 | int row 48 | ); 49 | typedef void (*gml_list_model_insert_rows_cb_t)( 50 | void* go_ptr, 51 | int row, 52 | int count 53 | ); 54 | void gml_list_model_cb_register( 55 | gml_list_model_row_count_cb_t rc_cb, 56 | gml_list_model_data_cb_t d_cb 57 | ); 58 | 59 | // Reset model. 60 | void gml_list_model_begin_reset_model(gml_list_model lm); 61 | void gml_list_model_end_reset_model(gml_list_model lm); 62 | 63 | // Insert rows. 64 | void gml_list_model_begin_insert_rows(gml_list_model lm, int row, int count); 65 | void gml_list_model_end_insert_rows(gml_list_model lm); 66 | 67 | // Move rows. 68 | void gml_list_model_begin_move_rows(gml_list_model lm, int row, int count, int dst_row); 69 | void gml_list_model_end_move_rows(gml_list_model lm); 70 | 71 | // Rows' data changed. 72 | void gml_list_model_rows_data_changed(gml_list_model lm, int row, int count); 73 | 74 | // Remove rows. 75 | void gml_list_model_begin_remove_rows(gml_list_model lm, int row, int count); 76 | void gml_list_model_end_remove_rows(gml_list_model lm); 77 | 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /internal/binding/headers/gml_object.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_OBJECT_H 29 | #define GML_HEADER_OBJECT_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | typedef void* gml_object; 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /internal/binding/headers/gml_variant.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_HEADER_VARIANT_H 29 | #define GML_HEADER_VARIANT_H 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #include "gml_includes.h" 36 | #include "gml_bytes.h" 37 | 38 | typedef void* gml_variant; 39 | 40 | gml_variant gml_variant_new(); 41 | void gml_variant_free(gml_variant v); 42 | 43 | // #############################// 44 | // ### To variant from value ###// 45 | // #############################// 46 | 47 | gml_variant gml_variant_new_from_bool(u_int8_t b); 48 | 49 | gml_variant gml_variant_new_from_float (float f); 50 | gml_variant gml_variant_new_from_double(double d); 51 | 52 | gml_variant gml_variant_new_from_int (int i); 53 | gml_variant gml_variant_new_from_int8 (int8_t i); 54 | gml_variant gml_variant_new_from_uint8 (u_int8_t i); 55 | gml_variant gml_variant_new_from_int16 (int16_t i); 56 | gml_variant gml_variant_new_from_uint16(u_int16_t i); 57 | gml_variant gml_variant_new_from_int32 (int32_t i); 58 | gml_variant gml_variant_new_from_uint32(u_int32_t i); 59 | gml_variant gml_variant_new_from_int64 (int64_t i); 60 | gml_variant gml_variant_new_from_uint64(u_int64_t i); 61 | 62 | gml_variant gml_variant_new_from_string(char* s); 63 | gml_variant gml_variant_new_from_bytes (char* b, int size); 64 | 65 | // ########################// 66 | // ### Variant to value ###// 67 | // ########################// 68 | 69 | u_int8_t gml_variant_to_bool(gml_variant v); 70 | 71 | float gml_variant_to_float (gml_variant v); 72 | double gml_variant_to_double(gml_variant v); 73 | 74 | int gml_variant_to_int (gml_variant v); 75 | int8_t gml_variant_to_int8 (gml_variant v); 76 | u_int8_t gml_variant_to_uint8 (gml_variant v); 77 | int16_t gml_variant_to_int16 (gml_variant v); 78 | u_int16_t gml_variant_to_uint16(gml_variant v); 79 | int32_t gml_variant_to_int32 (gml_variant v); 80 | u_int32_t gml_variant_to_uint32(gml_variant v); 81 | int64_t gml_variant_to_int64 (gml_variant v); 82 | u_int64_t gml_variant_to_uint64(gml_variant v); 83 | 84 | void gml_variant_to_string(gml_variant v, gml_bytes b); 85 | void gml_variant_to_bytes (gml_variant v, gml_bytes b); 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /internal/binding/sources/gml_app.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_APP_H 29 | #define GML_APP_H 30 | 31 | #include "gml_includes.h" 32 | #include "gml_error.h" 33 | #include "gml_image_provider.h" 34 | #include "gml_image_item.h" 35 | 36 | class GmlApp : public QObject { 37 | Q_OBJECT 38 | private: 39 | int argc; 40 | static GmlApp* globalApp; 41 | 42 | public: 43 | QApplication app; 44 | QQmlApplicationEngine engine; 45 | string language; 46 | QTranslator translator; 47 | 48 | GmlApp(int& argc, char** argv); 49 | 50 | static GmlApp* App(); 51 | 52 | signals: 53 | void requestRunMain(void* goPtr); 54 | void imageItemChanged(const QString id); 55 | 56 | private slots: 57 | void runMain(void* goPtr); 58 | }; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /internal/binding/sources/gml_bytes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #include "gml_includes.h" 29 | #include "gml_error.h" 30 | 31 | //#############// 32 | //### C API ###// 33 | //#############// 34 | 35 | gml_bytes gml_bytes_new() { 36 | try { 37 | QByteArray* qb = new QByteArray(); 38 | return (gml_bytes)qb; 39 | } 40 | catch (std::exception& e) { 41 | gml_error_log_exception(e.what()); 42 | return NULL; 43 | } 44 | catch (...) { 45 | gml_error_log_exception(); 46 | return NULL; 47 | } 48 | } 49 | 50 | void gml_bytes_free(gml_bytes b) { 51 | if (b == NULL) { 52 | return; 53 | } 54 | QByteArray* qb = (QByteArray*)b; 55 | delete qb; 56 | b = NULL; 57 | } 58 | 59 | const char* gml_bytes_get(gml_bytes b, int* size) { 60 | try { 61 | QByteArray* qb = (QByteArray*)b; 62 | *size = qb->length(); 63 | return qb->constData(); 64 | } 65 | catch (std::exception& e) { 66 | gml_error_log_exception(e.what()); 67 | return NULL; 68 | } 69 | catch (...) { 70 | gml_error_log_exception(); 71 | return NULL; 72 | } 73 | } -------------------------------------------------------------------------------- /internal/binding/sources/gml_error.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #include "gml_error.h" 29 | 30 | //#############// 31 | //### C API ###// 32 | //#############// 33 | 34 | gml_error gml_error_new() { 35 | try { 36 | GmlError* gerr = new GmlError(); 37 | return (gml_error)gerr; 38 | } 39 | catch (std::exception& e) { 40 | gml_error_log_exception("new gml_error: " + string(e.what())); 41 | return NULL; 42 | } 43 | catch (...) { 44 | gml_error_log_exception("new gml_error"); 45 | return NULL; 46 | } 47 | } 48 | 49 | void gml_error_free(gml_error err) { 50 | if (err == NULL) { 51 | return; 52 | } 53 | GmlError* gerr = (GmlError*)err; 54 | delete gerr; 55 | err = NULL; 56 | } 57 | 58 | void gml_error_reset(gml_error err) { 59 | try { 60 | GmlError* gerr = (GmlError*)err; 61 | gerr->msg = ""; 62 | } 63 | catch (std::exception& e) { 64 | gml_error_log_exception("reset error message: " + string(e.what())); 65 | } 66 | catch (...) { 67 | gml_error_log_exception("reset error message"); 68 | } 69 | } 70 | 71 | const char* gml_error_get_msg(gml_error err) { 72 | try { 73 | GmlError* gerr = (GmlError*)err; 74 | return gerr->msg.c_str(); 75 | } 76 | catch (std::exception& e) { 77 | gml_error_log_exception("get error message: " + string(e.what())); 78 | return NULL; 79 | } 80 | catch (...) { 81 | gml_error_log_exception("get error message"); 82 | return NULL; 83 | } 84 | } 85 | 86 | //################// 87 | //### Internal ###// 88 | //################// 89 | 90 | void gml_error_set_msg(gml_error err, const std::string& msg) { 91 | GmlError* gerr = (GmlError*)err; 92 | gerr->msg = msg; 93 | } 94 | 95 | void gml_error_set_catched_exception_msg(gml_error err) { 96 | gml_error_set_msg(err, "catched unknown exception"); 97 | } 98 | 99 | void gml_error_log_exception(const string& msg) { 100 | if (msg == "") { 101 | cerr << "gml: catched unknown exception" << endl; 102 | } else { 103 | cerr << "gml: catched exception: " << msg << endl; 104 | } 105 | } -------------------------------------------------------------------------------- /internal/binding/sources/gml_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_ERROR_H 29 | #define GML_ERROR_H 30 | 31 | #include "gml_includes.h" 32 | 33 | struct GmlError { 34 | string msg; 35 | }; 36 | 37 | void gml_error_set_msg(gml_error err, const string& msg); 38 | void gml_error_set_catched_exception_msg(gml_error err); 39 | void gml_error_log_exception(const string& msg = ""); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /internal/binding/sources/gml_global.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #include "gml_includes.h" 29 | #include "gml_error.h" 30 | 31 | //#############// 32 | //### C API ###// 33 | //#############// 34 | 35 | void gml_global_set_search_paths(const char* prefix, const char** paths, int paths_size) { 36 | try { 37 | QStringList list; 38 | for (int i=0; i < paths_size; ++i) { 39 | list.append(QString(paths[i])); 40 | } 41 | 42 | QDir::setSearchPaths(QString(prefix), list); 43 | } 44 | catch (std::exception& e) { 45 | gml_error_log_exception(e.what()); 46 | } 47 | catch (...) { 48 | gml_error_log_exception(); 49 | } 50 | } 51 | 52 | void gml_global_set_icon_theme_name(const char* name) { 53 | try { 54 | QIcon::setThemeName(QString(name)); 55 | } 56 | catch (std::exception& e) { 57 | gml_error_log_exception(e.what()); 58 | } 59 | catch (...) { 60 | gml_error_log_exception(); 61 | } 62 | } 63 | 64 | void gml_global_set_icon_theme_search_paths(const char** paths, int paths_size) { 65 | try { 66 | QStringList list; 67 | for (int i=0; i < paths_size; ++i) { 68 | list.append(QString(paths[i])); 69 | } 70 | 71 | QIcon::setThemeSearchPaths(list); 72 | } 73 | catch (std::exception& e) { 74 | gml_error_log_exception(e.what()); 75 | } 76 | catch (...) { 77 | gml_error_log_exception(); 78 | } 79 | } -------------------------------------------------------------------------------- /internal/binding/sources/gml_image.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #include "gml_includes.h" 29 | #include "gml_error.h" 30 | 31 | //###############// 32 | //### Private ###// 33 | //###############// 34 | 35 | void gml_image_cleanup(void *data) { 36 | free(data); 37 | } 38 | 39 | //#############// 40 | //### C API ###// 41 | //#############// 42 | 43 | gml_image gml_image_new() { 44 | try { 45 | QImage* qImg = new QImage(); 46 | return (gml_image)qImg; 47 | } 48 | catch (std::exception& e) { 49 | gml_error_log_exception(e.what()); 50 | return NULL; 51 | } 52 | catch (...) { 53 | gml_error_log_exception(); 54 | return NULL; 55 | } 56 | } 57 | 58 | void gml_image_free(gml_image img) { 59 | if (img == NULL) { 60 | return; 61 | } 62 | QImage* qImg = (QImage*)img; 63 | delete qImg; 64 | img = NULL; 65 | } 66 | 67 | void gml_image_reset(gml_image img) { 68 | try { 69 | QImage* qImg = (QImage*)img; 70 | *qImg = QImage(); 71 | } 72 | catch (std::exception& e) { 73 | gml_error_log_exception(e.what()); 74 | } 75 | catch (...) { 76 | gml_error_log_exception(); 77 | } 78 | } 79 | 80 | void gml_image_copy(gml_image img, gml_image dst, int x, int y, int width, int height) { 81 | try { 82 | QImage* qImg = (QImage*)img; 83 | QImage* qDst = (QImage*)dst; 84 | *qDst = qImg->copy(x, y, width, height); 85 | } 86 | catch (std::exception& e) { 87 | gml_error_log_exception(e.what()); 88 | } 89 | catch (...) { 90 | gml_error_log_exception(); 91 | } 92 | } 93 | 94 | void gml_image_set_to(gml_image img, gml_image other) { 95 | try { 96 | QImage* qImg = (QImage*)img; 97 | QImage* qImgOther = (QImage*)other; 98 | *qImg = *qImgOther; 99 | } 100 | catch (std::exception& e) { 101 | gml_error_log_exception(e.what()); 102 | } 103 | catch (...) { 104 | gml_error_log_exception(); 105 | } 106 | } 107 | 108 | int gml_image_load_from_file(gml_image img, const char* filename, gml_error err) { 109 | try { 110 | QImage* qImg = (QImage*)img; 111 | *qImg = QImage(QString(filename)); 112 | if (qImg->isNull()) { 113 | gml_error_set_msg(err, "failed to load image from file"); 114 | return -1; 115 | } 116 | return 0; 117 | } 118 | catch (std::exception& e) { 119 | gml_error_set_msg(err, e.what()); 120 | return -1; 121 | } 122 | catch (...) { 123 | gml_error_set_catched_exception_msg(err); 124 | return -1; 125 | } 126 | } 127 | 128 | int gml_image_load_from_rgba(gml_image img, const char* cdata, int size, int width, int height, int stride, gml_error err) { 129 | try { 130 | QImage* qImg = (QImage*)img; 131 | 132 | // Create a copy of the data. 133 | uchar* data = (uchar*)(malloc(size)); 134 | if (data == NULL) { 135 | throw std::runtime_error("failed to malloc image memory"); 136 | } 137 | memcpy(data, cdata, size); 138 | 139 | *qImg = QImage(data, width, height, stride, QImage::Format_RGBA8888, &gml_image_cleanup, data); 140 | return 0; 141 | } 142 | catch (std::exception& e) { 143 | gml_error_set_msg(err, e.what()); 144 | return -1; 145 | } 146 | catch (...) { 147 | gml_error_set_catched_exception_msg(err); 148 | return -1; 149 | } 150 | } 151 | 152 | int gml_image_load_from_data(gml_image img, const char* data, int size, gml_error err) { 153 | try { 154 | QImage* qImg = (QImage*)img; 155 | qImg->loadFromData((const unsigned char*)(data), size); 156 | if (qImg->isNull()) { 157 | gml_error_set_msg(err, "failed to load image from data"); 158 | return -1; 159 | } 160 | return 0; 161 | } 162 | catch (std::exception& e) { 163 | gml_error_set_msg(err, e.what()); 164 | return -1; 165 | } 166 | catch (...) { 167 | gml_error_set_catched_exception_msg(err); 168 | return -1; 169 | } 170 | } 171 | 172 | int gml_image_height(gml_image img) { 173 | try { 174 | return ((QImage*)img)->height(); 175 | } 176 | catch (std::exception& e) { 177 | gml_error_log_exception(e.what()); 178 | return -1; 179 | } 180 | catch (...) { 181 | gml_error_log_exception(); 182 | return -1; 183 | } 184 | } 185 | 186 | int gml_image_width(gml_image img) { 187 | try { 188 | return ((QImage*)img)->width(); 189 | } 190 | catch (std::exception& e) { 191 | gml_error_log_exception(e.what()); 192 | return -1; 193 | } 194 | catch (...) { 195 | gml_error_log_exception(); 196 | return -1; 197 | } 198 | } 199 | 200 | int gml_image_is_empty(gml_image img) { 201 | try { 202 | if (((QImage*)img)->isNull()) { 203 | return 1; 204 | } else { 205 | return 0; 206 | } 207 | } 208 | catch (std::exception& e) { 209 | gml_error_log_exception(e.what()); 210 | return -1; 211 | } 212 | catch (...) { 213 | gml_error_log_exception(); 214 | return -1; 215 | } 216 | } -------------------------------------------------------------------------------- /internal/binding/sources/gml_image_item.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #include "gml_image_item.h" 29 | 30 | //########################// 31 | //### Static Variables ###// 32 | //########################// 33 | 34 | gml_image_item_request_cb_t gml_image_item_request_cb = NULL; 35 | 36 | //#############// 37 | //### C API ###// 38 | //#############// 39 | 40 | void gml_image_item_request_cb_register(gml_image_item_request_cb_t cb) { 41 | gml_image_item_request_cb = cb; 42 | } 43 | 44 | void gml_image_item_emit_changed(const char* id) { 45 | try { 46 | emit GmlApp::App()->imageItemChanged(QString(id)); 47 | } 48 | catch (std::exception& e) { 49 | gml_error_log_exception(e.what()); 50 | } 51 | catch (...) { 52 | gml_error_log_exception(); 53 | } 54 | } 55 | 56 | //##########################// 57 | //### GmlImageItem Class ###// 58 | //##########################// 59 | 60 | GmlImageItem::GmlImageItem(QQuickItem *parent) : 61 | QQuickPaintedItem(parent), 62 | src(""), 63 | transformationMode(Qt::FastTransformation), 64 | aspectRatioMode(Qt::KeepAspectRatio), 65 | imgX(0), imgY(0), 66 | imgWidth(0), imgHeight(0) 67 | { 68 | QObject::connect(GmlApp::App(), &GmlApp::imageItemChanged, 69 | this, &GmlImageItem::onImageItemChanged); 70 | QObject::connect(this, &GmlImageItem::sourceChanged, 71 | this, &GmlImageItem::onSourceChanged); 72 | QObject::connect(this, &GmlImageItem::modeChanged, 73 | this, &GmlImageItem::onRequestUpdate); 74 | } 75 | 76 | QString GmlImageItem::source() const { 77 | return src; 78 | } 79 | 80 | void GmlImageItem::setSource(const QString &source) { 81 | this->src = source; 82 | emit sourceChanged(); 83 | } 84 | 85 | int GmlImageItem::imageX() { 86 | return imgX; 87 | } 88 | 89 | int GmlImageItem::imageY() { 90 | return imgY; 91 | } 92 | 93 | int GmlImageItem::imageWidth() { 94 | return imgWidth; 95 | } 96 | 97 | int GmlImageItem::imageHeight() { 98 | return imgHeight; 99 | } 100 | 101 | Qt::AspectRatioMode GmlImageItem::getAspectRatioMode() { 102 | return aspectRatioMode; 103 | } 104 | 105 | void GmlImageItem::setAspectRatioMode(const Qt::AspectRatioMode m) { 106 | aspectRatioMode = m; 107 | emit modeChanged(); 108 | } 109 | 110 | Qt::TransformationMode GmlImageItem::getTransformationMode() { 111 | return transformationMode; 112 | } 113 | 114 | void GmlImageItem::setTransformationMode(const Qt::TransformationMode m) { 115 | transformationMode = m; 116 | emit modeChanged(); 117 | } 118 | 119 | void GmlImageItem::onRequestUpdate() { 120 | update(); 121 | } 122 | 123 | void GmlImageItem::onImageItemChanged(const QString id) { 124 | if (this->src != id) { 125 | return; 126 | } 127 | 128 | onSourceChanged(); 129 | } 130 | 131 | void GmlImageItem::onSourceChanged() { 132 | // Call to go. 133 | try { 134 | gml_image_item_request_cb( 135 | src.toUtf8().data(), 136 | (gml_image)(&img) 137 | ); 138 | } 139 | catch (std::exception& e) { 140 | gml_error_log_exception("image item request: " + string(e.what())); 141 | } 142 | catch (...) { 143 | gml_error_log_exception("image item request"); 144 | } 145 | 146 | // Repaint. 147 | update(); 148 | } 149 | 150 | void GmlImageItem::paint(QPainter *painter) { 151 | if (img.isNull()) { 152 | return; 153 | } 154 | 155 | QRectF bRect = boundingRect(); 156 | QImage scaled = img.scaled(bRect.width(), bRect.height(), aspectRatioMode, transformationMode); 157 | QPointF center = bRect.center() - scaled.rect().center(); 158 | 159 | // Ensure the image is centered. 160 | if (center.x() < 0) { 161 | center.setX(0); 162 | } 163 | if (center.y() < 0) { 164 | center.setY(0); 165 | } 166 | 167 | // Notify, if the size or positions have changed. 168 | int w = scaled.width(); 169 | int h = scaled.height(); 170 | int x = (this->width() - w) / 2; 171 | int y = (this->height() - h) / 2; 172 | if (x != imgX || y != imgY || w != imgWidth || h != imgHeight) { 173 | imgX = x; 174 | imgY = y; 175 | imgWidth = w; 176 | imgHeight = h; 177 | emit imageDimensionsChanged(); 178 | } 179 | 180 | painter->drawImage(center, scaled); 181 | emit painted(); 182 | } 183 | 184 | -------------------------------------------------------------------------------- /internal/binding/sources/gml_image_item.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_IMAGE_ITEM_H 29 | #define GML_IMAGE_ITEM_H 30 | 31 | #include "gml_includes.h" 32 | #include "gml_error.h" 33 | #include "gml_app.h" 34 | 35 | class GmlImageItem : public QQuickPaintedItem 36 | { 37 | Q_OBJECT 38 | Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged) 39 | Q_PROPERTY(Qt::TransformationMode transformationMode READ getTransformationMode WRITE setTransformationMode NOTIFY modeChanged) 40 | Q_PROPERTY(Qt::AspectRatioMode aspectRatioMode READ getAspectRatioMode WRITE setAspectRatioMode NOTIFY modeChanged) 41 | Q_PROPERTY(int imageX READ imageX NOTIFY imageDimensionsChanged) 42 | Q_PROPERTY(int imageY READ imageY NOTIFY imageDimensionsChanged) 43 | Q_PROPERTY(int imageWidth READ imageWidth NOTIFY imageDimensionsChanged) 44 | Q_PROPERTY(int imageHeight READ imageHeight NOTIFY imageDimensionsChanged) 45 | 46 | public: 47 | GmlImageItem(QQuickItem *parent = nullptr); 48 | 49 | QString source() const; 50 | void setSource(const QString &source); 51 | int imageX(); 52 | int imageY(); 53 | int imageWidth(); 54 | int imageHeight(); 55 | 56 | Qt::AspectRatioMode getAspectRatioMode(); 57 | void setAspectRatioMode(const Qt::AspectRatioMode m); 58 | 59 | Qt::TransformationMode getTransformationMode(); 60 | void setTransformationMode(const Qt::TransformationMode m); 61 | 62 | void paint(QPainter *painter); 63 | 64 | signals: 65 | void sourceChanged(); 66 | void modeChanged(); 67 | void imageDimensionsChanged(); 68 | void painted(); 69 | 70 | private: 71 | QString src; 72 | QImage img; 73 | Qt::TransformationMode transformationMode; 74 | Qt::AspectRatioMode aspectRatioMode; 75 | int imgX, imgY, imgWidth, imgHeight; 76 | 77 | private slots: 78 | void onRequestUpdate(); 79 | void onImageItemChanged(const QString id); 80 | void onSourceChanged(); 81 | 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /internal/binding/sources/gml_image_provider.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #include "gml_image_provider.h" 29 | #include "gml_error.h" 30 | 31 | //########################// 32 | //### Static Variables ###// 33 | //########################// 34 | 35 | gml_image_provider_request_cb_t gml_image_provider_request_cb = NULL; 36 | 37 | //#############// 38 | //### C API ###// 39 | //#############// 40 | 41 | void gml_image_provider_request_cb_register(gml_image_provider_request_cb_t cb) { 42 | gml_image_provider_request_cb = cb; 43 | } 44 | 45 | gml_image_provider gml_image_provider_new( 46 | void* go_ptr, 47 | int aspect_ratio_mode, 48 | int transformation_mode 49 | ) { 50 | try { 51 | GmlImageProvider* gip = new GmlImageProvider( 52 | go_ptr, 53 | static_cast(aspect_ratio_mode), 54 | static_cast(transformation_mode) 55 | ); 56 | return (gml_image_provider)gip; 57 | } 58 | catch (std::exception& e) { 59 | gml_error_log_exception(e.what()); 60 | return NULL; 61 | } 62 | catch (...) { 63 | gml_error_log_exception(); 64 | return NULL; 65 | } 66 | } 67 | 68 | void gml_image_provider_free(gml_image_provider ip) { 69 | if (ip == NULL) { 70 | return; 71 | } 72 | GmlImageProvider* gip = (GmlImageProvider*)ip; 73 | delete gip; 74 | ip = NULL; 75 | } 76 | 77 | void gml_image_response_emit_finished(gml_image_response img_resp, char* error_string) { 78 | try { 79 | GmlAsyncImageResponse* gimg_resp = (GmlAsyncImageResponse*)img_resp; 80 | gimg_resp->finalize(QString(error_string)); 81 | } 82 | catch (std::exception& e) { 83 | gml_error_log_exception("image response: emit finished: " + string(e.what())); 84 | } 85 | catch (...) { 86 | gml_error_log_exception("image response: emit finished"); 87 | } 88 | } 89 | 90 | //###################################// 91 | //### GmlAsyncImageResponse Class ###// 92 | //###################################// 93 | 94 | GmlAsyncImageResponse::GmlAsyncImageResponse( 95 | void* ipGoPtr, 96 | const QString &id, 97 | const QSize &requestedSize, 98 | Qt::AspectRatioMode aspectRatioMode, 99 | Qt::TransformationMode transformMode 100 | ) : 101 | ipGoPtr(ipGoPtr), 102 | requestedSize(requestedSize), 103 | aspectRatioMode(aspectRatioMode), 104 | transformMode(transformMode) 105 | { 106 | // Call to go. 107 | try { 108 | gml_image_provider_request_cb( 109 | ipGoPtr, 110 | (gml_image_response)(this), 111 | id.toUtf8().data(), 112 | (gml_image)(&img) 113 | ); 114 | } 115 | catch (std::exception& e) { 116 | gml_error_log_exception("image async response: request: " + string(e.what())); 117 | } 118 | catch (...) { 119 | gml_error_log_exception("image async response: request"); 120 | } 121 | } 122 | 123 | QString GmlAsyncImageResponse::errorString() const { 124 | return errorStr; 125 | } 126 | 127 | QQuickTextureFactory* GmlAsyncImageResponse::textureFactory() const { 128 | return QQuickTextureFactory::textureFactoryForImage(img); 129 | } 130 | 131 | void GmlAsyncImageResponse::finalize(const QString& errorString) { 132 | // Check for an error. 133 | if (!errorString.isEmpty()) { 134 | errorStr = errorString; 135 | } else if (!requestedSize.isNull() && requestedSize.isValid()) { 136 | // Resize the image to the requested size 137 | img = img.scaled(requestedSize, Qt::IgnoreAspectRatio, transformMode); 138 | } 139 | 140 | // Emit the finished signal. 141 | emit finished(); 142 | } 143 | 144 | //###########################// 145 | //### ImageProvider Class ###// 146 | //###########################// 147 | 148 | GmlImageProvider::GmlImageProvider( 149 | void* goPtr, 150 | Qt::AspectRatioMode aspectRatioMode, 151 | Qt::TransformationMode transformMode 152 | ) : 153 | goPtr(goPtr), 154 | aspectRatioMode(aspectRatioMode), 155 | transformMode(transformMode) 156 | {} 157 | 158 | QQuickImageResponse* GmlImageProvider::requestImageResponse( 159 | const QString &id, 160 | const QSize &requestedSize 161 | ) { 162 | return new GmlAsyncImageResponse(goPtr, id, requestedSize, aspectRatioMode, transformMode); 163 | } 164 | -------------------------------------------------------------------------------- /internal/binding/sources/gml_image_provider.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_IMAGE_PROVIDER_H 29 | #define GML_IMAGE_PROVIDER_H 30 | 31 | #include "gml_includes.h" 32 | 33 | class GmlAsyncImageResponse : public QQuickImageResponse 34 | { 35 | public: 36 | GmlAsyncImageResponse( 37 | void* ipGoPtr, 38 | const QString &id, 39 | const QSize &requestedSize, 40 | Qt::AspectRatioMode aspectRatioMode, 41 | Qt::TransformationMode transformMode 42 | ); 43 | 44 | QQuickTextureFactory* textureFactory() const override; 45 | QString errorString() const override; 46 | 47 | void finalize(const QString& errorString); 48 | 49 | private: 50 | void* ipGoPtr; 51 | QImage img; 52 | QSize requestedSize; 53 | QString errorStr; 54 | Qt::AspectRatioMode aspectRatioMode; 55 | Qt::TransformationMode transformMode; 56 | }; 57 | 58 | class GmlImageProvider : public QQuickAsyncImageProvider 59 | { 60 | public: 61 | GmlImageProvider( 62 | void* goPtr, 63 | Qt::AspectRatioMode aspectRatioMode, 64 | Qt::TransformationMode transformMode 65 | ); 66 | 67 | QQuickImageResponse* requestImageResponse( 68 | const QString& id, 69 | const QSize& requestedSize 70 | ) override; 71 | 72 | private: 73 | void* goPtr; 74 | Qt::AspectRatioMode aspectRatioMode; 75 | Qt::TransformationMode transformMode; 76 | }; 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /internal/binding/sources/gml_includes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_INCLUDES_H 29 | #define GML_INCLUDES_H 30 | 31 | #include "../headers/gml.h" 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | 60 | using std::string; 61 | using std::cout; 62 | using std::cerr; 63 | using std::endl; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /internal/binding/sources/gml_list_model.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | #ifndef GML_LIST_MODEL_H 29 | #define GML_LIST_MODEL_H 30 | 31 | #include "gml_includes.h" 32 | #include "gml_error.h" 33 | 34 | class GmlListModel : public QAbstractListModel { 35 | Q_OBJECT 36 | public: 37 | GmlListModel( 38 | void* goPtr 39 | ); 40 | 41 | int rowCount(const QModelIndex& parent) const override; 42 | QVariant data(const QModelIndex& index, int role) const override; 43 | 44 | void emitBeginResetModel(); 45 | void emitEndResetModel(); 46 | 47 | void emitBeginInsertRows(int row, int count); 48 | void emitEndInsertRows(); 49 | 50 | void emitBeginMoveRows(int row, int count, int dstRow); 51 | void emitEndMoveRows(); 52 | 53 | void emitRowsDataChanged(int row, int count); 54 | 55 | void emitBeginRemoveRows(int row, int count); 56 | void emitEndRemoveRows(); 57 | 58 | private: 59 | void* goPtr; 60 | }; 61 | 62 | #endif -------------------------------------------------------------------------------- /internal/build/build.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package build 29 | 30 | import ( 31 | "fmt" 32 | "go/build" 33 | "os" 34 | "strings" 35 | 36 | "github.com/desertbit/gml/internal/utils" 37 | ) 38 | 39 | const ( 40 | PostHookName = "GML_BUILD_POST_HOOKS" 41 | ) 42 | 43 | func Build(rootDir, sourceDir, buildDir, destDir, qtModules string, clean, noStrip, debugBuild, race bool, tags, buildvcs string) (err error) { 44 | // Force no strip if this is a debug build. 45 | if debugBuild { 46 | noStrip = true 47 | } 48 | 49 | // Convert the comma separated qt modules list to a whitespace separated one. 50 | qtModules = strings.Join(strings.Split(qtModules, ","), " ") 51 | 52 | ctx, err := newContext(rootDir, sourceDir, buildDir, destDir, qtModules, clean, debugBuild) 53 | if err != nil { 54 | return 55 | } 56 | 57 | // Prepare the qt project. 58 | utils.PrintColorln("> preparing project") 59 | err = prepareQtProject(ctx) 60 | if err != nil { 61 | return 62 | } 63 | 64 | // Prepare the resources. 65 | utils.PrintColorln("> preparing resources") 66 | err = prepareResources(ctx) 67 | if err != nil { 68 | return 69 | } 70 | 71 | // Generate C, C++ and go files. 72 | utils.PrintColorln("> generating source files") 73 | err = generate(ctx) 74 | if err != nil { 75 | return 76 | } 77 | 78 | // Build the static C lib. 79 | utils.PrintColorln("> building C source") 80 | err = buildCLib(ctx) 81 | if err != nil { 82 | return 83 | } 84 | 85 | // Run go build. 86 | utils.PrintColorln("> building Go source") 87 | err = buildGo(ctx, tags, clean, noStrip, race, buildvcs) 88 | if err != nil { 89 | return 90 | } 91 | 92 | // Run post hooks if available. 93 | err = runPostHooks(ctx) 94 | if err != nil { 95 | return 96 | } 97 | 98 | return 99 | } 100 | 101 | func buildCLib(ctx *Context) (err error) { 102 | err = utils.RunCommand(ctx.Env(), ctx.BuildDir, "qmake") 103 | if err != nil { 104 | return fmt.Errorf("qmake failed: %v", err) 105 | } 106 | 107 | err = utils.RunCommand(ctx.Env(), ctx.BuildDir, "make") 108 | if err != nil { 109 | return fmt.Errorf("make failed: %v", err) 110 | } 111 | 112 | return 113 | } 114 | 115 | func buildGo(ctx *Context, tags string, clean, noStrip, race bool, buildvcs string) (err error) { 116 | // Delete the output binary to force relinking. 117 | // This is faster than building with the -a option. 118 | e, err := utils.Exists(ctx.OutputFile) 119 | if err != nil { 120 | return 121 | } else if e { 122 | err = os.Remove(ctx.OutputFile) 123 | if err != nil { 124 | return 125 | } 126 | } 127 | 128 | var ( 129 | ldflags []string 130 | args = []string{"build", "-o", ctx.OutputFile} 131 | ) 132 | 133 | if buildvcs != "" { 134 | args = append(args, fmt.Sprintf("-buildvcs=%s", buildvcs)) 135 | } 136 | if clean { 137 | args = append(args, "-a") 138 | } 139 | if !noStrip { 140 | args = append(args, "-trimpath") 141 | ldflags = append(ldflags, "-s", "-w") 142 | } 143 | if ctx.DebugBuild { 144 | ldflags = append(ldflags, "-compressdwarf=false") 145 | } 146 | if race { 147 | args = append(args, "-race") 148 | } 149 | if utils.Verbose { 150 | args = append(args, "-v") 151 | } 152 | 153 | // Add the go build tags if defined. 154 | tags = strings.TrimSpace(tags) 155 | if len(tags) > 0 { 156 | args = append(args, "-tags", tags) 157 | } 158 | 159 | // Hide the terminal window on windows bullshit systems. 160 | if build.Default.GOOS == "windows" { 161 | ldflags = append(ldflags, "-H=windowsgui") 162 | } 163 | 164 | // Combine ldflags passed by arguments. 165 | if len(ldflags) > 0 { 166 | args = append(args, "-ldflags", strings.Join(ldflags, " ")) 167 | } 168 | 169 | // Don't overwrite already set cgo flags. 170 | // Let's extend them. 171 | osEnv := os.Environ() 172 | cgoLDFLAGS := "CGO_LDFLAGS=" 173 | cgoCFLAGS := "CGO_CFLAGS=" 174 | for _, e := range osEnv { 175 | if strings.HasPrefix(e, "CGO_LDFLAGS=") { 176 | cgoLDFLAGS = e 177 | } else if strings.HasPrefix(e, "CGO_CFLAGS=") { 178 | cgoCFLAGS = e 179 | } 180 | } 181 | cgoLDFLAGS += " " + ctx.StaticLibPath 182 | cgoCFLAGS += " -I" + ctx.CGenIncludeDir + " -I" + ctx.GmlBindingHeadersDir 183 | 184 | env := ctx.Env(cgoLDFLAGS, cgoCFLAGS) 185 | if utils.Verbose { 186 | fmt.Println("build environment variables:", env) 187 | } 188 | 189 | err = utils.RunCommand( 190 | env, 191 | ctx.SourceDir, 192 | "go", args..., 193 | ) 194 | return 195 | } 196 | 197 | func runPostHooks(ctx *Context) (err error) { 198 | var value string 199 | 200 | for _, e := range os.Environ() { 201 | pair := strings.Split(e, "=") 202 | if len(pair) != 2 || pair[0] != PostHookName { 203 | continue 204 | } 205 | value = pair[1] 206 | break 207 | } 208 | if value == "" { 209 | return 210 | } 211 | 212 | utils.PrintColorln("> running post hooks") 213 | 214 | scripts := strings.Split(value, ",") 215 | for _, script := range scripts { 216 | script = strings.TrimSpace(script) 217 | if script == "" { 218 | continue 219 | } 220 | 221 | err = utils.RunCommand( 222 | ctx.Env( 223 | "GML_SOURCE_DIR="+ctx.SourceDir, 224 | "GML_BUILD_DIR="+ctx.BuildDir, 225 | "GML_DEST_DIR="+ctx.DestDir, 226 | "GML_DEST_BINARY="+ctx.OutputFile, 227 | ), 228 | ctx.DestDir, 229 | script, 230 | ) 231 | if err != nil { 232 | return 233 | } 234 | } 235 | 236 | return 237 | } 238 | -------------------------------------------------------------------------------- /internal/build/generate.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package build 29 | 30 | import ( 31 | "io/ioutil" 32 | "os" 33 | "path/filepath" 34 | ) 35 | 36 | const ( 37 | genGoFilename = "gml_gen.go" 38 | ) 39 | 40 | type genTargets struct { 41 | Packages []*genPackage 42 | } 43 | 44 | type genPackage struct { 45 | PackageName string 46 | Dir string 47 | Structs []*genStruct 48 | } 49 | 50 | type genStruct struct { 51 | Name string 52 | CBaseName string 53 | CPPBaseName string 54 | Signals []*genSignal 55 | Slots []*genSlot 56 | Properties []*genProperty 57 | AdditionalType string 58 | } 59 | 60 | type genSignal struct { 61 | Name string 62 | EmitName string 63 | CPPName string 64 | Params []*genParam 65 | } 66 | 67 | type genSlot struct { 68 | Name string 69 | CPPName string 70 | Params []*genParam 71 | 72 | NoRet bool 73 | RetType string 74 | CGoRetType string 75 | CRetType string 76 | CPPRetType string 77 | } 78 | 79 | type genProperty struct { 80 | Name string 81 | PublicName string 82 | CPPName string 83 | SetName string 84 | 85 | Type string 86 | CType string 87 | CPPType string 88 | 89 | Silent bool 90 | } 91 | 92 | type genParam struct { 93 | Name string 94 | Type string 95 | CType string 96 | CGoType string 97 | CPPType string 98 | } 99 | 100 | // TODO: make concurrent with multiple goroutines. 101 | func generate(ctx *Context) (err error) { 102 | gt, err := parseDirRecursive(ctx) 103 | if err != nil { 104 | return 105 | } 106 | 107 | // Create dummies if no C & C++ files will be generated. 108 | if len(gt.Packages) == 0 { 109 | return generateDummyFiles(ctx) 110 | } 111 | 112 | err = generateCMainHeader(gt, ctx.CGenIncludeDir) 113 | if err != nil { 114 | return 115 | } 116 | 117 | for _, gp := range gt.Packages { 118 | err = generateGoFile(gp) 119 | if err != nil { 120 | return 121 | } 122 | 123 | err = generateCHeaderFile(gp, ctx.CGenDir) 124 | if err != nil { 125 | return 126 | } 127 | 128 | err = generateCPPHeaderFile(gp, ctx.CPPGenDir) 129 | if err != nil { 130 | return 131 | } 132 | 133 | err = generateCPPSourceFile(gp, ctx.CPPGenDir) 134 | if err != nil { 135 | return 136 | } 137 | } 138 | return 139 | } 140 | 141 | // Create dummy files, because otherwise make fill fail if there are no sources files present. 142 | // QMake is configured with a *.cpp & *.h 143 | func generateDummyFiles(ctx *Context) (err error) { 144 | err = ioutil.WriteFile(filepath.Join(ctx.CGenDir, "_dummy.h"), []byte("// Dummy File"), 0755) 145 | if err != nil { 146 | return 147 | } 148 | 149 | err = ioutil.WriteFile(filepath.Join(ctx.CPPGenDir, "_dummy.h"), []byte("// Dummy File"), 0755) 150 | if err != nil { 151 | return 152 | } 153 | 154 | err = ioutil.WriteFile(filepath.Join(ctx.CPPGenDir, "_dummy.cpp"), []byte("// Dummy File"), 0755) 155 | return 156 | } 157 | 158 | // This shoult be in a separate directory, so no unnecessary files are in the global include dir. 159 | func generateCMainHeader(gt *genTargets, genDir string) (err error) { 160 | filename := filepath.Join(genDir, "gml_gen.h") 161 | 162 | // Create the file. 163 | f, err := os.Create(filename) 164 | if err != nil { 165 | return 166 | } 167 | defer func() { 168 | derr := f.Close() 169 | if derr != nil && err == nil { 170 | err = derr 171 | } 172 | }() 173 | 174 | return cMainHeaderTmpl.Execute(f, gt) 175 | } 176 | 177 | func generateGoFile(gp *genPackage) (err error) { 178 | filename := filepath.Join(gp.Dir, genGoFilename) 179 | 180 | // Create the file. 181 | f, err := os.Create(filename) 182 | if err != nil { 183 | return 184 | } 185 | defer func() { 186 | derr := f.Close() 187 | if derr != nil && err == nil { 188 | err = derr 189 | } 190 | }() 191 | 192 | return goTmpl.Execute(f, gp) 193 | } 194 | 195 | func generateCHeaderFile(gp *genPackage, genDir string) (err error) { 196 | filename := filepath.Join(genDir, gp.PackageName+".h") 197 | 198 | // Create the file. 199 | f, err := os.Create(filename) 200 | if err != nil { 201 | return 202 | } 203 | defer func() { 204 | derr := f.Close() 205 | if derr != nil && err == nil { 206 | err = derr 207 | } 208 | }() 209 | 210 | return cHeaderTmpl.Execute(f, gp) 211 | } 212 | 213 | func generateCPPSourceFile(gp *genPackage, genDir string) (err error) { 214 | filename := filepath.Join(genDir, gp.PackageName+".cpp") 215 | 216 | // Create the file. 217 | f, err := os.Create(filename) 218 | if err != nil { 219 | return 220 | } 221 | defer func() { 222 | derr := f.Close() 223 | if derr != nil && err == nil { 224 | err = derr 225 | } 226 | }() 227 | 228 | return cppSourceTmpl.Execute(f, gp) 229 | } 230 | 231 | func generateCPPHeaderFile(gp *genPackage, genDir string) (err error) { 232 | filename := filepath.Join(genDir, gp.PackageName+".h") 233 | 234 | // Create the file. 235 | f, err := os.Create(filename) 236 | if err != nil { 237 | return 238 | } 239 | defer func() { 240 | derr := f.Close() 241 | if derr != nil && err == nil { 242 | err = derr 243 | } 244 | }() 245 | 246 | return cppHeaderTmpl.Execute(f, gp) 247 | } 248 | -------------------------------------------------------------------------------- /internal/build/qtproject.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package build 29 | 30 | import ( 31 | "os" 32 | "text/template" 33 | ) 34 | 35 | var qtProTmpl = template.Must(template.New("t").Parse(qtProData)) 36 | 37 | func prepareQtProject(ctx *Context) (err error) { 38 | // Create or open the config file. 39 | f, err := os.Create(ctx.QtProFile) 40 | if err != nil { 41 | return 42 | } 43 | defer func() { 44 | derr := f.Close() 45 | if derr != nil && err == nil { 46 | err = derr 47 | } 48 | }() 49 | 50 | return qtProTmpl.Execute(f, &ctx) 51 | } 52 | 53 | const qtProData = ` 54 | QT += core qml quick widgets {{ .QTModules }} 55 | 56 | TEMPLATE = lib 57 | 58 | {{ if .DebugBuild -}} 59 | CONFIG += debug staticlib c++11 60 | {{- else -}} 61 | CONFIG += release staticlib c++11 62 | {{- end}} 63 | 64 | win32|win64 { 65 | {{ if .DebugBuild -}} 66 | Debug:DESTDIR = {{.BuildDir}} 67 | {{- else -}} 68 | Release:DESTDIR = {{.BuildDir}} 69 | {{- end}} 70 | } 71 | 72 | INCLUDEPATH += {{.GmlBindingDir}}/headers 73 | 74 | HEADERS += {{.GmlBindingHeadersDir}}/*.h {{.GmlBindingSourcesDir}}/*.h {{.CGenDir}}/*.h {{.CPPGenDir}}/*.h 75 | SOURCES += {{.GmlBindingSourcesDir}}/*.cpp {{.CPPGenDir}}/*.cpp 76 | RESOURCES += {{.QMLResFile}} 77 | 78 | OBJECTS_DIR = {{.BuildDir}} 79 | MOC_DIR = {{.BuildDir}} 80 | UI_DIR = {{.BuildDir}} 81 | DESTDIR = {{.BuildDir}} 82 | TARGET = gml 83 | ` 84 | -------------------------------------------------------------------------------- /internal/build/resources.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package build 29 | 30 | import ( 31 | "os" 32 | "path/filepath" 33 | "strings" 34 | "text/template" 35 | ) 36 | 37 | var qmlResTmpl = template.Must(template.New("t").Parse(qmlResData)) 38 | 39 | type resource struct { 40 | FilePath string 41 | Alias string 42 | } 43 | 44 | func prepareResources(ctx *Context) (err error) { 45 | // Create the resources file. 46 | f, err := os.Create(ctx.QMLResFile) 47 | if err != nil { 48 | return 49 | } 50 | defer func() { 51 | derr := f.Close() 52 | if derr != nil && err == nil { 53 | err = derr 54 | } 55 | }() 56 | 57 | resources := make([]resource, 0) 58 | 59 | // Define a walk func used to walk over all files in our qml and resources dirs. 60 | walkFunc := func(path string, info os.FileInfo, err error) error { 61 | if err != nil { 62 | return err 63 | } 64 | 65 | // Ignore any hidden files or directories. 66 | if strings.HasPrefix(info.Name(), ".") { 67 | if info.IsDir() { 68 | return filepath.SkipDir 69 | } 70 | return nil 71 | } 72 | 73 | // Add any file that we encounter to the resources, but relative to our 74 | // directory where the .qrc file lies within. 75 | if !info.IsDir() { 76 | res := resource{ 77 | FilePath: strings.TrimPrefix(path, ctx.SourceDir+"/"), 78 | } 79 | 80 | if info.Name() == "qtquickcontrols2.conf" { 81 | res.Alias = "qtquickcontrols2.conf" 82 | } 83 | resources = append(resources, res) 84 | } 85 | 86 | return nil 87 | } 88 | 89 | // Scan first the qml directory and add all files found within 90 | // to our resources file. 91 | err = filepath.Walk(ctx.QMLDir, walkFunc) 92 | if err != nil { 93 | return 94 | } 95 | 96 | // Do the same for the resources directory. 97 | err = filepath.Walk(ctx.QMLResDir, walkFunc) 98 | if err != nil { 99 | return 100 | } 101 | 102 | // Write the contents of our template with the paths to the file. 103 | return qmlResTmpl.Execute(f, resources) 104 | } 105 | 106 | const qmlResData = ` 107 | 108 | 109 | {{- range .}} 110 | {{.FilePath}} 111 | {{- end}} 112 | 113 | ` 114 | -------------------------------------------------------------------------------- /internal/build/template_c.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package build 29 | 30 | import "text/template" 31 | 32 | var cMainHeaderTmpl = template.Must(template.New("t").Funcs(tmplFuncMap).Parse(cMainHeaderTmplText)) 33 | 34 | const cMainHeaderTmplText = `// This file is auto-generated by gml. 35 | #ifndef GML_GEN_C_INCLUDE_H 36 | #define GML_GEN_C_INCLUDE_H 37 | 38 | {{ range .Packages}} 39 | #include "../{{.PackageName}}.h" 40 | {{- end}} 41 | 42 | #endif 43 | ` 44 | 45 | var cHeaderTmpl = template.Must(template.New("t").Funcs(tmplFuncMap).Parse(cHeaderTmplText)) 46 | 47 | const cHeaderTmplText = `// This file is auto-generated by gml. 48 | #ifndef GML_GEN_C_{{.PackageName}}_H 49 | #define GML_GEN_C_{{.PackageName}}_H 50 | 51 | #include 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | {{/* Struct loop */ -}} 58 | {{range $struct := .Structs -}} 59 | //### 60 | //### {{$struct.Name}} 61 | //### 62 | 63 | typedef void* {{$struct.CBaseName}}; 64 | 65 | {{$struct.CBaseName}} {{$struct.CBaseName}}_new(void* go_ptr); 66 | void {{$struct.CBaseName}}_free({{$struct.CBaseName}}); 67 | 68 | {{- /* Signals */ -}} 69 | {{- range $signal := $struct.Signals }} 70 | void {{$struct.CBaseName}}_{{$signal.Name}}({{$struct.CBaseName}} _v{{cParams $signal.Params true false}}); 71 | {{end}} 72 | 73 | {{- /* Slots */ -}} 74 | {{- range $slot := $struct.Slots }} 75 | typedef {{$slot.CRetType}} (*{{$struct.CBaseName}}_{{$slot.Name}}_cb_t)(void* _go_ptr{{cParams $slot.Params true false}}); 76 | void {{$struct.CBaseName}}_{{$slot.Name}}_cb_register({{$struct.CBaseName}}_{{$slot.Name}}_cb_t cb); 77 | {{end}} 78 | 79 | {{- /* Properties */ -}} 80 | {{- range $prop := $struct.Properties }} 81 | {{if not $prop.Silent -}} 82 | typedef void (*{{$struct.CBaseName}}_{{$prop.Name}}_changed_cb_t)(void* go_ptr); 83 | void {{$struct.CBaseName}}_{{$prop.Name}}_cb_register({{$struct.CBaseName}}_{{$prop.Name}}_changed_cb_t cb); 84 | {{- end}} 85 | 86 | {{$prop.CType}} {{$struct.CBaseName}}_{{$prop.Name}}_get({{$struct.CBaseName}} c); 87 | void {{$struct.CBaseName}}_{{$prop.Name}}_set({{$struct.CBaseName}} c, {{$prop.CType}} v); 88 | {{end}} 89 | 90 | {{- /* End of struct loop */ -}} 91 | {{- end}} 92 | 93 | #ifdef __cplusplus 94 | } 95 | #endif 96 | 97 | #endif 98 | ` 99 | -------------------------------------------------------------------------------- /internal/build/template_go.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package build 29 | 30 | import "text/template" 31 | 32 | var goTmpl = template.Must(template.New("t").Funcs(tmplFuncMap).Parse(goTmplText)) 33 | 34 | const goTmplText = `// This file is auto-generated by gml. 35 | package {{.PackageName}} 36 | 37 | /* 38 | #cgo pkg-config: Qt5Core Qt5Qml Qt5Quick 39 | #cgo LDFLAGS: -lstdc++ 40 | #include 41 | #include 42 | 43 | {{- /* Register with go functions */}} 44 | {{range $struct := .Structs}} 45 | 46 | {{- range $slot := $struct.Slots }} 47 | extern {{$slot.CRetType}} {{$struct.CBaseName}}_{{$slot.Name}}_go_slot(void* _goPtr{{cParams $slot.Params true false}}); 48 | {{end -}} 49 | {{- range $prop := $struct.Properties }}{{if not $prop.Silent}} 50 | extern void {{$struct.CBaseName}}_{{$prop.Name}}_go_prop_changed(void* _goPtr); 51 | {{end}}{{end}} 52 | static void {{$struct.CBaseName}}_register() { 53 | {{- range $slot := $struct.Slots }} 54 | {{$struct.CBaseName}}_{{$slot.Name}}_cb_register({{$struct.CBaseName}}_{{$slot.Name}}_go_slot); 55 | {{end -}} 56 | {{- range $prop := $struct.Properties }}{{if not $prop.Silent}} 57 | {{$struct.CBaseName}}_{{$prop.Name}}_cb_register({{$struct.CBaseName}}_{{$prop.Name}}_go_prop_changed); 58 | {{end}}{{end -}} 59 | } 60 | 61 | {{- end}} 62 | */ 63 | import "C" 64 | import ( 65 | "unsafe" 66 | "runtime" 67 | 68 | "github.com/desertbit/gml" 69 | "github.com/desertbit/gml/pointer" 70 | ) 71 | 72 | // Force to use the gml package. The import is not always required... 73 | var _ = gml.Object{} 74 | 75 | {{/* Struct loop */ -}} 76 | {{range $struct := .Structs}} 77 | //### 78 | //### {{$struct.Name}} 79 | //### 80 | 81 | {{/* Init */ -}} 82 | func init() { 83 | C.{{$struct.CBaseName}}_register() 84 | } 85 | 86 | func (_v *{{$struct.Name}}) GmlInit() { 87 | goPtr := pointer.Save(_v) 88 | _v.GmlObject_SetGoPointer(goPtr) 89 | _v.GmlObject_SetPointer(unsafe.Pointer(C.{{$struct.CBaseName}}_new(goPtr))) 90 | runtime.SetFinalizer(_v, func(_v *{{$struct.Name}}) { 91 | C.{{$struct.CBaseName}}_free((C.{{$struct.CBaseName}})(_v.GmlObject_Pointer())) 92 | pointer.Unref(goPtr) 93 | }) 94 | } 95 | 96 | {{- /* Signals */}} 97 | {{range $signal := $struct.Signals }} 98 | func (_v *{{$struct.Name}}) {{$signal.EmitName}}({{goParams $signal.Params true true}}) { 99 | _ptr := (C.{{$struct.CBaseName}})(_v.GmlObject_Pointer()) 100 | {{- goToCParams $signal.Params "_c_" true 4}} 101 | C.{{$struct.CBaseName}}_{{$signal.Name}}(_ptr{{goParams $signal.Params false false "_c_"}}) 102 | } 103 | {{end}} 104 | 105 | {{- /* Slots */ -}} 106 | {{range $slot := $struct.Slots }} 107 | //export {{$struct.CBaseName}}_{{$slot.Name}}_go_slot 108 | func {{$struct.CBaseName}}_{{$slot.Name}}_go_slot(_goPtr unsafe.Pointer{{goCParams $slot.Params true false}}) {{$slot.CGoRetType}} { 109 | _v := (pointer.Restore(_goPtr)).(*{{$struct.Name}}) 110 | {{- cToGoParams $slot.Params "_go_" 4}} 111 | 112 | {{ if $slot.NoRet -}} 113 | _v.{{$slot.Name}}({{goParams $slot.Params false true "_go_"}}) 114 | {{- else -}} 115 | _r := _v.{{$slot.Name}}({{goParams $slot.Params false true "_go_"}}) 116 | {{- goToCValue $slot.RetType "_r" "_rc" false 4}} 117 | return _rc 118 | {{- end}} 119 | } 120 | {{end}} 121 | 122 | {{- /* Properties */ -}} 123 | {{range $prop := $struct.Properties }} 124 | func (_v *{{$struct.Name}}) {{$prop.SetName}}(v {{$prop.Type}}) { 125 | _ptr := (C.{{$struct.CBaseName}})(_v.GmlObject_Pointer()) 126 | {{- goToCValue $prop.Type "v" "vc" true 4}} 127 | gml.RunMain(func() { 128 | C.{{$struct.CBaseName}}_{{$prop.Name}}_set(_ptr, vc) 129 | }) 130 | } 131 | 132 | func (_v *{{$struct.Name}}) {{$prop.Name}}() (r {{$prop.Type}}) { 133 | _ptr := (C.{{$struct.CBaseName}})(_v.GmlObject_Pointer()) 134 | gml.RunMain(func() { 135 | v := C.{{$struct.CBaseName}}_{{$prop.Name}}_get(_ptr) 136 | {{- cToGoValue $prop.Type "vg" "v" 8}} 137 | r = vg 138 | }) 139 | return 140 | } 141 | 142 | {{if not $prop.Silent}} 143 | //export {{$struct.CBaseName}}_{{$prop.Name}}_go_prop_changed 144 | func {{$struct.CBaseName}}_{{$prop.Name}}_go_prop_changed(_goPtr unsafe.Pointer) { 145 | _v := (pointer.Restore(_goPtr)).(*{{$struct.Name}}) 146 | _v.on{{$prop.PublicName}}Changed() 147 | } 148 | {{end}} 149 | {{- end}} 150 | 151 | {{- /* End of struct loop */ -}} 152 | {{- end}} 153 | ` 154 | -------------------------------------------------------------------------------- /internal/docker/context.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package docker 29 | 30 | import ( 31 | "fmt" 32 | "go/build" 33 | "os" 34 | "path/filepath" 35 | "strings" 36 | 37 | "github.com/desertbit/gml/internal/utils" 38 | ) 39 | 40 | type Context struct { 41 | RootDir string 42 | SourceDir string 43 | SourceDirRel string 44 | BuildDir string 45 | DestDir string 46 | 47 | GoPath string 48 | 49 | CGoLDFLAGS string 50 | CGoCFLAGS string 51 | } 52 | 53 | func newContext(rootDir, sourceDir, buildDir, destDir string) (ctx *Context, err error) { 54 | // Get absolute paths. 55 | rootDir, err = filepath.Abs(rootDir) 56 | if err != nil { 57 | return 58 | } 59 | destDir, err = filepath.Abs(destDir) 60 | if err != nil { 61 | return 62 | } 63 | 64 | // Source and build dir are relative to the root dir. 65 | // Construct the absolute paths now. 66 | sourceDirRel := sourceDir 67 | sourceDir, err = filepath.Abs(filepath.Join(rootDir, sourceDir)) 68 | if err != nil { 69 | return 70 | } 71 | buildDir, err = filepath.Abs(filepath.Join(rootDir, buildDir)) 72 | if err != nil { 73 | return 74 | } 75 | 76 | // Obtain the current GOPATH. 77 | goPathEnv := os.Getenv("GOPATH") 78 | if goPathEnv == "" { 79 | goPathEnv = build.Default.GOPATH 80 | } 81 | goPaths := strings.Split(goPathEnv, ":") 82 | if len(goPaths) == 0 { 83 | err = fmt.Errorf("invalid GOPATH") 84 | return 85 | } 86 | goPath := goPaths[0] 87 | 88 | // Set the bin name. 89 | binName := filepath.Base(sourceDir) 90 | if binName == "" || binName == "." { 91 | binName = "gml-app" 92 | } 93 | 94 | // Obtain the cgo flags from the current environment. 95 | osEnv := os.Environ() 96 | cgoLDFLAGS := "CGO_LDFLAGS=" 97 | cgoCFLAGS := "CGO_CFLAGS=" 98 | for _, e := range osEnv { 99 | if strings.HasPrefix(e, "CGO_LDFLAGS=") { 100 | cgoLDFLAGS = e 101 | } else if strings.HasPrefix(e, "CGO_CFLAGS=") { 102 | cgoCFLAGS = e 103 | } 104 | } 105 | 106 | ctx = &Context{ 107 | RootDir: rootDir, 108 | SourceDir: sourceDir, 109 | SourceDirRel: sourceDirRel, 110 | BuildDir: buildDir, 111 | DestDir: destDir, 112 | GoPath: goPath, 113 | CGoLDFLAGS: cgoLDFLAGS, 114 | CGoCFLAGS: cgoCFLAGS, 115 | } 116 | 117 | err = ctx.createDirsIfNotExists() 118 | if err != nil { 119 | return 120 | } 121 | 122 | err = ctx.checkForRequiredDirs() 123 | return 124 | } 125 | 126 | func (c *Context) createDirsIfNotExists() (err error) { 127 | dirs := []string{ 128 | c.BuildDir, 129 | c.DestDir, 130 | c.GoPath, 131 | } 132 | 133 | for _, d := range dirs { 134 | err = os.MkdirAll(d, 0755) 135 | if err != nil { 136 | return 137 | } 138 | } 139 | return 140 | } 141 | 142 | func (c *Context) checkForRequiredDirs() (err error) { 143 | dirs := []string{ 144 | c.SourceDir, 145 | } 146 | 147 | for _, d := range dirs { 148 | e, err := utils.Exists(d) 149 | if err != nil { 150 | return err 151 | } else if !e { 152 | return fmt.Errorf("required directory does not exists: '%s'", d) 153 | } 154 | } 155 | return 156 | } 157 | -------------------------------------------------------------------------------- /internal/docker/docker.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package docker 29 | 30 | import ( 31 | "fmt" 32 | "os" 33 | "os/exec" 34 | "os/user" 35 | "path/filepath" 36 | "strings" 37 | 38 | "github.com/desertbit/gml/internal/utils" 39 | "github.com/desertbit/go-shlex" 40 | "golang.org/x/crypto/ssh/terminal" 41 | ) 42 | 43 | const ( 44 | containerPrefix = "desertbit/gml:" 45 | ) 46 | 47 | var ( 48 | containers = []string{ 49 | "linux", 50 | "windows_32_static", 51 | "windows_64_static", 52 | "windows_32_shared", 53 | "windows_64_shared", 54 | } 55 | ) 56 | 57 | func Containers() []string { 58 | return containers 59 | } 60 | 61 | func Build( 62 | container string, 63 | rootDir, sourceDir, buildDir, destDir, qtModules string, 64 | clean, noStrip, debugBuild, race, customContainer bool, 65 | tags, dockerArgs, buildvcs string, 66 | ) (err error) { 67 | if !customContainer { 68 | err = checkIfValidContainer(container) 69 | if err != nil { 70 | return 71 | } 72 | container = containerPrefix + container 73 | } 74 | 75 | // Obtain the build architecture. 76 | var arch string 77 | pos := strings.Index(container, ":") 78 | if pos > 0 { 79 | arch = strings.TrimSpace(container[pos+1:]) 80 | } 81 | 82 | ctx, err := newContext( 83 | rootDir, sourceDir, 84 | filepath.Join(buildDir, arch), 85 | filepath.Join(destDir, arch), 86 | ) 87 | if err != nil { 88 | return 89 | } 90 | 91 | utils.PrintColorln("> docker build: " + container) 92 | 93 | usr, err := user.Current() 94 | if err != nil { 95 | return 96 | } 97 | 98 | // Only add the -t docker flag if this is a TTY. 99 | var ttyArg string 100 | if terminal.IsTerminal(int(os.Stdout.Fd())) { 101 | ttyArg = "t" 102 | } 103 | 104 | args := []string{ 105 | "run", "--rm", "-i" + ttyArg, 106 | "-e", "UID=" + usr.Uid, 107 | "-e", "GID=" + usr.Gid, 108 | "-e", "GOBIN=/work/bin", 109 | "-e", "GOPATH=/gopath", 110 | "-e", "GOCACHE=/work/build/go-cache", 111 | "-e", ctx.CGoLDFLAGS, 112 | "-e", ctx.CGoCFLAGS, 113 | "-v", ctx.GoPath + ":/gopath", 114 | "-v", ctx.RootDir + ":/work", 115 | "-v", ctx.BuildDir + ":/work/build", 116 | "-v", ctx.DestDir + ":/work/bin", 117 | } 118 | 119 | if ctx.SourceDir != ctx.RootDir { 120 | args = append(args, "-v", ctx.SourceDir+":"+filepath.Join("/work", ctx.SourceDirRel)) 121 | } 122 | 123 | // Add the custom docker arguments. 124 | dockerArgsSplit, err := shlex.Split(dockerArgs, true) 125 | if err != nil { 126 | err = fmt.Errorf("failed to parse custom docker arguments: %w", err) 127 | return 128 | } 129 | args = append(args, dockerArgsSplit...) 130 | 131 | // Container and gml command. 132 | args = append(args, container, "gml") 133 | 134 | if utils.Verbose { 135 | args = append(args, "-v") 136 | } 137 | 138 | args = append(args, "build", 139 | "--root-dir", "/work", 140 | "--source-dir", ctx.SourceDirRel, 141 | "--build-dir", "build/gml-build", 142 | "--dest-dir", "/work/bin", 143 | "--qt-modules", qtModules, 144 | "--buildvcs", buildvcs) 145 | 146 | if clean { 147 | args = append(args, "--clean") 148 | } 149 | if noStrip { 150 | args = append(args, "--no-strip") 151 | } 152 | if debugBuild { 153 | args = append(args, "--debug") 154 | } 155 | if race { 156 | args = append(args, "--race") 157 | } 158 | 159 | // Add the tags if defined. 160 | tags = strings.TrimSpace(tags) 161 | if len(tags) > 0 { 162 | args = append(args, "--tags", tags) 163 | } 164 | 165 | c := exec.Command("docker", args...) 166 | c.Dir = ctx.BuildDir 167 | c.Stderr = os.Stderr 168 | c.Stdout = os.Stdout 169 | c.Stdin = os.Stdin 170 | 171 | return c.Run() 172 | } 173 | 174 | func Pull(container string) (err error) { 175 | err = checkIfValidContainer(container) 176 | if err != nil { 177 | return 178 | } 179 | 180 | c := exec.Command("docker", "pull", containerPrefix+container) 181 | c.Stderr = os.Stderr 182 | c.Stdout = os.Stdout 183 | 184 | return c.Run() 185 | } 186 | 187 | func checkIfValidContainer(container string) error { 188 | for _, c := range containers { 189 | if c == container { 190 | return nil 191 | } 192 | } 193 | return fmt.Errorf("invalid container: %s", container) 194 | } 195 | -------------------------------------------------------------------------------- /internal/json/json.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | /* 29 | json-iterator (https://github.com/json-iterator/go) seems to be even faster 30 | than easyjson (https://github.com/mailru/easyjson) and does not require code 31 | generation, but is in fact a 100% drop-in replacement for encoding/json. 32 | */ 33 | package json 34 | 35 | import ( 36 | jsoniter "github.com/json-iterator/go" 37 | ) 38 | 39 | func Marshal(v interface{}) (data []byte, err error) { 40 | return jsoniter.Marshal(v) 41 | } 42 | 43 | func Unmarshal(data []byte, v interface{}) (err error) { 44 | return jsoniter.Unmarshal(data, v) 45 | } 46 | -------------------------------------------------------------------------------- /internal/utils/path.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package utils 29 | 30 | import ( 31 | "errors" 32 | "fmt" 33 | "go/build" 34 | "io/ioutil" 35 | "os" 36 | "path/filepath" 37 | "strings" 38 | ) 39 | 40 | const ( 41 | // TODO: maybe use reflect.TypeOf(*ctx).PkgPath() ? 42 | goImportPath = "github.com/desertbit/gml" 43 | ) 44 | 45 | func FindModPath(dir string) (path string, err error) { 46 | for { 47 | path = filepath.Join(dir, "go.mod") 48 | if fi, err := os.Stat(path); err == nil && !fi.IsDir() { 49 | return path, nil 50 | } 51 | 52 | parent := filepath.Dir(dir) 53 | if parent == dir { 54 | break 55 | } 56 | dir = parent 57 | } 58 | 59 | return "", errors.New("go.mod not found") 60 | } 61 | 62 | func FindBindingPath(projectRootDir string) (path string, err error) { 63 | projectRootDir, err = filepath.Abs(projectRootDir) 64 | if err != nil { 65 | return 66 | } 67 | 68 | goModFilePath, err := FindModPath(projectRootDir) 69 | if err != nil { 70 | return 71 | } 72 | 73 | // Obtain the import path including the version from the go.mod file. 74 | data, err := ioutil.ReadFile(goModFilePath) 75 | if err != nil { 76 | return 77 | } 78 | 79 | lines := strings.Split(string(data), "\n") 80 | for _, line := range lines { 81 | if !strings.Contains(line, goImportPath) { 82 | continue 83 | } 84 | 85 | // Remove comments from the line first. 86 | pos := strings.Index(line, "//") 87 | if pos >= 0 { 88 | line = line[:pos] 89 | } 90 | 91 | fields := strings.Fields(strings.TrimPrefix(strings.TrimSpace(line), "require")) 92 | if len(fields) != 2 || fields[0] != goImportPath { 93 | continue 94 | } 95 | 96 | path = fields[0] + "@" + fields[1] 97 | break 98 | } 99 | 100 | if path == "" { 101 | err = fmt.Errorf("failed to find gml import in go.mod file") 102 | return 103 | } 104 | 105 | // Obtain the current GOPATH. 106 | goPathEnv := os.Getenv("GOPATH") 107 | if goPathEnv == "" { 108 | goPathEnv = build.Default.GOPATH 109 | } 110 | goPaths := strings.Split(goPathEnv, ":") 111 | if len(goPaths) == 0 { 112 | err = fmt.Errorf("invalid GOPATH") 113 | return 114 | } 115 | goPath := goPaths[0] 116 | 117 | // Our final binding path. 118 | path = filepath.Join(goPath, "pkg", "mod", path, "internal", "binding") 119 | 120 | // Ensure it exists. 121 | e, err := Exists(path) 122 | if err != nil { 123 | return 124 | } else if !e { 125 | err = fmt.Errorf("gml binding path does not exists: '%s'", path) 126 | return 127 | } 128 | 129 | return 130 | } 131 | -------------------------------------------------------------------------------- /internal/utils/print.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package utils 29 | 30 | import ( 31 | "fmt" 32 | 33 | "github.com/fatih/color" 34 | ) 35 | 36 | var ( 37 | Verbose bool 38 | ) 39 | 40 | func PrintColor(s string) { 41 | color.Set(color.FgHiGreen) 42 | fmt.Print(s) 43 | color.Unset() 44 | } 45 | 46 | func PrintColorln(s string) { 47 | PrintColor(s + "\n") 48 | } 49 | -------------------------------------------------------------------------------- /internal/utils/utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package utils 29 | 30 | import ( 31 | "fmt" 32 | "io" 33 | "io/ioutil" 34 | "os" 35 | "os/exec" 36 | "path/filepath" 37 | "unicode" 38 | ) 39 | 40 | // Exists returns whether the given file or directory exists. 41 | func Exists(path string) (bool, error) { 42 | _, err := os.Lstat(path) 43 | if err == nil { 44 | return true, nil 45 | } 46 | if os.IsNotExist(err) { 47 | return false, nil 48 | } 49 | return false, err 50 | } 51 | 52 | func RunCommand(env []string, dir, cmd string, args ...string) (err error) { 53 | c := exec.Command(cmd, args...) 54 | c.Dir = dir 55 | c.Env = env 56 | 57 | // TODO: also log to a log file. 58 | c.Stderr = os.Stderr 59 | if Verbose { 60 | c.Stdout = os.Stdout 61 | } 62 | 63 | return c.Run() 64 | } 65 | 66 | func FirstCharToLower(s string) string { 67 | if len(s) == 0 { 68 | return "" 69 | } 70 | 71 | // Ensure first char is lower case. 72 | sr := []rune(s) 73 | sr[0] = unicode.ToLower(rune(sr[0])) 74 | return string(sr) 75 | } 76 | 77 | func FirstCharToUpper(s string) string { 78 | if len(s) == 0 { 79 | return "" 80 | } 81 | 82 | // Ensure first char is lower case. 83 | sr := []rune(s) 84 | sr[0] = unicode.ToUpper(rune(sr[0])) 85 | return string(sr) 86 | } 87 | 88 | // CopyFile copies the contents of the file named src to the file named 89 | // by dst. The file will be created if it does not already exist. If the 90 | // destination file exists, all it's contents will be replaced by the contents 91 | // of the source file. The file mode will be copied from the source and 92 | // the copied data is synced/flushed to stable storage. 93 | func CopyFile(src, dst string, sync bool) (err error) { 94 | in, err := os.Open(src) 95 | if err != nil { 96 | return 97 | } 98 | defer in.Close() 99 | 100 | out, err := os.Create(dst) 101 | if err != nil { 102 | return 103 | } 104 | defer func() { 105 | if e := out.Close(); e != nil { 106 | err = e 107 | } 108 | }() 109 | 110 | _, err = io.Copy(out, in) 111 | if err != nil { 112 | return 113 | } 114 | 115 | if sync { 116 | err = out.Sync() 117 | if err != nil { 118 | return 119 | } 120 | } 121 | 122 | si, err := os.Stat(src) 123 | if err != nil { 124 | return 125 | } 126 | err = os.Chmod(dst, si.Mode()) 127 | if err != nil { 128 | return 129 | } 130 | 131 | return 132 | } 133 | 134 | // CopyDir recursively copies a directory tree, attempting to preserve permissions. 135 | // Source directory must exist, destination directory must *not* exist. 136 | // Symlinks are ignored and skipped. 137 | func CopyDir(src string, dst string, sync bool) (err error) { 138 | src = filepath.Clean(src) 139 | dst = filepath.Clean(dst) 140 | 141 | si, err := os.Stat(src) 142 | if err != nil { 143 | return err 144 | } 145 | if !si.IsDir() { 146 | return fmt.Errorf("source is not a directory") 147 | } 148 | 149 | _, err = os.Stat(dst) 150 | if err != nil && !os.IsNotExist(err) { 151 | return 152 | } 153 | if err == nil { 154 | return fmt.Errorf("destination already exists") 155 | } 156 | 157 | err = os.MkdirAll(dst, si.Mode()) 158 | if err != nil { 159 | return 160 | } 161 | 162 | entries, err := ioutil.ReadDir(src) 163 | if err != nil { 164 | return 165 | } 166 | 167 | for _, entry := range entries { 168 | srcPath := filepath.Join(src, entry.Name()) 169 | dstPath := filepath.Join(dst, entry.Name()) 170 | 171 | if entry.IsDir() { 172 | err = CopyDir(srcPath, dstPath, sync) 173 | if err != nil { 174 | return 175 | } 176 | } else { 177 | // Skip symlinks. 178 | if entry.Mode()&os.ModeSymlink != 0 { 179 | continue 180 | } 181 | 182 | err = CopyFile(srcPath, dstPath, sync) 183 | if err != nil { 184 | return 185 | } 186 | } 187 | } 188 | 189 | return 190 | } 191 | -------------------------------------------------------------------------------- /internal/utils/utils_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package utils 29 | 30 | import ( 31 | "runtime" 32 | "sync" 33 | "testing" 34 | ) 35 | 36 | func TestGetThreadID(t *testing.T) { 37 | var wg sync.WaitGroup 38 | n := 10 39 | idChan := make(chan int, n) 40 | 41 | runtime.GOMAXPROCS(n) 42 | runtime.LockOSThread() 43 | 44 | wg.Add(n) 45 | for i := 0; i < n; i++ { 46 | go func() { 47 | defer wg.Done() 48 | runtime.LockOSThread() 49 | idChan <- GetThreadID() 50 | }() 51 | } 52 | 53 | wg.Wait() 54 | 55 | lastID := -1 56 | for i := 0; i < n; i++ { 57 | nextID := <-idChan 58 | if lastID == nextID { 59 | t.Error(lastID, nextID) 60 | } 61 | lastID = nextID 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /internal/utils/utils_unix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | /* 4 | * GML - Go QML 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Copyright (c) 2019 Roland Singer 9 | * Copyright (c) 2019 Sebastian Borchers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | */ 29 | 30 | package utils 31 | 32 | import "syscall" 33 | 34 | func GetThreadID() int { 35 | return syscall.Gettid() 36 | } 37 | -------------------------------------------------------------------------------- /internal/utils/utils_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | /* 4 | * GML - Go QML 5 | * 6 | * The MIT License (MIT) 7 | * 8 | * Copyright (c) 2019 Roland Singer 9 | * Copyright (c) 2019 Sebastian Borchers 10 | * 11 | * Permission is hereby granted, free of charge, to any person obtaining a copy 12 | * of this software and associated documentation files (the "Software"), to deal 13 | * in the Software without restriction, including without limitation the rights 14 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | * copies of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be included in all 19 | * copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | */ 29 | 30 | package utils 31 | 32 | import ( 33 | "golang.org/x/sys/windows" 34 | ) 35 | 36 | func GetThreadID() int { 37 | return int(windows.GetCurrentThreadId()) 38 | } 39 | -------------------------------------------------------------------------------- /listmodel.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | // #include 31 | // 32 | // extern int gml_list_model_row_count_go_slot(void* goPtr); 33 | // extern gml_variant gml_list_model_data_go_slot(void* goPtr, int row); 34 | // static void gml_list_model_init() { 35 | // gml_list_model_cb_register( 36 | // gml_list_model_row_count_go_slot, 37 | // gml_list_model_data_go_slot 38 | // ); 39 | // } 40 | import "C" 41 | import ( 42 | "fmt" 43 | "runtime" 44 | "unsafe" 45 | 46 | "github.com/desertbit/gml/pointer" 47 | ) 48 | 49 | func init() { 50 | C.gml_list_model_init() 51 | } 52 | 53 | type listModelInitializer interface { 54 | initListModel(handler ListModelHandler) 55 | } 56 | 57 | type ListModelHandler interface { 58 | RowCount() int 59 | Data(row int) interface{} 60 | } 61 | 62 | type ListModel struct { 63 | Object 64 | 65 | ptr C.gml_list_model 66 | handler ListModelHandler 67 | } 68 | 69 | func InitListModel(m interface{}) { 70 | lmi, ok := m.(listModelInitializer) 71 | if !ok { 72 | panic(fmt.Errorf("failed to assert to list model")) 73 | } 74 | 75 | handler, ok := m.(ListModelHandler) 76 | if !ok { 77 | panic(fmt.Errorf("failed to assert to list model handler")) 78 | } 79 | 80 | lmi.initListModel(handler) 81 | } 82 | 83 | func (lm *ListModel) initListModel(handler ListModelHandler) { 84 | lm.handler = handler 85 | 86 | // If signals, slots or properties are defined on the model handler, 87 | // then use the generated C++ type by calling GmlInit... 88 | // Otherwise this is a standalone ListModel. 89 | switch ht := lm.handler.(type) { 90 | case objectInitializer: 91 | ht.GmlInit() 92 | lm.ptr = (C.gml_list_model)(lm.GmlObject_Pointer()) 93 | 94 | default: 95 | handlerGoPtr := pointer.Save(lm.handler) 96 | lm.GmlObject_SetGoPointer(handlerGoPtr) 97 | 98 | lm.ptr = C.gml_list_model_new(handlerGoPtr) 99 | lm.GmlObject_SetPointer(unsafe.Pointer(lm.ptr)) 100 | 101 | // Always cleanup. 102 | runtime.SetFinalizer(lm, func(lm *ListModel) { 103 | C.gml_list_model_free(lm.ptr) 104 | pointer.Unref(handlerGoPtr) 105 | }) 106 | } 107 | 108 | // Check if something failed. 109 | // This should never happen. It signalizes a fatal error. 110 | if lm.ptr == nil { 111 | panic(fmt.Errorf("failed to create gml list model: C pointer is nil")) 112 | } 113 | } 114 | 115 | func (lm *ListModel) Reset(dataModifier func()) { 116 | RunMain(func() { 117 | // Begin the reset operation. 118 | C.gml_list_model_begin_reset_model(lm.ptr) 119 | // Perform the data modifications. 120 | dataModifier() 121 | // End the reset operation. 122 | C.gml_list_model_end_reset_model(lm.ptr) 123 | }) 124 | } 125 | 126 | func (lm *ListModel) Insert(row, count int, dataModifier func()) { 127 | RunMain(func() { 128 | // Begin the insert operation. 129 | C.gml_list_model_begin_insert_rows(lm.ptr, C.int(row), C.int(count)) 130 | // Perform the data modification. 131 | dataModifier() 132 | // End the insert operation. 133 | C.gml_list_model_end_insert_rows(lm.ptr) 134 | }) 135 | } 136 | 137 | func (lm *ListModel) Move(row, count, dstRow int, dataModifier func()) { 138 | RunMain(func() { 139 | // Begin the move operation. 140 | C.gml_list_model_begin_move_rows(lm.ptr, C.int(row), C.int(count), C.int(dstRow)) 141 | // Perform the data modification. 142 | dataModifier() 143 | // End the move operation. 144 | C.gml_list_model_end_move_rows(lm.ptr) 145 | }) 146 | } 147 | 148 | func (lm *ListModel) Reload(row, count int, dataModifier func()) { 149 | RunMain(func() { 150 | // Perform the data modification. 151 | dataModifier() 152 | // Signal the changed operation. 153 | C.gml_list_model_rows_data_changed(lm.ptr, C.int(row), C.int(count)) 154 | }) 155 | } 156 | 157 | func (lm *ListModel) Remove(row, count int, dataModifier func()) { 158 | RunMain(func() { 159 | // Begin the remove operation. 160 | C.gml_list_model_begin_remove_rows(lm.ptr, C.int(row), C.int(count)) 161 | // Perform the data modification. 162 | dataModifier() 163 | // End the remove operation. 164 | C.gml_list_model_end_remove_rows(lm.ptr) 165 | }) 166 | } 167 | 168 | //#####################// 169 | //### Exported to C ###// 170 | //#####################// 171 | 172 | //export gml_list_model_row_count_go_slot 173 | func gml_list_model_row_count_go_slot(goPtr unsafe.Pointer) C.int { 174 | return C.int((pointer.Restore(goPtr)).(ListModelHandler).RowCount()) 175 | } 176 | 177 | //export gml_list_model_data_go_slot 178 | func gml_list_model_data_go_slot(goPtr unsafe.Pointer, row C.int) C.gml_variant { 179 | data := (pointer.Restore(goPtr)).(ListModelHandler).Data(int(row)) 180 | 181 | v := ToVariant(data) 182 | // Release, because C++ is handling memory. 183 | v.Release() 184 | 185 | return v.ptr 186 | } 187 | -------------------------------------------------------------------------------- /object.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | // #include 31 | import "C" 32 | 33 | import ( 34 | "fmt" 35 | "unsafe" 36 | ) 37 | 38 | type objectInitializer interface { 39 | GmlInit() 40 | } 41 | 42 | type objectGetter interface { 43 | GmlObject() *Object 44 | } 45 | 46 | type Object struct { 47 | ptr unsafe.Pointer 48 | goPtr unsafe.Pointer 49 | } 50 | 51 | func (o *Object) GmlObject_Pointer() unsafe.Pointer { 52 | if o.ptr == nil { 53 | panic(fmt.Errorf("gml.Object pointer is nil: did you call GmlInit()?")) 54 | } 55 | return o.ptr 56 | } 57 | 58 | func (o *Object) GmlObject_SetPointer(ptr unsafe.Pointer) { 59 | o.ptr = ptr 60 | } 61 | 62 | func (o *Object) GmlObject_GoPointer() unsafe.Pointer { 63 | if o.goPtr == nil { 64 | panic(fmt.Errorf("gml.Object go pointer is nil: did you call GmlInit()?")) 65 | } 66 | return o.goPtr 67 | } 68 | 69 | func (o *Object) GmlObject_SetGoPointer(goPtr unsafe.Pointer) { 70 | o.goPtr = goPtr 71 | } 72 | 73 | func (o *Object) GmlObject() *Object { 74 | return o 75 | } 76 | 77 | func (o *Object) cObject() C.gml_object { 78 | return (C.gml_object)(o.GmlObject_Pointer()) 79 | } 80 | 81 | func toObject(i interface{}) (o *Object, err error) { 82 | switch v := i.(type) { 83 | case *Object: 84 | o = v 85 | case objectGetter: 86 | o = v.GmlObject() 87 | case nil: 88 | err = fmt.Errorf("failed to get object: value is nil") 89 | default: 90 | err = fmt.Errorf("failed to get object: unknown type: %T", v) 91 | } 92 | 93 | if o == nil && err == nil { 94 | err = fmt.Errorf("failed to get object: object pointer is nil") 95 | } 96 | return 97 | } 98 | -------------------------------------------------------------------------------- /pointer/pointer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | // Package pointer is based on: https://github.com/desertbit/go-pointer 29 | package pointer 30 | 31 | // #include 32 | import "C" 33 | import ( 34 | "sync" 35 | "unsafe" 36 | ) 37 | 38 | var ( 39 | mutex sync.Mutex 40 | store = map[unsafe.Pointer]interface{}{} 41 | ) 42 | 43 | func Save(v interface{}) unsafe.Pointer { 44 | if v == nil { 45 | return nil 46 | } 47 | 48 | // Generate real fake C pointer. 49 | // This pointer will not store any data, but will be used for indexing purposes. 50 | // Since Go does not allow to cast dangling pointer to unsafe.Pointer, we do really allocate one byte. 51 | // Why we need indexing, because Go does not allow C code to store pointers to Go data. 52 | ptr := C.malloc(C.size_t(1)) 53 | if ptr == nil { 54 | panic("can't allocate 'cgo-pointer hack index pointer': ptr == nil") 55 | } 56 | 57 | mutex.Lock() 58 | store[ptr] = v 59 | mutex.Unlock() 60 | 61 | return ptr 62 | } 63 | 64 | func Restore(ptr unsafe.Pointer) (v interface{}) { 65 | if ptr == nil { 66 | return nil 67 | } 68 | 69 | mutex.Lock() 70 | v = store[ptr] 71 | mutex.Unlock() 72 | return 73 | } 74 | 75 | func Unref(ptr unsafe.Pointer) { 76 | if ptr == nil { 77 | return 78 | } 79 | 80 | mutex.Lock() 81 | delete(store, ptr) 82 | mutex.Unlock() 83 | 84 | C.free(ptr) 85 | } 86 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | /* 2 | * GML - Go QML 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2019 Roland Singer 7 | * Copyright (c) 2019 Sebastian Borchers 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | 28 | package gml 29 | 30 | /* 31 | #include 32 | 33 | static char** makeCharArray(int size) { 34 | return (char**)(malloc(size * sizeof(char*))); 35 | } 36 | 37 | static void setCharArrayString(char **a, char *s, int n) { 38 | a[n] = s; 39 | } 40 | 41 | static void freeCharArray(char **a, int size) { 42 | int i; 43 | for (i = 0; i < size; i++) { 44 | free(a[i]); 45 | } 46 | free(a); 47 | } 48 | */ 49 | import "C" 50 | 51 | //###############// 52 | //### Private ###// 53 | //###############// 54 | 55 | func toCharArray(ss []string) **C.char { 56 | a := C.makeCharArray(C.int(len(ss))) 57 | for i, s := range ss { 58 | C.setCharArrayString(a, C.CString(s), C.int(i)) 59 | } 60 | return a 61 | } 62 | 63 | func freeCharArray(a **C.char, size int) { 64 | C.freeCharArray(a, C.int(size)) 65 | } 66 | --------------------------------------------------------------------------------