├── .gitignore ├── .test ├── .travis.yml ├── Gopkg.lock ├── Gopkg.toml ├── LICENSE ├── Makefile ├── README.md ├── TODO ├── _example ├── action │ └── action.go ├── alignment │ └── alignment.go ├── arrow │ └── arrow.go ├── builder │ ├── builder.go │ ├── callback │ │ └── callback.go │ └── hello.ui ├── clipboard │ └── clipboard.go ├── demo │ └── demo.go ├── dnd │ └── dnd.go ├── drawable │ └── drawable.go ├── event │ └── event.go ├── example.mk ├── expander │ └── expander.go ├── iconview │ └── iconview.go ├── idle │ └── idle.go ├── listview │ └── listview.go ├── locale │ └── locale.go ├── notebook │ └── notebook.go ├── number │ └── number.go ├── sourceview │ └── sourceview.go ├── spinbutton │ └── spinbutton.go ├── statusicon │ └── statusicon.go ├── table │ └── table.go ├── textview │ └── textview.go ├── thread │ └── thread.go ├── toolbar │ └── toolbar.go ├── toolpalette │ ├── toolpalette.go │ └── turkey.jpg ├── treeview │ └── treeview.go └── twitterstream │ ├── settings.json.example │ └── twitterstream.go ├── data ├── go-gtk-logo.png ├── mattn-logo.png ├── win32-demo.png └── win32-twitter.png ├── gdk ├── gdk.go ├── gdk.go.h ├── gdk_freebsd.go ├── gdk_linux.go ├── gdk_quartz_darwin.go ├── gdk_windows.go └── gdk_x11_darwin.go ├── gdkpixbuf ├── gdkpixbuf.go └── gdkpixbuf.go.h ├── gio ├── gio.go └── gio.go.h ├── glib ├── glib.go └── glib.go.h ├── gtk ├── gtk.go ├── gtk.go.h ├── gtk_internal_test.go ├── gtk_test.go └── gtk_x11.go ├── gtkgl ├── gdkgl.go ├── gtkgl.go.h └── gtkglarea.go ├── gtksourceview ├── gtksourceview.go └── gtksourceview.go.h ├── gtkspell └── gtkspell.go ├── pango ├── pango.go └── pango.go.h └── tools ├── gogtkinfo └── gogtkinfo.go └── make_inline_pixbuf └── make_inline_pixbuf.go /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | _obj 3 | *.cgo?.* 4 | _cgo_* 5 | main 6 | *.exe 7 | tags 8 | .idea 9 | vendor 10 | 11 | # example binaries 12 | example/action/action 13 | example/alignment/alignment 14 | example/arrow/arrow 15 | example/builder/builder 16 | example/clipboard/clipboard 17 | example/demo/demo 18 | example/dnd/dnd 19 | example/drawable/drawable 20 | example/event/event 21 | example/expander/expander 22 | example/iconview/iconview 23 | example/listview/listview 24 | example/locale/locale 25 | example/notebook/notebook 26 | example/number/number 27 | example/sourceview/sourceview 28 | example/spinbutton/spinbutton 29 | example/statusicon/statusicon 30 | example/table/table 31 | example/thread/thread 32 | example/toolbar/toolbar 33 | example/treeview/treeview 34 | example/twitterstream/twitterstream 35 | 36 | coverage.txt 37 | 38 | *.swp 39 | -------------------------------------------------------------------------------- /.test: -------------------------------------------------------------------------------- 1 | make example 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.6 5 | - 1.7 6 | - 1.8 7 | - 1.9.3 8 | 9 | env: 10 | global: 11 | - DEP_VERSION="0.4.1" 12 | - secure: "ByVmoy5LqIJf/hn3G/eNasDasbTkG5jud7ZumMTUP+gdBE98/olKffQXkrfFKq1e6My5G/XVp9tTEB7fz1hKxFpOwOAr/OwTTGqXRieNZhV/YQKKepAUvQE5XxAxbiV9RqsaLCcErlvAJgidn9cJAtnjvtvSncy/k1r5DIUsZIM=" 13 | 14 | before_install: 15 | # Download the binary to bin folder in $GOPATH 16 | - curl -L -s https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 -o $GOPATH/bin/dep 17 | # Make the binary executable 18 | - chmod +x $GOPATH/bin/dep 19 | 20 | install: 21 | - dep ensure 22 | 23 | script: xvfb-run go test -v -race -coverprofile=coverage.txt -covermode=atomic ./gtk 24 | 25 | after_success: 26 | - bash <(curl -s https://codecov.io/bash) 27 | 28 | addons: 29 | apt: 30 | packages: 31 | - libgtk2.0-dev 32 | - xvfb 33 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | name = "github.com/davecgh/go-spew" 6 | packages = ["spew"] 7 | revision = "346938d642f2ec3594ed81d874461961cd0faa76" 8 | version = "v1.1.0" 9 | 10 | [[projects]] 11 | branch = "master" 12 | name = "github.com/mattn/go-pointer" 13 | packages = ["."] 14 | revision = "1d30dc4b6f28271a3bd126071d4d0363e618415b" 15 | 16 | [[projects]] 17 | name = "github.com/pmezard/go-difflib" 18 | packages = ["difflib"] 19 | revision = "792786c7400a136282c1664665ae0a8db921c6c2" 20 | version = "v1.0.0" 21 | 22 | [[projects]] 23 | name = "github.com/stretchr/testify" 24 | packages = ["assert"] 25 | revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" 26 | version = "v1.2.1" 27 | 28 | [solve-meta] 29 | analyzer-name = "dep" 30 | analyzer-version = 1 31 | inputs-digest = "a295491a6204f7afbbd0d9296cb3f5e4878c06352e31b9afdea4a19ba26aa083" 32 | solver-name = "gps-cdcl" 33 | solver-version = 1 34 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [[constraint]] 29 | branch = "master" 30 | name = "github.com/garyburd/go-oauth" 31 | 32 | [[constraint]] 33 | branch = "master" 34 | name = "github.com/mattn/go-pointer" 35 | 36 | [[constraint]] 37 | name = "github.com/stretchr/testify" 38 | version = "1.2.1" 39 | 40 | [prune] 41 | go-tests = true 42 | unused-packages = true 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Yasuhiro Matsumoto 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include _example/example.mk 2 | 3 | .DEFAULT_GOAL := all 4 | .PHONY: all 5 | all: 6 | cd pango && go get -x 7 | cd glib && go get -x 8 | cd gdk && go get -x 9 | cd gdkpixbuf && go get -x 10 | cd gtk && go get -x 11 | cd gtksourceview && go get -x 12 | #cd gtkgl && go get -x . 13 | #cd gtkspell && go get -x . 14 | 15 | .PHONY: all 16 | fmt: 17 | cd pango && go fmt . 18 | cd glib && go fmt . 19 | cd gdk && go fmt . 20 | cd gdkpixbuf && go fmt . 21 | cd gtk && go fmt . 22 | cd gtksourceview && go fmt . 23 | #cd gtkgl && go fmt . 24 | #cd gtkspell && go fmt . 25 | 26 | .PHONY: clean 27 | clean: clean-example 28 | @true 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-gtk 2 | 3 | [![Build Status](https://travis-ci.org/mattn/go-gtk.png?branch=master)](https://travis-ci.org/mattn/go-gtk) 4 | [![Codecov](https://codecov.io/gh/mattn/go-gtk/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-gtk) 5 | 6 | ## WHATS 7 | 8 | Go bindings for GTK 9 | 10 | ## SCREENSHOT 11 | 12 | ![Go GTK!](https://github.com/mattn/go-gtk/raw/gh-pages/static/images/screenshot.png "Go GTK!") 13 | 14 | ## INSTALL 15 | 16 | You can experiment with go-gtk 17 | by running the various example programs: 18 | 19 | git clone https://github.com/mattn/go-gtk 20 | cd go-gtk 21 | go get ... 22 | make example 23 | ./example/demo/demo 24 | 25 | Or 26 | 27 | go get github.com/mattn/go-gtk/gtk 28 | 29 | Don't forget, that you need the GTK-Development-Packages. 30 | 31 | If you use linux, you should install `libgtk+-2.0` and packages that depend on gtk. 32 | 33 | On Debian and Debian derived distributions you can run (as root): 34 | 35 | apt-get install libgtk2.0-dev libglib2.0-dev libgtksourceview2.0-dev 36 | 37 | If you use windows, find gtk binary packages from here: 38 | 39 | * [https://www.gtk.org/docs/installations/windows](https://www.gtk.org/docs/installations/windows) 40 | 41 | ## EMBEDDING 42 | 43 | It is possible to embed a pixbuf image with: 44 | ```sh 45 | $ go run tools/make_inline_pixbuf/make_inline_pixbuf.go logoPNG data/go-gtk-logo.png > logo.gen.go 46 | ``` 47 | 48 | And then load it with: 49 | ```go 50 | pb := gdkpixbuf.NewPixbufFromData(logoPNG) 51 | ``` 52 | 53 | ## LICENSE 54 | 55 | The library is available under the same terms and conditions as the Go, the BSD style license, and the LGPL (GNU Lesser General Public License). The idea is that if you can use Go (and Gtk) in a project, you should also be able to use go-gtk. 56 | 57 | ## AUTHOR 58 | 59 | * Yasuhiro Matsumoto 60 | 61 | ## CONTRIBUTE AUTHORS 62 | 63 | * David Roundy 64 | * Mark Andrew Gerads 65 | * Tobias Kortkamp 66 | * Mikhail Trushnikov 67 | * Federico Sogaro 68 | * Crazy2be 69 | * Daniël de Kok 70 | * Erik Lissel 71 | * Jeffrey Bolle 72 | * Leonhard Küper 73 | * Matt Joiner 74 | * SQP 75 | * Steven T 76 | * Taru Karttunen 77 | * Utkan Güngördü 78 | * matiaslina 79 | * Dag Robøle 80 | * Denis Dyakov 81 | * Giuseppe Mazzotta 82 | 83 | ## GOAL 84 | 85 | Hopefully support following widgets and methods enough to run general application. 86 | 87 | (output of tools/gogtkinfo) 88 | 89 | Main Loop and Events : 30% ( 8/ 26) 90 | GtkAccelGroup : 15% ( 3/ 19) 91 | GtkAccelMap : 0% ( 0/ 14) 92 | GtkClipboard : 29% ( 9/ 31) 93 | Drag and Drop : 11% ( 4/ 35) 94 | GtkIconTheme : 9% ( 3/ 33) 95 | GtkStockItem : 66% ( 4/ 6) 96 | Themeable Stock Images : 2% ( 1/ 42) 97 | Resource Files : 14% ( 4/ 28) 98 | GtkSettings : 40% ( 6/ 15) 99 | GtkBinding : 0% ( 0/ 14) 100 | Graphics Contexts : 0% ( 0/ 2) 101 | GtkStyle : 9% ( 6/ 64) 102 | Selections : 8% ( 4/ 47) 103 | Version Information : 0% ( 0/ 6) 104 | Testing : 0% ( 0/ 16) 105 | Filesystem Utilities : 0% ( 0/ 7) 106 | GtkDialog : 63% ( 12/ 19) 107 | GtkMessageDialog : 62% ( 5/ 8) 108 | GtkWindow : 53% ( 55/102) 109 | GtkWindowGroup : 0% ( 0/ 5) 110 | GtkAboutDialog : 90% ( 29/ 32) 111 | GtkAssistant : 91% ( 21/ 23) 112 | GtkOffscreenWindow : 0% ( 0/ 3) 113 | GtkAccelLabel : 83% ( 5/ 6) 114 | GtkImage : 32% ( 10/ 31) 115 | GtkLabel : 86% ( 39/ 45) 116 | GtkProgressBar : 100% ( 12/ 12) 117 | GtkStatusbar : 77% ( 7/ 9) 118 | GtkInfoBar : 100% ( 12/ 12) 119 | GtkStatusIcon : 68% ( 26/ 38) 120 | GtkSpinner : 100% ( 3/ 3) 121 | GtkButton : 100% ( 28/ 28) 122 | GtkCheckButton : 100% ( 3/ 3) 123 | GtkRadioButton : 100% ( 8/ 8) 124 | GtkToggleButton : 100% ( 9/ 9) 125 | GtkLinkButton : 75% ( 6/ 8) 126 | GtkScaleButton : 100% ( 9/ 9) 127 | GtkVolumeButton : 100% ( 1/ 1) 128 | GtkEntry : 44% ( 28/ 63) 129 | GtkEntryBuffer : 72% ( 8/ 11) 130 | GtkEntryCompletion : 96% ( 25/ 26) 131 | GtkHScale : 100% ( 2/ 2) 132 | GtkVScale : 100% ( 2/ 2) 133 | GtkSpinButton : 100% ( 30/ 30) 134 | GtkEditable : 100% ( 13/ 13) 135 | GtkTextIter : 25% ( 23/ 91) 136 | GtkTextMark : 0% ( 0/ 7) 137 | GtkTextBuffer : 67% ( 52/ 77) 138 | GtkTextTag : 83% ( 5/ 6) 139 | GtkTextAttributes : 100% ( 5/ 5) 140 | GtkTextTagTable : 83% ( 5/ 6) 141 | GtkTextView : 29% ( 19/ 64) 142 | GtkTreePath : 90% ( 18/ 20) 143 | GtkTreeRowReference : 60% ( 6/ 10) 144 | GtkTreeIter : 100% ( 2/ 2) 145 | GtkTreeModel : 57% ( 15/ 26) 146 | GtkTreeSelection : 78% ( 18/ 23) 147 | GtkTreeViewColumn : 61% ( 34/ 55) 148 | GtkTreeView : 19% ( 19/ 98) 149 | GtkTreeView drag-and-drop : 0% ( 0/ 7) 150 | GtkCellView : 0% ( 0/ 11) 151 | GtkIconView : 17% ( 11/ 62) 152 | GtkTreeSortable : 87% ( 7/ 8) 153 | GtkTreeModelSort : 0% ( 0/ 9) 154 | GtkTreeModelFilter : 0% ( 0/ 11) 155 | GtkCellLayout : 0% ( 0/ 9) 156 | GtkCellRenderer : 100% ( 2/ 2) 157 | GtkCellEditable : 0% ( 0/ 3) 158 | GtkCellRendererAccel : 100% ( 1/ 1) 159 | GtkCellRendererCombo : 100% ( 1/ 1) 160 | GtkCellRendererPixbuf : 100% ( 1/ 1) 161 | GtkCellRendererProgress : 100% ( 1/ 1) 162 | GtkCellRendererSpin : 100% ( 1/ 1) 163 | GtkCellRendererText : 100% ( 2/ 2) 164 | GtkCellRendererToggle : 100% ( 7/ 7) 165 | GtkCellRendererSpinner : 100% ( 1/ 1) 166 | GtkListStore : 84% ( 16/ 19) 167 | GtkTreeStore : 80% ( 17/ 21) 168 | GtkComboBox : 78% ( 30/ 38) 169 | GtkComboBoxText : 100% ( 7/ 7) 170 | GtkComboBoxEntry : 80% ( 4/ 5) 171 | GtkMenu : 48% ( 13/ 27) 172 | GtkMenuBar : 100% ( 5/ 5) 173 | GtkMenuItem : 90% ( 18/ 20) 174 | GtkImageMenuItem : 54% ( 6/ 11) 175 | GtkRadioMenuItem : 44% ( 4/ 9) 176 | GtkCheckMenuItem : 100% ( 10/ 10) 177 | GtkSeparatorMenuItem : 100% ( 1/ 1) 178 | GtkTearoffMenuItem : 100% ( 1/ 1) 179 | GtkToolShell : 0% ( 0/ 9) 180 | GtkToolbar : 63% ( 24/ 38) 181 | GtkToolItem : 76% ( 19/ 25) 182 | GtkToolPalette : 59% ( 13/ 22) 183 | GtkToolItemGroup : 47% ( 8/ 17) 184 | GtkSeparatorToolItem : 100% ( 3/ 3) 185 | GtkToolButton : 100% ( 15/ 15) 186 | GtkMenuToolButton : 85% ( 6/ 7) 187 | GtkToggleToolButton : 100% ( 5/ 5) 188 | GtkRadioToolButton : 33% ( 2/ 6) 189 | GtkUIManager : 29% ( 5/ 17) 190 | GtkActionGroup : 55% ( 11/ 20) 191 | GtkAction : 93% ( 44/ 47) 192 | GtkToggleAction : 100% ( 6/ 6) 193 | GtkRadioAction : 100% ( 5/ 5) 194 | GtkRecentAction : 75% ( 3/ 4) 195 | GtkActivatable : 66% ( 4/ 6) 196 | GtkColorButton : 100% ( 10/ 10) 197 | GtkColorSelectionDialog : 0% ( 0/ 2) 198 | GtkColorSelection : 0% ( 0/ 21) 199 | GtkHSV : 0% ( 0/ 8) 200 | GtkFileChooser : 27% ( 16/ 58) 201 | GtkFileChooserButton : 18% ( 2/ 11) 202 | GtkFileChooserDialog : 100% ( 1/ 1) 203 | GtkFileChooserWidget : 50% ( 1/ 2) 204 | GtkFileFilter : 55% ( 5/ 9) 205 | GtkFontButton : 100% ( 14/ 14) 206 | GtkFontSelection : 28% ( 4/ 14) 207 | GtkFontSelectionDialog : 100% ( 8/ 8) 208 | GtkInputDialog : 0% ( 0/ 1) 209 | GtkAlignment : 100% ( 4/ 4) 210 | GtkAspectFrame : 0% ( 0/ 2) 211 | GtkHBox : 100% ( 1/ 1) 212 | GtkVBox : 100% ( 1/ 1) 213 | GtkHButtonBox : 0% ( 0/ 5) 214 | GtkVButtonBox : 0% ( 0/ 5) 215 | GtkFixed : 100% ( 5/ 5) 216 | GtkHPaned : 100% ( 1/ 1) 217 | GtkVPaned : 100% ( 1/ 1) 218 | GtkLayout : 100% ( 12/ 12) 219 | GtkNotebook : 90% ( 50/ 55) 220 | GtkTable : 93% ( 14/ 15) 221 | GtkExpander : 87% ( 14/ 16) 222 | GtkOrientable : 0% ( 0/ 2) 223 | GtkFrame : 100% ( 9/ 9) 224 | GtkHSeparator : 100% ( 1/ 1) 225 | GtkVSeparator : 100% ( 1/ 1) 226 | GtkScrollbar : 100% ( 0/ 0) 227 | GtkHScrollbar : 100% ( 1/ 1) 228 | GtkVScrollbar : 100% ( 1/ 1) 229 | GtkScrolledWindow : 86% ( 13/ 15) 230 | GtkPrintOperation : 13% ( 5/ 36) 231 | GtkPrintContext : 18% ( 2/ 11) 232 | GtkPrintSettings : 0% ( 0/ 74) 233 | GtkPageSetup : 0% ( 0/ 25) 234 | GtkPaperSize : 0% ( 0/ 21) 235 | GtkPrinter : 0% ( 0/ 23) 236 | GtkPrintJob : 0% ( 0/ 10) 237 | GtkPrintUnixDialog : 0% ( 0/ 18) 238 | GtkPageSetupUnixDialog : 0% ( 0/ 5) 239 | GtkAdjustment : 83% ( 15/ 18) 240 | GtkArrow : 100% ( 2/ 2) 241 | GtkCalendar : 0% ( 0/ 17) 242 | GtkDrawingArea : 100% ( 2/ 2) 243 | GtkEventBox : 20% ( 1/ 5) 244 | GtkHandleBox : 0% ( 0/ 8) 245 | GtkIMContextSimple : 0% ( 0/ 2) 246 | GtkIMMulticontext : 0% ( 0/ 4) 247 | GtkSizeGroup : 100% ( 8/ 8) 248 | GtkTooltip : 60% ( 6/ 10) 249 | GtkViewport : 100% ( 9/ 9) 250 | GtkAccessible : 100% ( 3/ 3) 251 | GtkBin : 100% ( 1/ 1) 252 | GtkBox : 100% ( 11/ 11) 253 | GtkButtonBox : 0% ( 0/ 10) 254 | GtkContainer : 48% ( 16/ 33) 255 | GtkItem : 100% ( 3/ 3) 256 | GtkMenuShell : 27% ( 3/ 11) 257 | GtkMisc : 100% ( 4/ 4) 258 | GtkObject : 100% ( 2/ 2) 259 | GtkPaned : 88% ( 8/ 9) 260 | GtkRange : 53% ( 16/ 30) 261 | GtkScale : 90% ( 9/ 10) 262 | GtkSeparator : 100% ( 0/ 0) 263 | GtkWidget : 54% (101/187) 264 | GtkIMContext : 0% ( 0/ 11) 265 | GtkPlug : 0% ( 0/ 7) 266 | GtkSocket : 0% ( 0/ 5) 267 | GtkRecentManager : 0% ( 0/ 37) 268 | GtkRecentChooser : 0% ( 0/ 33) 269 | GtkRecentChooserDialog : 0% ( 0/ 2) 270 | GtkRecentChooserMenu : 0% ( 0/ 4) 271 | GtkRecentChooserWidget : 0% ( 0/ 2) 272 | GtkRecentFilter : 0% ( 0/ 12) 273 | GtkBuildable : 0% ( 0/ 10) 274 | 275 | Total progress : 48% (1539/3177) 276 | 277 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * more widgets. 2 | * main loop handling (using goroutine) (done) 3 | * split gtksourceview from gtk package (done) 4 | * copyright header in sources 5 | -------------------------------------------------------------------------------- /_example/action/action.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "unsafe" 7 | 8 | "github.com/mattn/go-gtk/glib" 9 | "github.com/mattn/go-gtk/gtk" 10 | ) 11 | 12 | func CreateWindow() *gtk.Window { 13 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 14 | window.SetDefaultSize(700, 300) 15 | vbox := gtk.NewVBox(false, 1) 16 | CreateMenuAndToolbar(window, vbox) 17 | CreateActivatableDemo(vbox) 18 | window.Add(vbox) 19 | return window 20 | } 21 | 22 | func CreateMenuAndToolbar(w *gtk.Window, vbox *gtk.VBox) { 23 | action_group := gtk.NewActionGroup("my_group") 24 | ui_manager := CreateUIManager() 25 | accel_group := ui_manager.GetAccelGroup() 26 | w.AddAccelGroup(accel_group) 27 | AddFileMenuActions(action_group) 28 | AddEditMenuActions(action_group) 29 | AddChoicesMenuActions(action_group) 30 | ui_manager.InsertActionGroup(action_group, 0) 31 | menubar := ui_manager.GetWidget("/MenuBar") 32 | vbox.PackStart(menubar, false, false, 0) 33 | toolbar := ui_manager.GetWidget("/ToolBar") 34 | vbox.PackStart(toolbar, false, false, 0) 35 | eventbox := gtk.NewEventBox() 36 | vbox.PackStart(eventbox, false, false, 0) 37 | // label := gtk.NewLabel("Right-click to see the popup menu.") 38 | // vbox.PackStart(label, false, false, 0) 39 | } 40 | 41 | func CreateActivatableDemo(vbox *gtk.VBox) { 42 | action_entry := gtk.NewAction("ActionEntry", 43 | "Button attached to Action", "", gtk.STOCK_INFO) 44 | action_entry.Connect("activate", func() { 45 | fmt.Println("Action clicked") 46 | }) 47 | frame1 := gtk.NewFrame("GtkActivatable interface demonstration") 48 | frame1.SetBorderWidth(5) 49 | hbox2 := gtk.NewHBox(false, 5) 50 | hbox2.SetSizeRequest(400, 50) 51 | hbox2.SetBorderWidth(5) 52 | button1 := gtk.NewButton() 53 | button1.SetSizeRequest(250, 0) 54 | button1.SetRelatedAction(action_entry) 55 | hbox2.PackStart(button1, false, false, 0) 56 | hbox2.PackStart(gtk.NewVSeparator(), false, false, 0) 57 | button2 := gtk.NewButtonWithLabel("Hide Action") 58 | button2.SetSizeRequest(150, 0) 59 | button2.Connect("clicked", func() { 60 | action_entry.SetVisible(false) 61 | fmt.Println("Hide Action") 62 | }) 63 | hbox2.PackStart(button2, false, false, 0) 64 | button3 := gtk.NewButtonWithLabel("Unhide Action") 65 | button3.SetSizeRequest(150, 0) 66 | button3.Connect("clicked", func() { 67 | action_entry.SetVisible(true) 68 | fmt.Println("Show Action") 69 | }) 70 | hbox2.PackStart(button3, false, false, 0) 71 | frame1.Add(hbox2) 72 | vbox.PackStart(frame1, false, true, 0) 73 | } 74 | 75 | func CreateUIManager() *gtk.UIManager { 76 | UI_INFO := ` 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | ` 112 | ui_manager := gtk.NewUIManager() 113 | ui_manager.AddUIFromString(UI_INFO) 114 | return ui_manager 115 | } 116 | 117 | func OnMenuFileNewGeneric() { 118 | fmt.Println("A File|New menu item was selected.") 119 | } 120 | 121 | func OnMenuFileQuit() { 122 | fmt.Println("quit app...") 123 | gtk.MainQuit() 124 | } 125 | 126 | func OnMenuOther(ctx *glib.CallbackContext) { 127 | v := reflect.ValueOf(ctx.Target()) 128 | if v.Kind() == reflect.Ptr { 129 | fmt.Printf("Item %s(%p) was selected", v.Elem(), v.Interface()) 130 | fmt.Println() 131 | if w, ok := v.Elem().Interface().(gtk.IWidget); ok { 132 | v := reflect.ValueOf(ctx.Target()) 133 | v2 := v.Elem() 134 | fmt.Println(v.Kind(), v2.Kind()) 135 | fmt.Println("Menu item ", w.GetName(), " was selected") 136 | } 137 | } 138 | } 139 | 140 | func OnMenuOther2(widget unsafe.Pointer, event unsafe.Pointer, 141 | data unsafe.Pointer) { 142 | fmt.Println("Menu item ", "", " was selected") 143 | } 144 | 145 | func AddFileMenuActions(action_group *gtk.ActionGroup) { 146 | action_group.AddAction(gtk.NewAction("FileMenu", "File", "", "")) 147 | 148 | action_filenewmenu := gtk.NewAction("FileNew", "", "", gtk.STOCK_NEW) 149 | action_group.AddAction(action_filenewmenu) 150 | 151 | action_new := gtk.NewAction("FileNewStandard", "_New", 152 | "Create a new file", gtk.STOCK_NEW) 153 | action_new.Connect("activate", OnMenuFileNewGeneric) 154 | action_group.AddActionWithAccel(action_new, "") 155 | 156 | action_new_foo := gtk.NewAction("FileNewFoo", "New Foo", 157 | "Create new foo", gtk.STOCK_NEW) 158 | action_new_foo.Connect("activate", OnMenuFileNewGeneric) 159 | action_group.AddAction(action_new_foo) 160 | 161 | action_new_goo := gtk.NewAction("FileNewGoo", "_New Goo", 162 | "Create new goo", gtk.STOCK_NEW) 163 | action_new_goo.Connect("activate", OnMenuFileNewGeneric) 164 | action_group.AddAction(action_new_goo) 165 | 166 | action_filequit := gtk.NewAction("FileQuit", "", "", gtk.STOCK_QUIT) 167 | action_filequit.Connect("activate", OnMenuFileQuit) 168 | action_group.AddActionWithAccel(action_filequit, "") 169 | } 170 | 171 | func AddEditMenuActions(action_group *gtk.ActionGroup) { 172 | action_group.AddAction(gtk.NewAction("EditMenu", "Edit", "", "")) 173 | 174 | action_editcopy := gtk.NewAction("EditCopy", "", "", gtk.STOCK_COPY) 175 | action_editcopy.Connect("activate", OnMenuOther) 176 | action_group.AddActionWithAccel(action_editcopy, "") 177 | 178 | action_editpaste := gtk.NewAction("EditPaste", "", "", gtk.STOCK_PASTE) 179 | action_editpaste.Connect("activate", OnMenuOther) 180 | action_group.AddActionWithAccel(action_editpaste, "") 181 | 182 | action_editsomething := gtk.NewAction("EditSomething", "Something", "", "") 183 | action_editsomething.Connect("activate", OnMenuOther) 184 | action_group.AddActionWithAccel(action_editsomething, "S") 185 | } 186 | 187 | func AddChoicesMenuActions(action_group *gtk.ActionGroup) { 188 | action_group.AddAction(gtk.NewAction("ChoicesMenu", "Choices", "", "")) 189 | 190 | var ra_list []*gtk.RadioAction 191 | ra_one := gtk.NewRadioAction("ChoiceOne", "One", "", "", 1) 192 | ra_list = append(ra_list, ra_one) 193 | 194 | ra_two := gtk.NewRadioAction("ChoiceTwo", "Two", "", "", 2) 195 | ra_list = append(ra_list, ra_two) 196 | 197 | ra_three := gtk.NewRadioAction("ChoiceThree", "Three", "", "", 2) 198 | ra_list = append(ra_list, ra_three) 199 | 200 | var sl *glib.SList 201 | for _, ra := range ra_list { 202 | ra.SetGroup(sl) 203 | sl = ra.GetGroup() 204 | action_group.AddAction(ra) 205 | } 206 | 207 | ra_last := gtk.NewToggleAction("ChoiceToggle", "Toggle", "", "") 208 | ra_last.SetActive(true) 209 | action_group.AddAction(ra_last) 210 | } 211 | 212 | func main() { 213 | gtk.Init(nil) 214 | window := CreateWindow() 215 | window.SetPosition(gtk.WIN_POS_CENTER) 216 | window.Connect("destroy", func(ctx *glib.CallbackContext) { 217 | fmt.Println("destroy pending...") 218 | gtk.MainQuit() 219 | }, "foo") 220 | window.ShowAll() 221 | gtk.Main() 222 | } 223 | -------------------------------------------------------------------------------- /_example/alignment/alignment.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mattn/go-gtk/gtk" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | gtk.Init(&os.Args) 10 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 11 | window.SetTitle("Alignment") 12 | window.Connect("destroy", gtk.MainQuit) 13 | 14 | notebook := gtk.NewNotebook() 15 | window.Add(notebook) 16 | 17 | align := gtk.NewAlignment(0.5, 0.5, 0.5, 0.5) 18 | notebook.AppendPage(align, gtk.NewLabel("Alignment")) 19 | 20 | button := gtk.NewButtonWithLabel("Hello World!") 21 | align.Add(button) 22 | 23 | fixed := gtk.NewFixed() 24 | notebook.AppendPage(fixed, gtk.NewLabel("Fixed")) 25 | 26 | button2 := gtk.NewButtonWithLabel("Pulse") 27 | fixed.Put(button2, 30, 30) 28 | 29 | progress := gtk.NewProgressBar() 30 | fixed.Put(progress, 30, 70) 31 | 32 | button.Connect("clicked", func() { 33 | progress.SetFraction(0.1 + 0.9*progress.GetFraction()) //easter egg 34 | }) 35 | button2.Connect("clicked", func() { 36 | progress.Pulse() 37 | }) 38 | 39 | window.ShowAll() 40 | window.SetSizeRequest(200, 200) 41 | 42 | gtk.Main() 43 | } 44 | -------------------------------------------------------------------------------- /_example/arrow/arrow.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mattn/go-gtk/gtk" 5 | "os" 6 | ) 7 | 8 | func createArrowButton(at gtk.ArrowType, st gtk.ShadowType) *gtk.Button { 9 | b := gtk.NewButton() 10 | a := gtk.NewArrow(at, st) 11 | 12 | b.Add(a) 13 | 14 | b.Show() 15 | a.Show() 16 | 17 | return b 18 | } 19 | 20 | func main() { 21 | gtk.Init(&os.Args) 22 | 23 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 24 | window.SetTitle("Arrow Buttons") 25 | window.Connect("destroy", gtk.MainQuit) 26 | 27 | box := gtk.NewHBox(false, 0) 28 | box.Show() 29 | window.Add(box) 30 | 31 | up := createArrowButton(gtk.ARROW_UP, gtk.SHADOW_IN) 32 | down := createArrowButton(gtk.ARROW_DOWN, gtk.SHADOW_OUT) 33 | left := createArrowButton(gtk.ARROW_LEFT, gtk.SHADOW_ETCHED_IN) 34 | right := createArrowButton(gtk.ARROW_RIGHT, gtk.SHADOW_ETCHED_OUT) 35 | 36 | box.PackStart(up, false, false, 3) 37 | box.PackStart(down, false, false, 3) 38 | box.PackStart(left, false, false, 3) 39 | box.PackStart(right, false, false, 3) 40 | 41 | up.Clicked(func() { println("↑") }) 42 | down.Clicked(func() { println("↓") }) 43 | left.Clicked(func() { println("←") }) 44 | right.Clicked(func() { println("→") }) 45 | 46 | window.Show() 47 | gtk.Main() 48 | } 49 | -------------------------------------------------------------------------------- /_example/builder/builder.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/mattn/go-gtk/_example/builder/callback" 7 | "github.com/mattn/go-gtk/gtk" 8 | ) 9 | 10 | //"github.com/mattn/go-gtk/example/builder/callback" 11 | func main() { 12 | gtk.Init(&os.Args) 13 | 14 | builder := gtk.NewBuilder() 15 | 16 | builder.AddFromFile("hello.ui") 17 | obj := builder.GetObject("window1") 18 | 19 | window := gtk.WidgetFromObject(obj) 20 | window.Show() 21 | window.Connect("destroy", gtk.MainQuit) 22 | 23 | callback.Init(builder) 24 | 25 | gtk.Main() 26 | } 27 | -------------------------------------------------------------------------------- /_example/builder/callback/callback.go: -------------------------------------------------------------------------------- 1 | package callback 2 | 3 | import ( 4 | "unsafe" 5 | 6 | "github.com/mattn/go-gtk/glib" 7 | "github.com/mattn/go-gtk/gtk" 8 | ) 9 | 10 | var aboutdialog *gtk.AboutDialog 11 | 12 | func Init(builder *gtk.Builder) { 13 | aboutdialog = >k.AboutDialog{ 14 | *(*gtk.Dialog)(unsafe.Pointer(&builder.GetObject("aboutdialog1").Object))} 15 | builder.ConnectSignalsFull(func(builder *gtk.Builder, obj *glib.GObject, sig, handler string, conn *glib.GObject, flags glib.ConnectFlags, user_data interface{}) { 16 | switch handler { 17 | case "on_imagemenuitem1_activate": 18 | obj.SignalConnect(sig, on_imagemenuitem1_activate, user_data, flags) 19 | case "on_show_aboutdialog_activate": 20 | obj.SignalConnect(sig, on_show_aboutdialog_activate, user_data, flags) 21 | case "gtk_widget_hide": 22 | obj.SignalConnect(sig, func(c *glib.CallbackContext) { 23 | gtk.WidgetFromObject(c.Target().(*glib.GObject)).Hide() 24 | }, nil, flags) 25 | } 26 | }, nil) 27 | } 28 | 29 | //export on_imagemenuitem1_activate 30 | func on_imagemenuitem1_activate() { 31 | gtk.MainQuit() 32 | } 33 | 34 | //export on_show_aboutdialog_activate 35 | func on_show_aboutdialog_activate() { 36 | aboutdialog.Run() 37 | } 38 | -------------------------------------------------------------------------------- /_example/builder/hello.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | False 7 | 5 8 | dialog 9 | go-gtk builder 10 | 0.1 11 | The library is available under the same terms and conditions as the Go, 12 | the BSD style license, and the LGPL (Lesser GNU Public License). 13 | The idea is that if you can use Go (and Gtk) in a project, you should also be able to use go-gtk. 14 | example program for go-gtk 15 | https://github.com/mattn/go-gtk 16 | Yasuhiro Matsumoto 17 | 18 | 19 | 20 | True 21 | False 22 | 2 23 | 24 | 25 | True 26 | False 27 | end 28 | 29 | 30 | False 31 | True 32 | end 33 | 0 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | True 44 | False 45 | ../../data/mattn-logo.png 46 | 47 | 48 | False 49 | builder 50 | 51 | 52 | True 53 | False 54 | 55 | 56 | True 57 | False 58 | 59 | 60 | False 61 | True 62 | False 63 | _File 64 | True 65 | 66 | 67 | True 68 | False 69 | 70 | 71 | gtk-quit 72 | False 73 | True 74 | False 75 | True 76 | True 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | False 87 | True 88 | False 89 | True 90 | _Help 91 | True 92 | 93 | 94 | True 95 | False 96 | 97 | 98 | gtk-about 99 | False 100 | True 101 | False 102 | True 103 | True 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | False 114 | True 115 | 0 116 | 117 | 118 | 119 | 120 | False 121 | True 122 | True 123 | True 124 | True 125 | <b>http://mattn.kaoriya.net/</b> 126 | image1 127 | none 128 | http://mattn.kaoriya.net/ 129 | 130 | 131 | True 132 | True 133 | 1 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /_example/clipboard/clipboard.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mattn/go-gtk/gdk" 6 | "github.com/mattn/go-gtk/gtk" 7 | ) 8 | 9 | func main() { 10 | gtk.Init(nil) 11 | clipboard := gtk.NewClipboardGetForDisplay( 12 | gdk.DisplayGetDefault(), 13 | gdk.SELECTION_CLIPBOARD) 14 | fmt.Println(clipboard.WaitForText()) 15 | clipboard.SetText("helloworld") 16 | gtk.MainIterationDo(true) 17 | clipboard.Store() 18 | gtk.MainIterationDo(true) 19 | } 20 | -------------------------------------------------------------------------------- /_example/demo/demo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "path/filepath" 8 | "regexp" 9 | "sort" 10 | "strings" 11 | 12 | "github.com/mattn/go-gtk/gdkpixbuf" 13 | "github.com/mattn/go-gtk/glib" 14 | "github.com/mattn/go-gtk/gtk" 15 | ) 16 | 17 | func uniq(strings []string) (ret []string) { 18 | return 19 | } 20 | 21 | func authors() []string { 22 | if b, err := exec.Command("git", "log").Output(); err == nil { 23 | lines := strings.Split(string(b), "\n") 24 | 25 | var a []string 26 | r := regexp.MustCompile(`^Author:\s*([^ <]+).*$`) 27 | for _, e := range lines { 28 | ms := r.FindStringSubmatch(e) 29 | if ms == nil { 30 | continue 31 | } 32 | a = append(a, ms[1]) 33 | } 34 | sort.Strings(a) 35 | var p string 36 | lines = []string{} 37 | for _, e := range a { 38 | if p == e { 39 | continue 40 | } 41 | lines = append(lines, e) 42 | p = e 43 | } 44 | return lines 45 | } 46 | return []string{"Yasuhiro Matsumoto "} 47 | } 48 | 49 | func main() { 50 | gtk.Init(&os.Args) 51 | 52 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 53 | window.SetPosition(gtk.WIN_POS_CENTER) 54 | window.SetTitle("GTK Go!") 55 | window.SetIconName("gtk-dialog-info") 56 | window.Connect("destroy", func(ctx *glib.CallbackContext) { 57 | fmt.Println("got destroy!", ctx.Data().(string)) 58 | gtk.MainQuit() 59 | }, "foo") 60 | 61 | //-------------------------------------------------------- 62 | // GtkVBox 63 | //-------------------------------------------------------- 64 | vbox := gtk.NewVBox(false, 1) 65 | 66 | //-------------------------------------------------------- 67 | // GtkMenuBar 68 | //-------------------------------------------------------- 69 | menubar := gtk.NewMenuBar() 70 | vbox.PackStart(menubar, false, false, 0) 71 | 72 | //-------------------------------------------------------- 73 | // GtkVPaned 74 | //-------------------------------------------------------- 75 | vpaned := gtk.NewVPaned() 76 | vbox.Add(vpaned) 77 | 78 | //-------------------------------------------------------- 79 | // GtkFrame 80 | //-------------------------------------------------------- 81 | frame1 := gtk.NewFrame("Demo") 82 | framebox1 := gtk.NewVBox(false, 1) 83 | frame1.Add(framebox1) 84 | 85 | frame2 := gtk.NewFrame("Demo") 86 | framebox2 := gtk.NewVBox(false, 1) 87 | frame2.Add(framebox2) 88 | 89 | vpaned.Pack1(frame1, false, false) 90 | vpaned.Pack2(frame2, false, false) 91 | 92 | //-------------------------------------------------------- 93 | // GtkImage 94 | //-------------------------------------------------------- 95 | dir, _ := filepath.Split(os.Args[0]) 96 | imagefile := filepath.Join(dir, "../../data/go-gtk-logo.png") 97 | 98 | label := gtk.NewLabel("Go Binding for GTK") 99 | label.ModifyFontEasy("DejaVu Serif 15") 100 | framebox1.PackStart(label, false, true, 0) 101 | 102 | //-------------------------------------------------------- 103 | // GtkEntry 104 | //-------------------------------------------------------- 105 | entry := gtk.NewEntry() 106 | entry.SetText("Hello world") 107 | framebox1.Add(entry) 108 | 109 | image := gtk.NewImageFromFile(imagefile) 110 | framebox1.Add(image) 111 | 112 | //-------------------------------------------------------- 113 | // GtkScale 114 | //-------------------------------------------------------- 115 | scale := gtk.NewHScaleWithRange(0, 100, 1) 116 | scale.Connect("value-changed", func() { 117 | fmt.Println("scale:", int(scale.GetValue())) 118 | }) 119 | framebox2.Add(scale) 120 | 121 | //-------------------------------------------------------- 122 | // GtkHBox 123 | //-------------------------------------------------------- 124 | buttons := gtk.NewHBox(false, 1) 125 | 126 | //-------------------------------------------------------- 127 | // GtkButton 128 | //-------------------------------------------------------- 129 | button := gtk.NewButtonWithLabel("Button with label") 130 | button.Clicked(func() { 131 | fmt.Println("button clicked:", button.GetLabel()) 132 | messagedialog := gtk.NewMessageDialog( 133 | button.GetTopLevelAsWindow(), 134 | gtk.DIALOG_MODAL, 135 | gtk.MESSAGE_INFO, 136 | gtk.BUTTONS_OK, 137 | entry.GetText()) 138 | messagedialog.Response(func() { 139 | fmt.Println("Dialog OK!") 140 | 141 | //-------------------------------------------------------- 142 | // GtkFileChooserDialog 143 | //-------------------------------------------------------- 144 | filechooserdialog := gtk.NewFileChooserDialog( 145 | "Choose File...", 146 | button.GetTopLevelAsWindow(), 147 | gtk.FILE_CHOOSER_ACTION_OPEN, 148 | gtk.STOCK_OK, 149 | gtk.RESPONSE_ACCEPT) 150 | filter := gtk.NewFileFilter() 151 | filter.AddPattern("*.go") 152 | filechooserdialog.AddFilter(filter) 153 | filechooserdialog.Response(func() { 154 | fmt.Println(filechooserdialog.GetFilename()) 155 | filechooserdialog.Destroy() 156 | }) 157 | filechooserdialog.Run() 158 | messagedialog.Destroy() 159 | }) 160 | messagedialog.Run() 161 | }) 162 | buttons.Add(button) 163 | 164 | //-------------------------------------------------------- 165 | // GtkFontButton 166 | //-------------------------------------------------------- 167 | fontbutton := gtk.NewFontButton() 168 | fontbutton.Connect("font-set", func() { 169 | fmt.Println("title:", fontbutton.GetTitle()) 170 | fmt.Println("fontname:", fontbutton.GetFontName()) 171 | fmt.Println("use_size:", fontbutton.GetUseSize()) 172 | fmt.Println("show_size:", fontbutton.GetShowSize()) 173 | }) 174 | buttons.Add(fontbutton) 175 | framebox2.PackStart(buttons, false, false, 0) 176 | 177 | buttons = gtk.NewHBox(false, 1) 178 | 179 | //-------------------------------------------------------- 180 | // GtkToggleButton 181 | //-------------------------------------------------------- 182 | togglebutton := gtk.NewToggleButtonWithLabel("ToggleButton with label") 183 | togglebutton.Connect("toggled", func() { 184 | if togglebutton.GetActive() { 185 | togglebutton.SetLabel("ToggleButton ON!") 186 | } else { 187 | togglebutton.SetLabel("ToggleButton OFF!") 188 | } 189 | }) 190 | buttons.Add(togglebutton) 191 | 192 | //-------------------------------------------------------- 193 | // GtkCheckButton 194 | //-------------------------------------------------------- 195 | checkbutton := gtk.NewCheckButtonWithLabel("CheckButton with label") 196 | checkbutton.Connect("toggled", func() { 197 | if checkbutton.GetActive() { 198 | checkbutton.SetLabel("CheckButton CHECKED!") 199 | } else { 200 | checkbutton.SetLabel("CheckButton UNCHECKED!") 201 | } 202 | }) 203 | buttons.Add(checkbutton) 204 | 205 | //-------------------------------------------------------- 206 | // GtkRadioButton 207 | //-------------------------------------------------------- 208 | buttonbox := gtk.NewVBox(false, 1) 209 | radiofirst := gtk.NewRadioButtonWithLabel(nil, "Radio1") 210 | buttonbox.Add(radiofirst) 211 | buttonbox.Add(gtk.NewRadioButtonWithLabel(radiofirst.GetGroup(), "Radio2")) 212 | buttonbox.Add(gtk.NewRadioButtonWithLabel(radiofirst.GetGroup(), "Radio3")) 213 | buttons.Add(buttonbox) 214 | //radiobutton.SetMode(false); 215 | radiofirst.SetActive(true) 216 | 217 | framebox2.PackStart(buttons, false, false, 0) 218 | 219 | //-------------------------------------------------------- 220 | // GtkVSeparator 221 | //-------------------------------------------------------- 222 | vsep := gtk.NewVSeparator() 223 | framebox2.PackStart(vsep, false, false, 0) 224 | 225 | //-------------------------------------------------------- 226 | // GtkComboBoxEntry 227 | //-------------------------------------------------------- 228 | combos := gtk.NewHBox(false, 1) 229 | comboboxentry := gtk.NewComboBoxText() 230 | comboboxentry.AppendText("Monkey") 231 | comboboxentry.AppendText("Tiger") 232 | comboboxentry.AppendText("Elephant") 233 | comboboxentry.Connect("changed", func() { 234 | fmt.Println("value:", comboboxentry.GetActiveText()) 235 | }) 236 | combos.Add(comboboxentry) 237 | 238 | //-------------------------------------------------------- 239 | // GtkComboBox 240 | //-------------------------------------------------------- 241 | combobox := gtk.NewComboBoxText() 242 | combobox.AppendText("Peach") 243 | combobox.AppendText("Banana") 244 | combobox.AppendText("Apple") 245 | combobox.SetActive(1) 246 | combobox.Connect("changed", func() { 247 | fmt.Println("value:", combobox.GetActiveText()) 248 | }) 249 | combos.Add(combobox) 250 | 251 | framebox2.PackStart(combos, false, false, 0) 252 | 253 | //-------------------------------------------------------- 254 | // GtkTextView 255 | //-------------------------------------------------------- 256 | swin := gtk.NewScrolledWindow(nil, nil) 257 | swin.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 258 | swin.SetShadowType(gtk.SHADOW_IN) 259 | textview := gtk.NewTextView() 260 | var start, end gtk.TextIter 261 | buffer := textview.GetBuffer() 262 | buffer.GetStartIter(&start) 263 | buffer.Insert(&start, "Hello ") 264 | buffer.GetEndIter(&end) 265 | buffer.Insert(&end, "World!") 266 | tag := buffer.CreateTag("bold", map[string]interface{}{ 267 | "background": "#FF0000", "weight": "700"}) 268 | buffer.GetStartIter(&start) 269 | buffer.GetEndIter(&end) 270 | buffer.ApplyTag(tag, &start, &end) 271 | swin.Add(textview) 272 | framebox2.Add(swin) 273 | 274 | buffer.Connect("changed", func() { 275 | fmt.Println("changed") 276 | }) 277 | 278 | //-------------------------------------------------------- 279 | // GtkMenuItem 280 | //-------------------------------------------------------- 281 | cascademenu := gtk.NewMenuItemWithMnemonic("_File") 282 | menubar.Append(cascademenu) 283 | submenu := gtk.NewMenu() 284 | cascademenu.SetSubmenu(submenu) 285 | 286 | var menuitem *gtk.MenuItem 287 | menuitem = gtk.NewMenuItemWithMnemonic("E_xit") 288 | menuitem.Connect("activate", func() { 289 | gtk.MainQuit() 290 | }) 291 | submenu.Append(menuitem) 292 | 293 | cascademenu = gtk.NewMenuItemWithMnemonic("_View") 294 | menubar.Append(cascademenu) 295 | submenu = gtk.NewMenu() 296 | cascademenu.SetSubmenu(submenu) 297 | 298 | checkmenuitem := gtk.NewCheckMenuItemWithMnemonic("_Disable") 299 | checkmenuitem.Connect("activate", func() { 300 | vpaned.SetSensitive(!checkmenuitem.GetActive()) 301 | }) 302 | submenu.Append(checkmenuitem) 303 | 304 | menuitem = gtk.NewMenuItemWithMnemonic("_Font") 305 | menuitem.Connect("activate", func() { 306 | fsd := gtk.NewFontSelectionDialog("Font") 307 | fsd.SetFontName(fontbutton.GetFontName()) 308 | fsd.Response(func() { 309 | fmt.Println(fsd.GetFontName()) 310 | fontbutton.SetFontName(fsd.GetFontName()) 311 | fsd.Destroy() 312 | }) 313 | fsd.SetTransientFor(window) 314 | fsd.Run() 315 | }) 316 | submenu.Append(menuitem) 317 | 318 | cascademenu = gtk.NewMenuItemWithMnemonic("_Help") 319 | menubar.Append(cascademenu) 320 | submenu = gtk.NewMenu() 321 | cascademenu.SetSubmenu(submenu) 322 | 323 | menuitem = gtk.NewMenuItemWithMnemonic("_About") 324 | menuitem.Connect("activate", func() { 325 | dialog := gtk.NewAboutDialog() 326 | dialog.SetName("Go-Gtk Demo!") 327 | dialog.SetProgramName("demo") 328 | dialog.SetAuthors(authors()) 329 | dir, _ := filepath.Split(os.Args[0]) 330 | imagefile := filepath.Join(dir, "../../data/mattn-logo.png") 331 | pixbuf, _ := gdkpixbuf.NewPixbufFromFile(imagefile) 332 | dialog.SetLogo(pixbuf) 333 | dialog.SetLicense("The library is available under the same terms and conditions as the Go, the BSD style license, and the LGPL (Lesser GNU Public License). The idea is that if you can use Go (and Gtk) in a project, you should also be able to use go-gtk.") 334 | dialog.SetWrapLicense(true) 335 | dialog.Run() 336 | dialog.Destroy() 337 | }) 338 | submenu.Append(menuitem) 339 | 340 | //-------------------------------------------------------- 341 | // GtkStatusbar 342 | //-------------------------------------------------------- 343 | statusbar := gtk.NewStatusbar() 344 | context_id := statusbar.GetContextId("go-gtk") 345 | statusbar.Push(context_id, "GTK binding for Go!") 346 | 347 | framebox2.PackStart(statusbar, false, false, 0) 348 | 349 | //-------------------------------------------------------- 350 | // Event 351 | //-------------------------------------------------------- 352 | window.Add(vbox) 353 | window.SetSizeRequest(600, 600) 354 | window.ShowAll() 355 | gtk.Main() 356 | } 357 | -------------------------------------------------------------------------------- /_example/dnd/dnd.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "strings" 6 | "unsafe" 7 | 8 | "github.com/mattn/go-gtk/gdk" 9 | "github.com/mattn/go-gtk/glib" 10 | "github.com/mattn/go-gtk/gtk" 11 | ) 12 | 13 | func main() { 14 | gtk.Init(&os.Args) 15 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 16 | window.SetTitle("GTK DND") 17 | window.Connect("destroy", gtk.MainQuit) 18 | 19 | vbox := gtk.NewVBox(true, 0) 20 | vbox.SetBorderWidth(5) 21 | 22 | targets := []gtk.TargetEntry{ 23 | {"text/uri-list", 0, 0}, 24 | {"STRING", 0, 1}, 25 | {"text/plain", 0, 2}, 26 | } 27 | dest := gtk.NewLabel("drop me file") 28 | dest.DragDestSet( 29 | gtk.DEST_DEFAULT_MOTION| 30 | gtk.DEST_DEFAULT_HIGHLIGHT| 31 | gtk.DEST_DEFAULT_DROP, 32 | targets, 33 | gdk.ACTION_COPY) 34 | dest.DragDestAddUriTargets() 35 | dest.Connect("drag-data-received", func(ctx *glib.CallbackContext) { 36 | sdata := gtk.NewSelectionDataFromNative(unsafe.Pointer(ctx.Args(3))) 37 | if sdata != nil { 38 | a := (*[2000]uint8)(sdata.GetData()) 39 | files := strings.Split(string(a[0:sdata.GetLength()-1]), "\n") 40 | for i := range files { 41 | filename, _, _ := glib.FilenameFromUri(files[i]) 42 | files[i] = filename 43 | } 44 | dialog := gtk.NewMessageDialog( 45 | window, 46 | gtk.DIALOG_MODAL, 47 | gtk.MESSAGE_INFO, 48 | gtk.BUTTONS_OK, 49 | strings.Join(files, "\n")) 50 | dialog.SetTitle("D&D") 51 | dialog.Response(func() { 52 | dialog.Destroy() 53 | }) 54 | dialog.Run() 55 | } 56 | }) 57 | vbox.Add(dest) 58 | 59 | window.Add(vbox) 60 | 61 | window.SetSizeRequest(300, 100) 62 | window.ShowAll() 63 | gtk.Main() 64 | } 65 | -------------------------------------------------------------------------------- /_example/drawable/drawable.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mattn/go-gtk/gdk" 5 | "github.com/mattn/go-gtk/glib" 6 | "github.com/mattn/go-gtk/gtk" 7 | "os" 8 | "unsafe" 9 | ) 10 | 11 | type point struct { 12 | x int 13 | y int 14 | } 15 | 16 | func main() { 17 | gtk.Init(&os.Args) 18 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 19 | window.SetTitle("GTK DrawingArea") 20 | window.Connect("destroy", gtk.MainQuit) 21 | 22 | vbox := gtk.NewVBox(true, 0) 23 | vbox.SetBorderWidth(5) 24 | drawingarea := gtk.NewDrawingArea() 25 | 26 | var p1, p2 point 27 | var gdkwin *gdk.Window 28 | var pixmap *gdk.Pixmap 29 | var gc *gdk.GC 30 | p1.x = -1 31 | p1.y = -1 32 | colors := []string{ 33 | "black", 34 | "gray", 35 | "blue", 36 | "purple", 37 | "red", 38 | "orange", 39 | "yellow", 40 | "green", 41 | "darkgreen", 42 | } 43 | 44 | drawingarea.Connect("configure-event", func() { 45 | if pixmap != nil { 46 | pixmap.Unref() 47 | } 48 | allocation := drawingarea.GetAllocation() 49 | pixmap = gdk.NewPixmap(drawingarea.GetWindow().GetDrawable(), allocation.Width, allocation.Height, 24) 50 | gc = gdk.NewGC(pixmap.GetDrawable()) 51 | gc.SetRgbFgColor(gdk.NewColor("white")) 52 | pixmap.GetDrawable().DrawRectangle(gc, true, 0, 0, -1, -1) 53 | gc.SetRgbFgColor(gdk.NewColor(colors[0])) 54 | gc.SetRgbBgColor(gdk.NewColor("white")) 55 | }) 56 | 57 | drawingarea.Connect("motion-notify-event", func(ctx *glib.CallbackContext) { 58 | arg := ctx.Args(0) 59 | mev := *(**gdk.EventMotion)(unsafe.Pointer(&arg)) 60 | var mt gdk.ModifierType 61 | if mev.IsHint != 0 { 62 | gdkwin.GetPointer(&p2.x, &p2.y, &mt) 63 | } else { 64 | p2.x, p2.y = int(mev.X), int(mev.Y) 65 | } 66 | if p1.x != -1 && p2.x != -1 && (gdk.EventMask(mt)&gdk.BUTTON_PRESS_MASK) != 0 { 67 | pixmap.GetDrawable().DrawLine(gc, p1.x, p1.y, p2.x, p2.y) 68 | gdkwin.Invalidate(nil, false) 69 | } 70 | colors = append(colors[1:], colors[0]) 71 | gc.SetRgbFgColor(gdk.NewColor(colors[0])) 72 | p1 = p2 73 | }) 74 | 75 | drawingarea.Connect("expose-event", func() { 76 | if pixmap == nil { 77 | return 78 | } 79 | gdkwin.GetDrawable().DrawDrawable(gc, pixmap.GetDrawable(), 0, 0, 0, 0, -1, -1) 80 | }) 81 | 82 | drawingarea.SetEvents(int(gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK | gdk.BUTTON_PRESS_MASK)) 83 | vbox.Add(drawingarea) 84 | 85 | window.Add(vbox) 86 | window.SetSizeRequest(400, 400) 87 | window.ShowAll() 88 | 89 | gdkwin = drawingarea.GetWindow() 90 | 91 | gtk.Main() 92 | } 93 | -------------------------------------------------------------------------------- /_example/event/event.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mattn/go-gtk/gdk" 6 | "github.com/mattn/go-gtk/glib" 7 | "github.com/mattn/go-gtk/gtk" 8 | "os" 9 | "unsafe" 10 | ) 11 | 12 | func main() { 13 | gtk.Init(&os.Args) 14 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 15 | window.SetTitle("GTK Events") 16 | window.Connect("destroy", gtk.MainQuit) 17 | 18 | event := make(chan interface{}) 19 | 20 | window.Connect("key-press-event", func(ctx *glib.CallbackContext) { 21 | arg := ctx.Args(0) 22 | event <- *(**gdk.EventKey)(unsafe.Pointer(&arg)) 23 | }) 24 | window.Connect("motion-notify-event", func(ctx *glib.CallbackContext) { 25 | arg := ctx.Args(0) 26 | event <- *(**gdk.EventMotion)(unsafe.Pointer(&arg)) 27 | }) 28 | 29 | go func() { 30 | for { 31 | e := <-event 32 | switch ev := e.(type) { 33 | case *gdk.EventKey: 34 | fmt.Println("key-press-event:", ev.Keyval) 35 | break 36 | case *gdk.EventMotion: 37 | fmt.Println("motion-notify-event:", int(ev.X), int(ev.Y)) 38 | break 39 | } 40 | } 41 | }() 42 | 43 | window.SetEvents(int(gdk.POINTER_MOTION_MASK | gdk.POINTER_MOTION_HINT_MASK | gdk.BUTTON_PRESS_MASK)) 44 | window.SetSizeRequest(400, 400) 45 | window.ShowAll() 46 | 47 | gtk.Main() 48 | } 49 | -------------------------------------------------------------------------------- /_example/example.mk: -------------------------------------------------------------------------------- 1 | EXAMPLES := \ 2 | _example/action/action \ 3 | _example/alignment/alignment \ 4 | _example/builder/builder \ 5 | _example/clipboard/clipboard \ 6 | _example/demo/demo \ 7 | _example/arrow/arrow \ 8 | _example/dnd/dnd \ 9 | _example/drawable/drawable \ 10 | _example/event/event \ 11 | _example/expander/expander \ 12 | _example/iconview/iconview \ 13 | _example/listview/listview \ 14 | _example/locale/locale \ 15 | _example/notebook/notebook \ 16 | _example/number/number \ 17 | _example/sourceview/sourceview \ 18 | _example/spinbutton/spinbutton \ 19 | _example/statusicon/statusicon \ 20 | _example/table/table \ 21 | _example/thread/thread \ 22 | _example/toolbar/toolbar \ 23 | _example/treeview/treeview \ 24 | _example/twitterstream/twitterstream 25 | 26 | .PHONY: example 27 | example: $(EXAMPLES) 28 | @true 29 | 30 | .PHONY: clean-example 31 | clean-example: 32 | rm -f $(EXAMPLES) 33 | 34 | %: %.go 35 | cd $(@D) && go build -x 36 | 37 | example/action/action: example/action/action.go 38 | example/alignment/alignment: example/alignment/alignment.go 39 | example/builder/builder: example/builder/builder.go 40 | example/clipboard/clipboard: example/clipboard/clipboard.go 41 | example/demo/demo: example/demo/demo.go 42 | example/arrow/arrow: example/arrow/arrow.go 43 | example/dnd/dnd: example/dnd/dnd.go 44 | example/drawable/drawable: example/drawable/drawable.go 45 | example/event/event: example/event/event.go 46 | example/expander/expander: example/expander/expander.go 47 | example/iconview/iconview: example/iconview/iconview.go 48 | example/listview/listview: example/listview/listview.go 49 | example/locale/locale: example/locale/locale.go 50 | example/notebook/notebook: example/notebook/notebook.go 51 | example/number/number: example/number/number.go 52 | example/sourceview/sourceview: example/sourceview/sourceview.go 53 | example/spinbutton/spinbutton: example/spinbutton/spinbutton.go 54 | example/statusicon/statusicon: example/statusicon/statusicon.go 55 | example/table/table: example/table/table.go 56 | example/thread/thread: example/thread/thread.go 57 | example/toolbar/toolbar: example/toolbar/toolbar.go 58 | example/treeview/treeview: example/treeview/treeview.go 59 | example/twitterstream/twitterstream: example/twitterstream/twitterstream.go 60 | -------------------------------------------------------------------------------- /_example/expander/expander.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mattn/go-gtk/gtk" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | gtk.Init(&os.Args) 10 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 11 | window.SetTitle("We love Expander") 12 | window.Connect("destroy", gtk.MainQuit) 13 | 14 | vbox := gtk.NewVBox(true, 0) 15 | vbox.SetBorderWidth(5) 16 | expander := gtk.NewExpander("dan the ...") 17 | expander.Add(gtk.NewLabel("404 contents not found")) 18 | vbox.PackStart(expander, false, false, 0) 19 | 20 | window.Add(vbox) 21 | window.ShowAll() 22 | 23 | gtk.Main() 24 | } 25 | -------------------------------------------------------------------------------- /_example/iconview/iconview.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "unsafe" 6 | 7 | "github.com/mattn/go-gtk/gdkpixbuf" 8 | "github.com/mattn/go-gtk/glib" 9 | "github.com/mattn/go-gtk/gtk" 10 | ) 11 | 12 | func main() { 13 | gtk.Init(&os.Args) 14 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 15 | window.SetTitle("GTK Icon View") 16 | window.Connect("destroy", gtk.MainQuit) 17 | 18 | swin := gtk.NewScrolledWindow(nil, nil) 19 | 20 | store := gtk.NewListStore(gdkpixbuf.GetType(), glib.G_TYPE_STRING) 21 | iconview := gtk.NewIconViewWithModel(store) 22 | iconview.SetPixbufColumn(0) 23 | iconview.SetTextColumn(1) 24 | swin.Add(iconview) 25 | 26 | gtk.StockListIDs().ForEach(func(d unsafe.Pointer, v interface{}) { 27 | id := glib.GPtrToString(d) 28 | var iter gtk.TreeIter 29 | store.Append(&iter) 30 | store.Set(&iter, 31 | 0, gtk.NewImage().RenderIcon(id, gtk.ICON_SIZE_SMALL_TOOLBAR, "").GPixbuf, 32 | 1, id) 33 | }) 34 | 35 | window.Add(swin) 36 | window.SetSizeRequest(500, 200) 37 | window.ShowAll() 38 | 39 | gtk.Main() 40 | } 41 | -------------------------------------------------------------------------------- /_example/idle/idle.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/mattn/go-gtk/glib" 8 | ) 9 | 10 | func main() { 11 | glib.IdleAdd(func() bool { 12 | fmt.Println("start") 13 | return false 14 | }) 15 | glib.TimeoutAdd(1000, func() bool { 16 | fmt.Println(fmt.Sprintf("%v", time.Now())) 17 | return true 18 | }) 19 | 20 | glib.NewMainLoop(nil, false).Run() 21 | } 22 | -------------------------------------------------------------------------------- /_example/listview/listview.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "unsafe" 6 | 7 | "github.com/mattn/go-gtk/gdkpixbuf" 8 | "github.com/mattn/go-gtk/glib" 9 | "github.com/mattn/go-gtk/gtk" 10 | ) 11 | 12 | func main() { 13 | gtk.Init(&os.Args) 14 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 15 | window.SetTitle("GTK Stock Icons") 16 | window.Connect("destroy", gtk.MainQuit) 17 | 18 | swin := gtk.NewScrolledWindow(nil, nil) 19 | 20 | store := gtk.NewListStore(glib.G_TYPE_STRING, glib.G_TYPE_BOOL, gdkpixbuf.GetType()) 21 | treeview := gtk.NewTreeView() 22 | swin.Add(treeview) 23 | 24 | treeview.SetModel(store) 25 | treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("name", gtk.NewCellRendererText(), "text", 0)) 26 | treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("check", gtk.NewCellRendererToggle(), "active", 1)) 27 | treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("icon", gtk.NewCellRendererPixbuf(), "pixbuf", 2)) 28 | n := 0 29 | gtk.StockListIDs().ForEach(func(d unsafe.Pointer, v interface{}) { 30 | id := glib.GPtrToString(d) 31 | var iter gtk.TreeIter 32 | store.Append(&iter) 33 | store.Set(&iter, 34 | 0, id, 35 | 1, (n == 1), 36 | 2, gtk.NewImage().RenderIcon(id, gtk.ICON_SIZE_SMALL_TOOLBAR, "").GPixbuf, 37 | ) 38 | n = 1 - n 39 | }) 40 | 41 | window.Add(swin) 42 | window.SetSizeRequest(400, 200) 43 | window.ShowAll() 44 | 45 | gtk.Main() 46 | } 47 | -------------------------------------------------------------------------------- /_example/locale/locale.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/mattn/go-gtk/gtk" 4 | import "github.com/mattn/go-gtk/glib" 5 | import "fmt" 6 | import "syscall" 7 | 8 | func main() { 9 | gtk.SetLocale() 10 | 11 | bs, _, _, err := glib.LocaleFromUtf8("こんにちわ世界\n") 12 | if err == nil { 13 | syscall.Write(syscall.Stdout, bs) 14 | } else { 15 | fmt.Println(err.Message()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /_example/notebook/notebook.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mattn/go-gtk/gtk" 5 | "os" 6 | "strconv" 7 | ) 8 | 9 | func main() { 10 | gtk.Init(&os.Args) 11 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 12 | window.SetTitle("GTK Notebook") 13 | window.Connect("destroy", gtk.MainQuit) 14 | 15 | notebook := gtk.NewNotebook() 16 | for n := 1; n <= 10; n++ { 17 | page := gtk.NewFrame("demo" + strconv.Itoa(n)) 18 | notebook.AppendPage(page, gtk.NewLabel("demo"+strconv.Itoa(n))) 19 | 20 | vbox := gtk.NewHBox(false, 1) 21 | 22 | prev := gtk.NewButtonWithLabel("go prev") 23 | prev.Clicked(func() { 24 | notebook.PrevPage() 25 | }) 26 | vbox.Add(prev) 27 | 28 | next := gtk.NewButtonWithLabel("go next") 29 | next.Clicked(func() { 30 | notebook.NextPage() 31 | }) 32 | vbox.Add(next) 33 | 34 | page.Add(vbox) 35 | } 36 | 37 | window.Add(notebook) 38 | window.SetSizeRequest(400, 200) 39 | window.ShowAll() 40 | 41 | gtk.Main() 42 | } 43 | -------------------------------------------------------------------------------- /_example/number/number.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mattn/go-gtk/glib" 6 | "github.com/mattn/go-gtk/gtk" 7 | "os" 8 | "strconv" 9 | "unsafe" 10 | ) 11 | 12 | func main() { 13 | gtk.Init(&os.Args) 14 | 15 | dialog := gtk.NewDialog() 16 | dialog.SetTitle("number input") 17 | 18 | vbox := dialog.GetVBox() 19 | 20 | label := gtk.NewLabel("Numnber:") 21 | vbox.Add(label) 22 | 23 | input := gtk.NewEntry() 24 | input.SetEditable(true) 25 | vbox.Add(input) 26 | 27 | input.Connect("insert-text", func(ctx *glib.CallbackContext) { 28 | a := (*[2000]uint8)(unsafe.Pointer(ctx.Args(0))) 29 | p := (*int)(unsafe.Pointer(ctx.Args(2))) 30 | i := 0 31 | for a[i] != 0 { 32 | i++ 33 | } 34 | s := string(a[0:i]) 35 | if s == "." { 36 | if *p == 0 { 37 | input.StopEmission("insert-text") 38 | } 39 | } else { 40 | _, err := strconv.ParseFloat(s, 64) 41 | if err != nil { 42 | input.StopEmission("insert-text") 43 | } 44 | } 45 | }) 46 | 47 | button := gtk.NewButtonWithLabel("OK") 48 | button.Connect("clicked", func() { 49 | fmt.Println(input.GetText()) 50 | gtk.MainQuit() 51 | }) 52 | vbox.Add(button) 53 | 54 | dialog.ShowAll() 55 | gtk.Main() 56 | } 57 | -------------------------------------------------------------------------------- /_example/sourceview/sourceview.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mattn/go-gtk/gtk" 5 | gsv "github.com/mattn/go-gtk/gtksourceview" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | gtk.Init(&os.Args) 11 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 12 | window.SetTitle("SourceView") 13 | window.Connect("destroy", gtk.MainQuit) 14 | 15 | swin := gtk.NewScrolledWindow(nil, nil) 16 | swin.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 17 | swin.SetShadowType(gtk.SHADOW_IN) 18 | sourcebuffer := gsv.NewSourceBufferWithLanguage(gsv.SourceLanguageManagerGetDefault().GetLanguage("cpp")) 19 | sourceview := gsv.NewSourceViewWithBuffer(sourcebuffer) 20 | 21 | var start gtk.TextIter 22 | sourcebuffer.GetStartIter(&start) 23 | sourcebuffer.BeginNotUndoableAction() 24 | sourcebuffer.Insert(&start, `#include 25 | template 26 | struct foo_base { 27 | T operator+(T const &rhs) const { 28 | T tmp(static_cast(*this)); 29 | tmp += rhs; 30 | return tmp; 31 | } 32 | }; 33 | 34 | class foo : public foo_base { 35 | private: 36 | int v; 37 | public: 38 | foo(int v) : v(v) {} 39 | foo &operator+=(foo const &rhs){ 40 | this->v += rhs.v; 41 | return *this; 42 | } 43 | operator int() { return v; } 44 | }; 45 | 46 | int main(void) { 47 | foo a(1), b(2); 48 | a += b; 49 | std::cout << (int)a << std::endl; 50 | } 51 | `) 52 | sourcebuffer.EndNotUndoableAction() 53 | 54 | swin.Add(sourceview) 55 | 56 | window.Add(swin) 57 | window.SetSizeRequest(400, 300) 58 | window.ShowAll() 59 | 60 | gtk.Main() 61 | } 62 | -------------------------------------------------------------------------------- /_example/spinbutton/spinbutton.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mattn/go-gtk/glib" 6 | "github.com/mattn/go-gtk/gtk" 7 | "strconv" 8 | ) 9 | 10 | func main() { 11 | gtk.Init(nil) 12 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 13 | window.SetPosition(gtk.WIN_POS_CENTER) 14 | window.SetTitle("GTK Go!") 15 | window.Connect("destroy", func(ctx *glib.CallbackContext) { 16 | fmt.Println("got destroy!", ctx.Data().(string)) 17 | gtk.MainQuit() 18 | }, "foo") 19 | 20 | //-------------------------------------------------------- 21 | // GtkHBox 22 | //-------------------------------------------------------- 23 | fixed := gtk.NewFixed() 24 | 25 | //-------------------------------------------------------- 26 | // GtkSpinButton 27 | //-------------------------------------------------------- 28 | spinbutton1 := gtk.NewSpinButtonWithRange(1.0, 10.0, 1.0) 29 | spinbutton1.SetDigits(3) 30 | spinbutton1.Spin(gtk.SPIN_STEP_FORWARD, 7.0) 31 | fixed.Put(spinbutton1, 40, 50) 32 | 33 | spinbutton1.OnValueChanged(func() { 34 | val := spinbutton1.GetValueAsInt() 35 | fval := spinbutton1.GetValue() 36 | fmt.Println("SpinButton changed, new value: " + strconv.Itoa(val) + " | " + strconv.FormatFloat(fval, 'f', 2, 64)) 37 | min, max := spinbutton1.GetRange() 38 | fmt.Println("Range: " + strconv.FormatFloat(min, 'f', 2, 64) + " " + strconv.FormatFloat(max, 'f', 2, 64)) 39 | fmt.Println("Digits: " + strconv.Itoa(int(spinbutton1.GetDigits()))) 40 | }) 41 | 42 | adjustment := gtk.NewAdjustment(2.0, 1.0, 8.0, 2.0, 0.0, 0.0) 43 | spinbutton2 := gtk.NewSpinButton(adjustment, 1.0, 1) 44 | spinbutton2.SetRange(0.0, 20.0) 45 | spinbutton2.SetValue(18.0) 46 | spinbutton2.SetIncrements(2.0, 4.0) 47 | fixed.Put(spinbutton2, 150, 50) 48 | 49 | //-------------------------------------------------------- 50 | // Event 51 | //-------------------------------------------------------- 52 | window.Add(fixed) 53 | window.SetSizeRequest(600, 600) 54 | window.ShowAll() 55 | gtk.Main() 56 | } 57 | -------------------------------------------------------------------------------- /_example/statusicon/statusicon.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mattn/go-gtk/glib" 6 | "github.com/mattn/go-gtk/gtk" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | gtk.Init(&os.Args) 12 | 13 | glib.SetApplicationName("go-gtk-statusicon-example") 14 | 15 | mi := gtk.NewMenuItemWithLabel("Popup!") 16 | mi.Connect("activate", func() { 17 | gtk.MainQuit() 18 | }) 19 | nm := gtk.NewMenu() 20 | nm.Append(mi) 21 | nm.ShowAll() 22 | 23 | si := gtk.NewStatusIconFromStock(gtk.STOCK_FILE) 24 | si.SetTitle("StatusIcon Example") 25 | si.SetTooltipMarkup("StatusIcon Example") 26 | si.Connect("popup-menu", func(cbx *glib.CallbackContext) { 27 | nm.Popup(nil, nil, gtk.StatusIconPositionMenu, si, uint(cbx.Args(0)), uint32(cbx.Args(1))) 28 | }) 29 | 30 | fmt.Println(` 31 | Can you see statusicon in systray? 32 | If you don't see it and if you use 'unity', try following. 33 | 34 | # gsettings set com.canonical.Unity.Panel systray-whitelist \ 35 | "$(gsettings get com.canonical.Unity.Panel systray-whitelist \| 36 | sed -e "s/]$/, 'go-gtk-statusicon-example']/")" 37 | `) 38 | 39 | gtk.Main() 40 | } 41 | -------------------------------------------------------------------------------- /_example/table/table.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mattn/go-gtk/gtk" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | gtk.Init(&os.Args) 11 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 12 | window.SetTitle("GTK Table") 13 | window.Connect("destroy", gtk.MainQuit) 14 | 15 | swin := gtk.NewScrolledWindow(nil, nil) 16 | swin.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) 17 | 18 | table := gtk.NewTable(5, 5, false) 19 | for y := uint(0); y < 5; y++ { 20 | for x := uint(0); x < 5; x++ { 21 | table.Attach(gtk.NewButtonWithLabel(fmt.Sprintf("%02d:%02d", x, y)), x, x+1, y, y+1, gtk.FILL, gtk.FILL, 5, 5) 22 | } 23 | } 24 | swin.AddWithViewPort(table) 25 | 26 | window.Add(swin) 27 | window.SetDefaultSize(200, 200) 28 | window.ShowAll() 29 | 30 | gtk.Main() 31 | } 32 | -------------------------------------------------------------------------------- /_example/textview/textview.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mattn/go-gtk/gdk" 6 | "github.com/mattn/go-gtk/glib" 7 | "github.com/mattn/go-gtk/gtk" 8 | "unsafe" 9 | ) 10 | 11 | func main() { 12 | gtk.Init(nil) 13 | 14 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 15 | window.SetPosition(gtk.WIN_POS_CENTER) 16 | window.SetTitle("GTK Go!") 17 | window.SetIconName("textview") 18 | window.Connect("destroy", gtk.MainQuit) 19 | 20 | textview := gtk.NewTextView() 21 | textview.SetEditable(true) 22 | textview.SetCursorVisible(true) 23 | var iter gtk.TextIter 24 | buffer := textview.GetBuffer() 25 | 26 | buffer.GetStartIter(&iter) 27 | buffer.Insert(&iter, "Hello ") 28 | 29 | tag := buffer.CreateTag("bold", map[string]string{"background": "#FF0000", "weight": "700"}) 30 | buffer.InsertWithTag(&iter, "Google!", tag) 31 | 32 | u := "http://www.google.com" 33 | tag.SetData("tag-name", unsafe.Pointer(&u)) 34 | textview.Connect("event-after", func(ctx *glib.CallbackContext) { 35 | arg := ctx.Args(0) 36 | if ev := *(**gdk.EventAny)(unsafe.Pointer(&arg)); ev.Type != gdk.BUTTON_RELEASE { 37 | return 38 | } 39 | ev := *(**gdk.EventButton)(unsafe.Pointer(&arg)) 40 | var iter gtk.TextIter 41 | textview.GetIterAtLocation(&iter, int(ev.X), int(ev.Y)) 42 | tags := iter.GetTags() 43 | for n := uint(0); n < tags.Length(); n++ { 44 | vv := tags.NthData(n) 45 | tag := gtk.NewTextTagFromPointer(vv) 46 | u := *(*string)(tag.GetData("tag-name")) 47 | fmt.Println(u) 48 | } 49 | }) 50 | 51 | window.Add(textview) 52 | window.SetSizeRequest(600, 600) 53 | window.ShowAll() 54 | gtk.Main() 55 | } 56 | -------------------------------------------------------------------------------- /_example/thread/thread.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "runtime" 5 | "strconv" 6 | "time" 7 | 8 | "github.com/mattn/go-gtk/gdk" 9 | "github.com/mattn/go-gtk/glib" 10 | "github.com/mattn/go-gtk/gtk" 11 | ) 12 | 13 | func main() { 14 | runtime.GOMAXPROCS(10) 15 | glib.ThreadInit(nil) 16 | gdk.ThreadsInit() 17 | gdk.ThreadsEnter() 18 | gtk.Init(nil) 19 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 20 | window.Connect("destroy", gtk.MainQuit) 21 | 22 | vbox := gtk.NewVBox(false, 1) 23 | 24 | label1 := gtk.NewLabel("") 25 | vbox.Add(label1) 26 | label2 := gtk.NewLabel("") 27 | vbox.Add(label2) 28 | 29 | window.Add(vbox) 30 | 31 | window.SetSizeRequest(100, 100) 32 | window.ShowAll() 33 | time.Sleep(1000 * 1000 * 100) 34 | go (func() { 35 | for i := 0; i < 300000; i++ { 36 | gdk.ThreadsEnter() 37 | label1.SetLabel(strconv.Itoa(i)) 38 | gdk.ThreadsLeave() 39 | } 40 | gtk.MainQuit() 41 | })() 42 | go (func() { 43 | for i := 300000; i >= 0; i-- { 44 | gdk.ThreadsEnter() 45 | label2.SetLabel(strconv.Itoa(i)) 46 | gdk.ThreadsLeave() 47 | } 48 | gtk.MainQuit() 49 | })() 50 | gtk.Main() 51 | } 52 | -------------------------------------------------------------------------------- /_example/toolbar/toolbar.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mattn/go-gtk/glib" 6 | "github.com/mattn/go-gtk/gtk" 7 | ) 8 | 9 | func main() { 10 | gtk.Init(nil) 11 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 12 | window.SetPosition(gtk.WIN_POS_CENTER) 13 | window.SetTitle("GTK Go!") 14 | window.Connect("destroy", func(ctx *glib.CallbackContext) { 15 | gtk.MainQuit() 16 | }, "") 17 | 18 | vbox := gtk.NewVBox(false, 0) 19 | 20 | toolbar := gtk.NewToolbar() 21 | toolbar.SetStyle(gtk.TOOLBAR_ICONS) 22 | vbox.PackStart(toolbar, false, false, 5) 23 | 24 | btnnew := gtk.NewToolButtonFromStock(gtk.STOCK_NEW) 25 | btnclose := gtk.NewToolButtonFromStock(gtk.STOCK_CLOSE) 26 | separator := gtk.NewSeparatorToolItem() 27 | btncustom := gtk.NewToolButton(nil, "Custom") 28 | btnmenu := gtk.NewMenuToolButtonFromStock("gtk.STOCK_CLOSE") 29 | btnmenu.SetArrowTooltipText("This is a tool tip") 30 | 31 | btnnew.OnClicked(onToolButtonClicked) 32 | btnclose.OnClicked(onToolButtonClicked) 33 | btncustom.OnClicked(onToolButtonClicked) 34 | 35 | toolmenu := gtk.NewMenu() 36 | menuitem := gtk.NewMenuItemWithMnemonic("8") 37 | menuitem.Show() 38 | toolmenu.Append(menuitem) 39 | menuitem = gtk.NewMenuItemWithMnemonic("16") 40 | menuitem.Show() 41 | toolmenu.Append(menuitem) 42 | menuitem = gtk.NewMenuItemWithMnemonic("32") 43 | menuitem.Show() 44 | toolmenu.Append(menuitem) 45 | btnmenu.SetMenu(toolmenu) 46 | 47 | toolbar.Insert(btnnew, -1) 48 | toolbar.Insert(btnclose, -1) 49 | toolbar.Insert(separator, -1) 50 | toolbar.Insert(btncustom, -1) 51 | toolbar.Insert(btnmenu, -1) 52 | 53 | hbox := gtk.NewHBox(false, 0) 54 | vbox.PackStart(hbox, true, true, 0) 55 | 56 | toolbar2 := gtk.NewToolbar() 57 | toolbar2.SetOrientation(gtk.ORIENTATION_VERTICAL) 58 | hbox.PackStart(toolbar2, false, false, 5) 59 | btnhelp := gtk.NewToolButtonFromStock(gtk.STOCK_HELP) 60 | btnhelp.OnClicked(onToolButtonClicked) 61 | toolbar2.Insert(btnhelp, -1) 62 | 63 | btntoggle := gtk.NewToggleToolButton() 64 | btntoggle2 := gtk.NewToggleToolButtonFromStock(gtk.STOCK_ITALIC) 65 | toolbar2.Insert(btntoggle, -1) 66 | toolbar2.Insert(btntoggle2, -1) 67 | 68 | for i := 0; i < toolbar.GetNItems(); i++ { 69 | gti := toolbar.GetNthItem(i) 70 | switch gti.(type) { 71 | case *gtk.ToolButton: 72 | fmt.Printf("toolbar[%d] is a *gtk.ToolButton\n", i) 73 | w := gti.(*gtk.ToolButton).GetIconWidget() 74 | gti.(*gtk.ToolButton).SetIconWidget(w) 75 | case *gtk.ToggleToolButton: 76 | fmt.Printf("toolbar[%d] is a *gtk.ToggleToolButton\n", i) 77 | gti.(*gtk.ToggleToolButton).SetActive(true) 78 | case *gtk.SeparatorToolItem: 79 | fmt.Printf("toolbar[%d] is a *gtk.SeparatorToolItem\n", i) 80 | default: 81 | fmt.Printf("toolbar: Item is of unknown type\n") 82 | } 83 | } 84 | 85 | for i := 0; i < toolbar2.GetNItems(); i++ { 86 | gti := toolbar2.GetNthItem(i) 87 | switch gti.(type) { 88 | case *gtk.ToolButton: 89 | fmt.Printf("toolbar2[%d] is a *gtk.ToolButton\n", i) 90 | case *gtk.ToggleToolButton: 91 | fmt.Printf("toolbar2[%d] is a *gtk.ToggleToolButton\n", i) 92 | gti.(*gtk.ToggleToolButton).SetActive(true) 93 | case *gtk.SeparatorToolItem: 94 | fmt.Printf("toolbar2[%d] is a *gtk.SeparatorToolItem\n", i) 95 | default: 96 | fmt.Printf("toolbar2: Item is of unknown type\n") 97 | } 98 | } 99 | 100 | window.Add(vbox) 101 | window.SetSizeRequest(600, 600) 102 | window.ShowAll() 103 | gtk.Main() 104 | } 105 | 106 | func onToolButtonClicked() { 107 | fmt.Println("ToolButton clicked") 108 | } 109 | -------------------------------------------------------------------------------- /_example/toolpalette/toolpalette.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mattn/go-gtk/glib" 6 | "github.com/mattn/go-gtk/gtk" 7 | ) 8 | 9 | func main() { 10 | gtk.Init(nil) 11 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 12 | window.SetPosition(gtk.WIN_POS_CENTER) 13 | window.SetTitle("GTK Go!") 14 | window.Connect("destroy", func(ctx *glib.CallbackContext) { 15 | gtk.MainQuit() 16 | }, "") 17 | 18 | box := gtk.NewHPaned() 19 | 20 | palette := gtk.NewToolPalette() 21 | group := gtk.NewToolItemGroup("Tools") 22 | b := gtk.NewToolButtonFromStock(gtk.STOCK_NEW) 23 | b.OnClicked(func() { fmt.Println("You clicked new!") }) 24 | group.Insert(b, -1) 25 | b = gtk.NewToolButtonFromStock(gtk.STOCK_CLOSE) 26 | group.Insert(b, -1) 27 | b = gtk.NewToolButtonFromStock(gtk.STOCK_REDO) 28 | group.Insert(b, -1) 29 | b = gtk.NewToolButtonFromStock(gtk.STOCK_REFRESH) 30 | group.Insert(b, -1) 31 | b = gtk.NewToolButtonFromStock(gtk.STOCK_QUIT) 32 | group.Insert(b, -1) 33 | b = gtk.NewToolButtonFromStock(gtk.STOCK_YES) 34 | group.Insert(b, -1) 35 | b = gtk.NewToolButtonFromStock(gtk.STOCK_NO) 36 | group.Insert(b, -1) 37 | b = gtk.NewToolButtonFromStock(gtk.STOCK_PRINT) 38 | group.Insert(b, -1) 39 | b = gtk.NewToolButtonFromStock(gtk.STOCK_NETWORK) 40 | group.Insert(b, -1) 41 | b = gtk.NewToolButtonFromStock(gtk.STOCK_INFO) 42 | group.Insert(b, -1) 43 | b = gtk.NewToolButtonFromStock(gtk.STOCK_HOME) 44 | group.Insert(b, -1) 45 | b = gtk.NewToolButtonFromStock(gtk.STOCK_INDEX) 46 | group.Insert(b, -1) 47 | b = gtk.NewToolButtonFromStock(gtk.STOCK_FIND) 48 | group.Insert(b, -1) 49 | b = gtk.NewToolButtonFromStock(gtk.STOCK_FILE) 50 | group.Insert(b, -1) 51 | b = gtk.NewToolButtonFromStock(gtk.STOCK_EXECUTE) 52 | group.Insert(b, -1) 53 | palette.Add(group) 54 | 55 | bcopy := gtk.NewToolButtonFromStock(gtk.STOCK_COPY) 56 | bcut := gtk.NewToolButtonFromStock(gtk.STOCK_CUT) 57 | bdelete := gtk.NewToolButtonFromStock(gtk.STOCK_DELETE) 58 | 59 | group = gtk.NewToolItemGroup("Stuff") 60 | group.Insert(bcopy, -1) 61 | group.Insert(bcut, -1) 62 | group.Insert(bdelete, -1) 63 | palette.Add(group) 64 | 65 | frame := gtk.NewVBox(false, 1) 66 | align := gtk.NewAlignment(0, 0, 0, 0) 67 | image := gtk.NewImageFromFile("./turkey.jpg") 68 | align.Add(image) 69 | frame.Add(align) 70 | 71 | box.Pack1(palette, true, false) 72 | box.Pack2(frame, false, false) 73 | 74 | window.Add(box) 75 | window.SetSizeRequest(600, 600) 76 | window.ShowAll() 77 | gtk.Main() 78 | } 79 | -------------------------------------------------------------------------------- /_example/toolpalette/turkey.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/go-gtk/48574e312fac321db5119d8f2e7c8349cf44b92f/_example/toolpalette/turkey.jpg -------------------------------------------------------------------------------- /_example/treeview/treeview.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/mattn/go-gtk/gdkpixbuf" 5 | "github.com/mattn/go-gtk/glib" 6 | "github.com/mattn/go-gtk/gtk" 7 | "os" 8 | "strconv" 9 | ) 10 | 11 | func main() { 12 | gtk.Init(&os.Args) 13 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 14 | window.SetTitle("GTK Folder View") 15 | window.Connect("destroy", gtk.MainQuit) 16 | 17 | swin := gtk.NewScrolledWindow(nil, nil) 18 | 19 | store := gtk.NewTreeStore(gdkpixbuf.GetType(), glib.G_TYPE_STRING) 20 | treeview := gtk.NewTreeView() 21 | swin.Add(treeview) 22 | 23 | treeview.SetModel(store.ToTreeModel()) 24 | treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("pixbuf", gtk.NewCellRendererPixbuf(), "pixbuf", 0)) 25 | treeview.AppendColumn(gtk.NewTreeViewColumnWithAttributes("text", gtk.NewCellRendererText(), "text", 1)) 26 | 27 | for n := 1; n <= 10; n++ { 28 | var iter1, iter2, iter3 gtk.TreeIter 29 | store.Append(&iter1, nil) 30 | store.Set(&iter1, gtk.NewImage().RenderIcon(gtk.STOCK_DIRECTORY, gtk.ICON_SIZE_SMALL_TOOLBAR, "").GPixbuf, "Folder"+strconv.Itoa(n)) 31 | store.Append(&iter2, &iter1) 32 | store.Set(&iter2, gtk.NewImage().RenderIcon(gtk.STOCK_DIRECTORY, gtk.ICON_SIZE_SMALL_TOOLBAR, "").GPixbuf, "SubFolder"+strconv.Itoa(n)) 33 | store.Append(&iter3, &iter2) 34 | store.Set(&iter3, gtk.NewImage().RenderIcon(gtk.STOCK_FILE, gtk.ICON_SIZE_SMALL_TOOLBAR, "").GPixbuf, "File"+strconv.Itoa(n)) 35 | } 36 | 37 | treeview.Connect("row_activated", func() { 38 | var path *gtk.TreePath 39 | var column *gtk.TreeViewColumn 40 | treeview.GetCursor(&path, &column) 41 | mes := "TreePath is: " + path.String() 42 | dialog := gtk.NewMessageDialog( 43 | treeview.GetTopLevelAsWindow(), 44 | gtk.DIALOG_MODAL, 45 | gtk.MESSAGE_INFO, 46 | gtk.BUTTONS_OK, 47 | mes) 48 | dialog.SetTitle("TreePath") 49 | dialog.Response(func() { 50 | dialog.Destroy() 51 | }) 52 | dialog.Run() 53 | }) 54 | 55 | window.Add(swin) 56 | window.SetSizeRequest(400, 200) 57 | window.ShowAll() 58 | 59 | gtk.Main() 60 | } 61 | -------------------------------------------------------------------------------- /_example/twitterstream/settings.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "AccessSecret": "ACCCESS_TOKEN_SECRET", 3 | "AccessToken": "ACCESS_TOKEN", 4 | "ClientSecret": "CLIENT_SECRET", 5 | "ClientToken": "CLIENT_TOKEN" 6 | } 7 | -------------------------------------------------------------------------------- /_example/twitterstream/twitterstream.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "compress/gzip" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "log" 10 | "net/http" 11 | "net/url" 12 | "os" 13 | "runtime" 14 | "strings" 15 | "sync" 16 | 17 | "github.com/garyburd/go-oauth/oauth" 18 | "github.com/mattn/go-gtk/gdkpixbuf" 19 | "github.com/mattn/go-gtk/gtk" 20 | ) 21 | 22 | var ( 23 | alive = true 24 | ) 25 | 26 | func readURL(url string) ([]byte, *http.Response) { 27 | r, err := http.Get(url) 28 | if err != nil { 29 | return nil, nil 30 | } 31 | var b []byte 32 | if b, err = ioutil.ReadAll(r.Body); err != nil { 33 | return nil, nil 34 | } 35 | return b, r 36 | } 37 | 38 | func bytes2pixbuf(data []byte, typ string) *gdkpixbuf.Pixbuf { 39 | var loader *gdkpixbuf.Loader 40 | if strings.Index(typ, "jpeg") >= 0 { 41 | loader, _ = gdkpixbuf.NewLoaderWithMimeType("image/jpeg") 42 | } else { 43 | loader, _ = gdkpixbuf.NewLoaderWithMimeType("image/png") 44 | } 45 | loader.SetSize(24, 24) 46 | loader.Write(data) 47 | loader.Close() 48 | return loader.GetPixbuf() 49 | } 50 | 51 | type tweet struct { 52 | Text string 53 | Identifier string `json:"id_str"` 54 | Source string 55 | User struct { 56 | Name string 57 | ScreenName string `json:"screen_name"` 58 | FollowersCount int `json:"followers_count"` 59 | ProfileImageUrl string `json:"profile_image_url"` 60 | } 61 | Place *struct { 62 | Id string 63 | FullName string `json:"full_name"` 64 | } 65 | Entities struct { 66 | HashTags []struct { 67 | Indices [2]int 68 | Text string 69 | } 70 | UserMentions []struct { 71 | Indices [2]int 72 | ScreenName string `json:"screen_name"` 73 | } `json:"user_mentions"` 74 | Urls []struct { 75 | Indices [2]int 76 | Url string 77 | DisplayUrl string `json:"display_url"` 78 | ExpandedUrl *string `json:"expanded_url"` 79 | } 80 | } 81 | } 82 | 83 | func stream(client *oauth.Client, cred *oauth.Credentials, f func(*tweet)) { 84 | param := make(url.Values) 85 | uri := "https://userstream.twitter.com/1.1/user.json" 86 | client.SignParam(cred, "GET", uri, param) 87 | uri = uri + "?" + param.Encode() 88 | res, err := http.Get(uri) 89 | if err != nil { 90 | log.Fatal("failed to get tweets:", err) 91 | } 92 | defer res.Body.Close() 93 | if res.StatusCode != 200 { 94 | log.Fatal("failed to get tweets:", err) 95 | } 96 | var buf *bufio.Reader 97 | if res.Header.Get("Content-Encoding") == "gzip" { 98 | gr, err := gzip.NewReader(res.Body) 99 | if err != nil { 100 | log.Fatal("failed to make gzip decoder:", err) 101 | } 102 | buf = bufio.NewReader(gr) 103 | } else { 104 | buf = bufio.NewReader(res.Body) 105 | } 106 | var last []byte 107 | for alive { 108 | b, _, err := buf.ReadLine() 109 | last = append(last, b...) 110 | var t tweet 111 | err = json.Unmarshal(last, &t) 112 | if err != nil { 113 | continue 114 | } 115 | last = []byte{} 116 | if t.Text == "" { 117 | continue 118 | } 119 | f(&t) 120 | } 121 | } 122 | 123 | func post(client *oauth.Client, cred *oauth.Credentials, s string) { 124 | param := make(url.Values) 125 | param.Set("status", s) 126 | uri := "https://api.twitter.com/1.1/statuses/update.json" 127 | client.SignParam(cred, "POST", uri, param) 128 | res, err := http.PostForm(uri, url.Values(param)) 129 | if err != nil { 130 | log.Println("failed to post tweet:", err) 131 | return 132 | } 133 | defer res.Body.Close() 134 | if res.StatusCode != 200 { 135 | log.Println("failed to get timeline:", err) 136 | return 137 | } 138 | } 139 | 140 | func display(t *tweet, buffer *gtk.TextBuffer, tag *gtk.TextTag) { 141 | var iter gtk.TextIter 142 | pixbufbytes, resp := readURL(t.User.ProfileImageUrl) 143 | buffer.GetStartIter(&iter) 144 | if resp != nil { 145 | buffer.InsertPixbuf(&iter, bytes2pixbuf(pixbufbytes, resp.Header.Get("Content-Type"))) 146 | } 147 | buffer.Insert(&iter, " ") 148 | buffer.InsertWithTag(&iter, t.User.ScreenName, tag) 149 | buffer.Insert(&iter, ":"+t.Text+"\n") 150 | gtk.MainIterationDo(false) 151 | } 152 | 153 | func show(client *oauth.Client, cred *oauth.Credentials, f func(t *tweet)) { 154 | param := make(url.Values) 155 | uri := "https://api.twitter.com/1.1/statuses/home_timeline.json" 156 | client.SignParam(cred, "GET", uri, param) 157 | uri = uri + "?" + param.Encode() 158 | res, err := http.Get(uri) 159 | if err != nil { 160 | return 161 | } 162 | defer res.Body.Close() 163 | if res.StatusCode != 200 { 164 | return 165 | } 166 | var tweets []tweet 167 | json.NewDecoder(res.Body).Decode(&tweets) 168 | for _, t := range tweets { 169 | f(&t) 170 | } 171 | } 172 | 173 | func main() { 174 | b, err := ioutil.ReadFile("settings.json") 175 | if err != nil { 176 | fmt.Println(`"settings.json" not found: `, err) 177 | return 178 | } 179 | var config map[string]string 180 | err = json.Unmarshal(b, &config) 181 | if err != nil { 182 | fmt.Println(`can't read "settings.json": `, err) 183 | return 184 | } 185 | client := &oauth.Client{Credentials: oauth.Credentials{config["ClientToken"], config["ClientSecret"]}} 186 | cred := &oauth.Credentials{config["AccessToken"], config["AccessSecret"]} 187 | 188 | runtime.LockOSThread() 189 | gtk.Init(&os.Args) 190 | window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) 191 | window.SetTitle("Twitter!") 192 | window.Connect("destroy", gtk.MainQuit) 193 | 194 | vbox := gtk.NewVBox(false, 1) 195 | 196 | scrolledwin := gtk.NewScrolledWindow(nil, nil) 197 | textview := gtk.NewTextView() 198 | textview.SetEditable(false) 199 | textview.SetCursorVisible(false) 200 | scrolledwin.Add(textview) 201 | vbox.Add(scrolledwin) 202 | 203 | buffer := textview.GetBuffer() 204 | tag := buffer.CreateTag("blue", map[string]string{"foreground": "#0000FF", "weight": "700"}) 205 | 206 | hbox := gtk.NewHBox(false, 1) 207 | vbox.PackEnd(hbox, false, true, 5) 208 | 209 | label := gtk.NewLabel("Tweet") 210 | hbox.PackStart(label, false, false, 5) 211 | text := gtk.NewEntry() 212 | hbox.PackEnd(text, true, true, 5) 213 | 214 | text.Connect("activate", func() { 215 | t := text.GetText() 216 | text.SetText("") 217 | post(client, cred, t) 218 | }) 219 | 220 | window.Add(vbox) 221 | window.SetSizeRequest(800, 500) 222 | window.ShowAll() 223 | 224 | var mutex sync.Mutex 225 | 226 | go func() { 227 | show(client, cred, func(t *tweet) { 228 | mutex.Lock() 229 | display(t, buffer, tag) 230 | mutex.Unlock() 231 | }) 232 | 233 | stream(client, cred, func(t *tweet) { 234 | mutex.Lock() 235 | display(t, buffer, tag) 236 | var start, end gtk.TextIter 237 | buffer.GetIterAtLine(&start, buffer.GetLineCount()-2) 238 | buffer.GetEndIter(&end) 239 | buffer.Delete(&start, &end) 240 | mutex.Unlock() 241 | }) 242 | }() 243 | 244 | for alive { 245 | mutex.Lock() 246 | alive = gtk.MainIterationDo(false) 247 | mutex.Unlock() 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /data/go-gtk-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/go-gtk/48574e312fac321db5119d8f2e7c8349cf44b92f/data/go-gtk-logo.png -------------------------------------------------------------------------------- /data/mattn-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/go-gtk/48574e312fac321db5119d8f2e7c8349cf44b92f/data/mattn-logo.png -------------------------------------------------------------------------------- /data/win32-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/go-gtk/48574e312fac321db5119d8f2e7c8349cf44b92f/data/win32-demo.png -------------------------------------------------------------------------------- /data/win32-twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattn/go-gtk/48574e312fac321db5119d8f2e7c8349cf44b92f/data/win32-twitter.png -------------------------------------------------------------------------------- /gdk/gdk.go.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_GDK_H 2 | #define GO_GDK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static gchar* toGstr(char* s) { return (gchar*)s; } 12 | 13 | static void freeCstr(char* s) { free(s); } 14 | 15 | static GdkWindow* toGdkWindow(void* w) { return GDK_WINDOW(w); } 16 | static GdkDragContext* toGdkDragContext(void* l) { return (GdkDragContext*)l; } 17 | static GdkFont* toGdkFont(void* l) { return (GdkFont*)l; } 18 | 19 | static void* _gdk_display_get_default() { 20 | return (void*) gdk_display_get_default(); 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /gdk/gdk_freebsd.go: -------------------------------------------------------------------------------- 1 | gdk_linux.go -------------------------------------------------------------------------------- /gdk/gdk_linux.go: -------------------------------------------------------------------------------- 1 | // +build !cgocheck 2 | 3 | package gdk 4 | 5 | /* 6 | #include 7 | #include 8 | // #cgo pkg-config: gdk-2.0 gthread-2.0 9 | */ 10 | import "C" 11 | import "unsafe" 12 | 13 | func (v *Window) GetNativeWindowID() int32 { 14 | return int32(C.gdk_x11_drawable_get_xid((*C.GdkDrawable)(unsafe.Pointer(v.GWindow)))) 15 | } 16 | -------------------------------------------------------------------------------- /gdk/gdk_quartz_darwin.go: -------------------------------------------------------------------------------- 1 | // +build !with-x11 2 | 3 | package gdk 4 | 5 | /* 6 | #cgo pkg-config: gdk-2.0 gthread-2.0 7 | #cgo CFLAGS: -x objective-c 8 | 9 | #include 10 | #include 11 | 12 | // Must return void* to avoid "struct size calculation error off=8 bytesize=0" 13 | // See: 14 | // - https://github.com/golang/go/issues/12065 15 | // - http://thread0.me/2015/07/gogoa-cocoa-bindings-for-go/ 16 | void* getNsWindow(GdkWindow *w) { 17 | return (void*) gdk_quartz_window_get_nswindow(w); 18 | } 19 | 20 | */ 21 | import "C" 22 | 23 | import "unsafe" 24 | 25 | type NSWindow struct { 26 | ID unsafe.Pointer 27 | } 28 | 29 | func (v *Window) GetNativeWindow() *NSWindow { 30 | return &NSWindow{ 31 | unsafe.Pointer(C.getNsWindow(v.GWindow)), 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /gdk/gdk_windows.go: -------------------------------------------------------------------------------- 1 | // +build !cgocheck 2 | 3 | package gdk 4 | 5 | /* 6 | #include 7 | #include 8 | // #cgo pkg-config: gdk-2.0 gthread-2.0 9 | */ 10 | import "C" 11 | import "unsafe" 12 | 13 | func (v *Window) GetNativeWindowID() int32 { 14 | return int32(uintptr(unsafe.Pointer(C.gdk_win32_drawable_get_handle((*C.GdkDrawable)(unsafe.Pointer(v.GWindow)))))) 15 | } 16 | -------------------------------------------------------------------------------- /gdk/gdk_x11_darwin.go: -------------------------------------------------------------------------------- 1 | // +build with-x11 2 | 3 | package gdk 4 | 5 | /* 6 | #cgo pkg-config: gdk-2.0 gthread-2.0 7 | 8 | #include 9 | #include 10 | */ 11 | import "C" 12 | import "unsafe" 13 | 14 | func (v *Window) GetNativeWindowID() int32 { 15 | return int32(C.gdk_x11_drawable_get_xid((*C.GdkDrawable)(unsafe.Pointer(v.GWindow)))) 16 | } 17 | -------------------------------------------------------------------------------- /gdkpixbuf/gdkpixbuf.go: -------------------------------------------------------------------------------- 1 | // +build !cgocheck 2 | 3 | package gdkpixbuf 4 | 5 | // #include "gdkpixbuf.go.h" 6 | // #cgo pkg-config: gdk-pixbuf-2.0 7 | import "C" 8 | import ( 9 | "log" 10 | "runtime" 11 | "unsafe" 12 | 13 | "github.com/mattn/go-gtk/gio" 14 | "github.com/mattn/go-gtk/glib" 15 | ) 16 | 17 | // PixbufData is an inline/embedded image data object for usage with NewPixbufFromData. 18 | type PixbufData struct { 19 | Data []byte 20 | Colorspace Colorspace 21 | HasAlpha bool 22 | BitsPerSample, Width, Height, RowStride int 23 | } 24 | 25 | func gstring(s *C.char) *C.gchar { return C.toGstr(s) } 26 | func cstring(s *C.gchar) *C.char { return C.toCstr(s) } 27 | func gostring(s *C.gchar) string { return C.GoString(cstring(s)) } 28 | 29 | func gbool(b bool) C.gboolean { 30 | if b { 31 | return C.gboolean(1) 32 | } 33 | return C.gboolean(0) 34 | } 35 | 36 | func gobool(b C.gboolean) bool { 37 | if b != 0 { 38 | return true 39 | } 40 | return false 41 | } 42 | 43 | func cfree(s *C.char) { C.freeCstr(s) } 44 | 45 | func panic_if_version_older(major int, minor int, micro int, function string) { 46 | if C._check_version(C.int(major), C.int(minor), C.int(micro)) == 0 { 47 | log.Panicf("%s is not provided on your Glib, version %d.%d is required\n", function, major, minor) 48 | } 49 | } 50 | 51 | func panic_if_version_older_auto(major, minor, micro int) { 52 | if C._check_version(C.int(major), C.int(minor), C.int(micro)) != 0 { 53 | return 54 | } 55 | formatStr := "%s is not provided on your Glib, version %d.%d is required\n" 56 | if pc, _, _, ok := runtime.Caller(1); ok { 57 | log.Panicf(formatStr, runtime.FuncForPC(pc).Name(), major, minor) 58 | } else { 59 | log.Panicf("Glib version %d.%d is required (unknown caller, see stack)\n", 60 | major, minor) 61 | } 62 | } 63 | 64 | func deprecated_since(major int, minor int, micro int, function string) { 65 | if C._check_version(C.int(major), C.int(minor), C.int(micro)) != 0 { 66 | log.Printf("\nWarning: %s is deprecated since glib %d.%d\n", function, major, minor) 67 | } 68 | } 69 | 70 | func argumentPanic(message string) { 71 | if pc, _, _, ok := runtime.Caller(2); ok { 72 | log.Panicf("Arguments error: %s : %s\n", 73 | runtime.FuncForPC(pc).Name(), message) 74 | } else { 75 | log.Panicln("Arguments error: (unknown caller, see stack):", message) 76 | } 77 | } 78 | 79 | //----------------------------------------------------------------------- 80 | // Pixbuf 81 | //----------------------------------------------------------------------- 82 | type Pixbuf struct { 83 | *GdkPixbuf 84 | *glib.GObject 85 | } 86 | 87 | type GdkPixbuf struct { 88 | GPixbuf *C.GdkPixbuf 89 | } 90 | 91 | func NewGdkPixbuf(p unsafe.Pointer) *GdkPixbuf { 92 | return &GdkPixbuf{(*C.GdkPixbuf)(p)} 93 | } 94 | 95 | // File Loading 96 | // GdkPixbuf * gdk_pixbuf_new (GdkColorspace colorspace, gboolean has_alpha, int bits_per_sample, int width, int height); 97 | func NewPixbuf(colorspace Colorspace, hasAlpha bool, bitsPerSample, width, height int) *Pixbuf { 98 | gpixbuf := C.gdk_pixbuf_new( 99 | C.GdkColorspace(colorspace), 100 | gbool(hasAlpha), 101 | C.int(bitsPerSample), 102 | C.int(width), 103 | C.int(height), 104 | ) 105 | 106 | return &Pixbuf{ 107 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 108 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 109 | } 110 | } 111 | 112 | func NewPixbufFromFile(filename string) (*Pixbuf, *glib.Error) { 113 | var err *C.GError 114 | ptr := C.CString(filename) 115 | defer cfree(ptr) 116 | gpixbuf := C.gdk_pixbuf_new_from_file(ptr, &err) 117 | if err != nil { 118 | return nil, glib.ErrorFromNative(unsafe.Pointer(err)) 119 | } 120 | return &Pixbuf{ 121 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 122 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 123 | }, nil 124 | } 125 | 126 | func NewPixbufFromFileAtSize(filename string, width, heigth int) (*Pixbuf, *glib.Error) { 127 | var err *C.GError 128 | ptr := C.CString(filename) 129 | defer cfree(ptr) 130 | gpixbuf := C.gdk_pixbuf_new_from_file_at_size(ptr, C.int(width), C.int(heigth), &err) 131 | if err != nil { 132 | return nil, glib.ErrorFromNative(unsafe.Pointer(err)) 133 | } 134 | return &Pixbuf{ 135 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 136 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 137 | }, nil 138 | } 139 | 140 | func NewPixbufFromFileAtScale(filename string, width, height int, preserve_aspect_ratio bool) (*Pixbuf, *glib.Error) { 141 | var err *C.GError 142 | ptr := C.CString(filename) 143 | defer cfree(ptr) 144 | gpixbuf := C.gdk_pixbuf_new_from_file_at_scale(ptr, C.int(width), C.int(height), gbool(preserve_aspect_ratio), &err) 145 | if err != nil { 146 | return nil, glib.ErrorFromNative(unsafe.Pointer(err)) 147 | } 148 | return &Pixbuf{ 149 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 150 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 151 | }, nil 152 | } 153 | 154 | // NewPixbufFromData creates a Pixbuf from image data in a byte array 155 | func NewPixbufFromData(pbd PixbufData) *Pixbuf { 156 | gpixbuf := C.gdk_pixbuf_new_from_data( 157 | C.to_gucharptr(unsafe.Pointer(&pbd.Data[0])), 158 | C.GdkColorspace(pbd.Colorspace), 159 | gbool(pbd.HasAlpha), 160 | C.int(pbd.BitsPerSample), 161 | C.int(pbd.Width), 162 | C.int(pbd.Height), 163 | C.int(pbd.RowStride), 164 | nil, nil) 165 | return &Pixbuf{ 166 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 167 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 168 | } 169 | } 170 | 171 | // NewPixbufFromBytes creates a Pixbuf from image data in a byte array 172 | // 173 | // Can be used for reading Base64 encoded images easily with the output from base64.StdEncoding.DecodeString("...") 174 | func NewPixbufFromBytes(buffer []byte) (*Pixbuf, *glib.Error) { 175 | var err *C.GError 176 | loader := C.gdk_pixbuf_loader_new() 177 | C.gdk_pixbuf_loader_write(loader, C.to_gucharptr(unsafe.Pointer(&buffer[0])), C.gsize(len(buffer)), &err) 178 | gpixbuf := C.gdk_pixbuf_loader_get_pixbuf(loader) 179 | 180 | if err != nil { 181 | return nil, glib.ErrorFromNative(unsafe.Pointer(err)) 182 | } 183 | return &Pixbuf{ 184 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 185 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 186 | }, nil 187 | } 188 | 189 | func NewPixbufFromStream(stream *gio.GInputStream) (*Pixbuf, *glib.Error) { 190 | ptr := (*C.GInputStream)(unsafe.Pointer(stream.GInputStream)) 191 | 192 | var err *C.GError 193 | gpixbuf := C.gdk_pixbuf_new_from_stream(ptr, nil, &err) 194 | if err != nil { 195 | return nil, glib.ErrorFromNative(unsafe.Pointer(err)) 196 | } 197 | return &Pixbuf{ 198 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 199 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 200 | }, nil 201 | } 202 | 203 | func NewPixbufFromXpmData(data **byte) (*Pixbuf, *glib.Error) { 204 | var err *C.GError 205 | gpixbuf := C.gdk_pixbuf_new_from_xpm_data( 206 | (**C.char)(unsafe.Pointer(data)), 207 | ) 208 | if err != nil { 209 | return nil, glib.ErrorFromNative(unsafe.Pointer(err)) 210 | } 211 | return &Pixbuf{ 212 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 213 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 214 | }, nil 215 | } 216 | 217 | func GetType() int { 218 | return int(C.gdk_pixbuf_get_type()) 219 | } 220 | 221 | func GetFileInfo(filename string, width, height *int) *Format { 222 | ptr := C.CString(filename) 223 | defer cfree(ptr) 224 | 225 | var w, h C.gint 226 | format := &Format{C.gdk_pixbuf_get_file_info(gstring(ptr), &w, &h)} 227 | *width = int(w) 228 | *height = int(h) 229 | return format 230 | } 231 | 232 | // Scaling 233 | 234 | type InterpType int 235 | 236 | const ( 237 | INTERP_NEAREST InterpType = iota 238 | INTERP_TILES 239 | INTERP_BILINEAR 240 | INTERP_HYPER 241 | ) 242 | 243 | func (p *Pixbuf) ScaleSimple(width, height int, interp InterpType) *Pixbuf { 244 | gpixbuf := C.gdk_pixbuf_scale_simple(p.GPixbuf, C.int(width), C.int(height), C.GdkInterpType(interp)) 245 | return &Pixbuf{ 246 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 247 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 248 | } 249 | } 250 | 251 | func (p *Pixbuf) Scale(x, y, width, height int, offsetX, offsetY, scaleX, scaleY float64, interp InterpType) *Pixbuf { 252 | var gpixbuf *C.GdkPixbuf 253 | C.gdk_pixbuf_scale( 254 | p.GPixbuf, 255 | gpixbuf, 256 | C.int(x), C.int(y), 257 | C.int(width), C.int(height), 258 | C.double(offsetX), C.double(offsetY), 259 | C.double(scaleX), C.double(scaleY), 260 | C.GdkInterpType(interp)) 261 | return &Pixbuf{ 262 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 263 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 264 | } 265 | } 266 | 267 | // gdk_pixbuf_composite_color_simple 268 | // gdk_pixbuf_composite 269 | // gdk_pixbuf_composite_color 270 | 271 | type PixbufRotation int 272 | 273 | const ( 274 | PIXBUF_ROTATE_NONE PixbufRotation = 0 275 | PIXBUF_ROTATE_COUNTERCLOCKWISE PixbufRotation = 90 276 | PIXBUF_ROTATE_UPSIDEDOWN PixbufRotation = 180 277 | PIXBUF_ROTATE_CLOCKWISE PixbufRotation = 270 278 | ) 279 | 280 | func (p *Pixbuf) RotateSimple(angle PixbufRotation) *Pixbuf { 281 | gpixbuf := C.gdk_pixbuf_rotate_simple(p.GPixbuf, C.GdkPixbufRotation(angle)) 282 | return &Pixbuf{ 283 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 284 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 285 | } 286 | } 287 | 288 | func (p *Pixbuf) Flip(horizontal bool) *Pixbuf { 289 | gpixbuf := C.gdk_pixbuf_flip(p.GPixbuf, gbool(horizontal)) 290 | return &Pixbuf{ 291 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 292 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 293 | } 294 | } 295 | 296 | func (p *Pixbuf) Fill(pixel uint32) { 297 | C.gdk_pixbuf_fill(p.GPixbuf, C.guint32(pixel)) 298 | } 299 | 300 | // The GdkPixbuf Structure 301 | 302 | type Colorspace int 303 | 304 | const ( 305 | GDK_COLORSPACE_RGB Colorspace = iota 306 | ) 307 | 308 | type PixbufAlphaMode int 309 | 310 | const ( 311 | GDK_PIXBUF_ALPHA_BILEVEL PixbufAlphaMode = iota 312 | GDK_PIXBUF_ALPHA_FULL 313 | ) 314 | 315 | func (p *Pixbuf) GetColorspace() Colorspace { 316 | return Colorspace(C.gdk_pixbuf_get_colorspace(p.GPixbuf)) 317 | } 318 | 319 | func (p *Pixbuf) GetNChannels() int { 320 | return int(C.gdk_pixbuf_get_n_channels(p.GPixbuf)) 321 | } 322 | 323 | func (p *Pixbuf) GetHasAlpha() bool { 324 | return gobool(C.gdk_pixbuf_get_has_alpha(p.GPixbuf)) 325 | } 326 | 327 | func (p *Pixbuf) GetBitsPerSample() int { 328 | return int(C.gdk_pixbuf_get_bits_per_sample(p.GPixbuf)) 329 | } 330 | 331 | func (p *Pixbuf) GetPixels() []byte { 332 | ptr := C.gdk_pixbuf_get_pixels( 333 | p.GPixbuf, 334 | ) 335 | return (*[1 << 30]byte)(unsafe.Pointer(ptr))[:] 336 | } 337 | 338 | // guchar * gdk_pixbuf_get_pixels_with_length (const GdkPixbuf *pixbuf, guint *length); 339 | // 340 | // Retuns a slice of byte backed by a C array of pixbuf data. 341 | func (p *Pixbuf) GetPixelsWithLength() []byte { 342 | panic_if_version_older(2, 26, 0, "gdk_pixbuf_get_pixels_with_length()") 343 | length := C.guint(0) 344 | ptr := C._gdk_pixbuf_get_pixels_with_length( 345 | p.GPixbuf, 346 | &length, 347 | ) 348 | return (*[1 << 30]byte)(unsafe.Pointer(ptr))[:length] 349 | } 350 | 351 | func (p *Pixbuf) GetWidth() int { 352 | return int(C.gdk_pixbuf_get_width(p.GPixbuf)) 353 | } 354 | 355 | func (p *Pixbuf) GetHeight() int { 356 | return int(C.gdk_pixbuf_get_height(p.GPixbuf)) 357 | } 358 | 359 | func (p *Pixbuf) GetRowstride() int { 360 | return int(C.gdk_pixbuf_get_rowstride(p.GPixbuf)) 361 | } 362 | 363 | // gdk_pixbuf_get_byte_length 364 | // gdk_pixbuf_get_option 365 | 366 | // File saving 367 | 368 | func (p *Pixbuf) Save(filename, savetype string, options ...string) *glib.Error { 369 | if len(options)%2 != 0 { 370 | argumentPanic("Save options must be even (key and value)") 371 | } 372 | 373 | pfilename := C.CString(filename) 374 | defer cfree(pfilename) 375 | psavetype := C.CString(savetype) 376 | defer cfree(psavetype) 377 | 378 | klen := len(options) / 2 379 | keys := C.makeCstrv(C.int(klen + 1)) 380 | vals := C.makeCstrv(C.int(klen + 1)) 381 | for i := 0; i < klen; i++ { 382 | C.setCstr(keys, C.int(i), C.CString(options[2*i])) 383 | C.setCstr(vals, C.int(i), C.CString(options[2*i+1])) 384 | } 385 | C.setCstr(keys, C.int(klen), nil) 386 | C.setCstr(vals, C.int(klen), nil) 387 | defer func() { 388 | for i := 0; i < klen; i++ { 389 | cfree(C.getCstr(keys, C.int(i))) 390 | cfree(C.getCstr(vals, C.int(i))) 391 | } 392 | C.freeCstrv(keys) 393 | C.freeCstrv(vals) 394 | }() 395 | 396 | var err *C.GError 397 | C.gdk_pixbuf_savev(p.GPixbuf, pfilename, psavetype, keys, vals, &err) 398 | if err != nil { 399 | return glib.ErrorFromNative(unsafe.Pointer(err)) 400 | } 401 | return nil 402 | } 403 | 404 | //----------------------------------------------------------------------- 405 | // Animation 406 | //----------------------------------------------------------------------- 407 | type Animation struct { 408 | GPixbufAnimation *C.GdkPixbufAnimation 409 | } 410 | 411 | //----------------------------------------------------------------------- 412 | // Format 413 | //----------------------------------------------------------------------- 414 | type Format struct { 415 | GPixbufFormat *C.GdkPixbufFormat 416 | } 417 | 418 | // gdk_pixbuf_get_formats 419 | 420 | func (v *Format) GetName() string { 421 | return gostring(C.gdk_pixbuf_format_get_name(v.GPixbufFormat)) 422 | } 423 | 424 | func (v *Format) GetDescription() string { 425 | return gostring(C.gdk_pixbuf_format_get_description(v.GPixbufFormat)) 426 | } 427 | 428 | func (v *Format) GetMimeTypes() []string { 429 | gstrv := C.gdk_pixbuf_format_get_mime_types(v.GPixbufFormat) 430 | defer C.g_strfreev(gstrv) 431 | s := make([]string, 0) 432 | for i := 0; C.getGstr(gstrv, C.int(i)) != nil; i++ { 433 | s = append(s, gostring(C.getGstr(gstrv, C.int(i)))) 434 | } 435 | return s 436 | } 437 | 438 | func (v *Format) GetExtensions() []string { 439 | gstrv := C.gdk_pixbuf_format_get_extensions(v.GPixbufFormat) 440 | defer C.g_strfreev(gstrv) 441 | s := make([]string, 0) 442 | for i := 0; C.getGstr(gstrv, C.int(i)) != nil; i++ { 443 | s = append(s, gostring(C.getGstr(gstrv, C.int(i)))) 444 | } 445 | return s 446 | } 447 | 448 | func (v *Format) IsWritable() bool { 449 | return gobool(C.gdk_pixbuf_format_is_writable(v.GPixbufFormat)) 450 | } 451 | 452 | func (v *Format) IsScalable() bool { 453 | return gobool(C.gdk_pixbuf_format_is_scalable(v.GPixbufFormat)) 454 | } 455 | 456 | func (v *Format) IsDisabled() bool { 457 | return gobool(C.gdk_pixbuf_format_is_disabled(v.GPixbufFormat)) 458 | } 459 | 460 | func (v *Format) SetDisabled(disabled bool) { 461 | C.gdk_pixbuf_format_set_disabled(v.GPixbufFormat, gbool(disabled)) 462 | } 463 | 464 | func (v *Format) GetLicense() string { 465 | return gostring(C.gdk_pixbuf_format_get_license(v.GPixbufFormat)) 466 | } 467 | 468 | //----------------------------------------------------------------------- 469 | // Loader 470 | //----------------------------------------------------------------------- 471 | type Loader struct { 472 | GPixbufLoader *C.GdkPixbufLoader 473 | } 474 | 475 | func NewLoader() *Loader { 476 | return &Loader{ 477 | C.gdk_pixbuf_loader_new()} 478 | } 479 | 480 | func NewLoaderWithType(image_type string) (loader *Loader, err *glib.Error) { 481 | var gerr *C.GError 482 | ptr := C.CString(image_type) 483 | defer cfree(ptr) 484 | loader = &Loader{ 485 | C.gdk_pixbuf_loader_new_with_type(ptr, &gerr)} 486 | if gerr != nil { 487 | err = glib.ErrorFromNative(unsafe.Pointer(gerr)) 488 | } 489 | return 490 | } 491 | 492 | func NewLoaderWithMimeType(mime_type string) (loader *Loader, err *glib.Error) { 493 | var error *C.GError 494 | ptr := C.CString(mime_type) 495 | defer cfree(ptr) 496 | loader = &Loader{ 497 | C.gdk_pixbuf_loader_new_with_mime_type(ptr, &error)} 498 | err = glib.ErrorFromNative(unsafe.Pointer(error)) 499 | return 500 | } 501 | 502 | func (v Loader) GetPixbuf() *Pixbuf { 503 | gpixbuf := C.gdk_pixbuf_loader_get_pixbuf(v.GPixbufLoader) 504 | return &Pixbuf{ 505 | GdkPixbuf: &GdkPixbuf{gpixbuf}, 506 | GObject: glib.ObjectFromNative(unsafe.Pointer(gpixbuf)), 507 | } 508 | } 509 | 510 | func (v Loader) Write(buf []byte) (bool, *glib.Error) { 511 | var err *C.GError 512 | var pbuf *byte 513 | pbuf = &buf[0] 514 | ret := gobool(C.gdk_pixbuf_loader_write(v.GPixbufLoader, C.to_gucharptr(unsafe.Pointer(pbuf)), C.gsize(len(buf)), &err)) 515 | if err != nil { 516 | return ret, glib.ErrorFromNative(unsafe.Pointer(err)) 517 | } 518 | return ret, nil 519 | } 520 | 521 | func (v Loader) Close() (bool, *glib.Error) { 522 | var err *C.GError 523 | ret := gobool(C.gdk_pixbuf_loader_close(v.GPixbufLoader, &err)) 524 | if err != nil { 525 | return ret, glib.ErrorFromNative(unsafe.Pointer(err)) 526 | } 527 | return ret, nil 528 | } 529 | 530 | //func (v Loader) GetPixbufAnimation() *Animation { 531 | // return &Animation { 532 | // C.gdk_pixbuf_loader_get_animation(v.GPixbufLoader) }; 533 | //} 534 | func (v Loader) SetSize(width int, height int) { 535 | C.gdk_pixbuf_loader_set_size(v.GPixbufLoader, C.int(width), C.int(height)) 536 | } 537 | 538 | func (v Loader) GetFormat() *Format { 539 | return &Format{ 540 | C.gdk_pixbuf_loader_get_format(v.GPixbufLoader)} 541 | } 542 | 543 | // FINISH 544 | -------------------------------------------------------------------------------- /gdkpixbuf/gdkpixbuf.go.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_GDK_PIXBUF_H 2 | #define GO_GDK_PIXBUF_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //static const gchar* to_gcharptr(const char* s) { return (const gchar*)s; } 12 | static guchar* to_gucharptr(void* s) { return (guchar*)s; } 13 | 14 | static inline GdkPixbuf* toGdkPixbuf(void* p) { return GDK_PIXBUF(p); } 15 | 16 | static inline gchar* toGstr(const char* s) { return (gchar*)s; } 17 | static inline char* toCstr(const gchar* s) { return (char*)s; } 18 | 19 | static inline void freeCstr(char* s) { free(s); } 20 | 21 | static inline char** makeCstrv(int count) { 22 | return (char**)malloc(sizeof(char*) * count); 23 | } 24 | 25 | static guchar* _gdk_pixbuf_get_pixels_with_length(const GdkPixbuf *pixbuf, guint *length) { 26 | #if GDK_PIXBUF_MAJOR >= 2 && GDK_PIXBUF_MINOR >= 26 27 | return gdk_pixbuf_get_pixels_with_length(pixbuf, length); 28 | #else 29 | return NULL; 30 | #endif 31 | } 32 | 33 | // 34 | static inline void freeCstrv(char** cstrv) { free(cstrv); } 35 | static inline char* getCstr(char** cstrv, int n) { return cstrv[n]; } 36 | static inline void setCstr(char** cstrv, int n, char* str) { cstrv[n] = str; } 37 | static inline gchar* getGstr(gchar** gstrv, int n) { return gstrv[n]; } 38 | 39 | static int _check_version(int major, int minor, int micro) { 40 | if (GDK_PIXBUF_MAJOR > major) return 1; 41 | if (GDK_PIXBUF_MAJOR < major) return 0; 42 | if (GDK_PIXBUF_MINOR > minor) return 1; 43 | if (GDK_PIXBUF_MINOR < minor) return 0; 44 | if (GDK_PIXBUF_MICRO > micro) return 1; 45 | return 0; 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /gio/gio.go: -------------------------------------------------------------------------------- 1 | package gio 2 | 3 | // #include "gio.go.h" 4 | // #cgo pkg-config: gio-2.0 5 | import "C" 6 | import ( 7 | "unsafe" 8 | 9 | "github.com/mattn/go-gtk/glib" 10 | ) 11 | 12 | func cfree(s *C.char) { C.freeCstr(s) } 13 | func gstring(s *C.char) *C.gchar { return C.toGstr(s) } 14 | func cstring(s *C.gchar) *C.char { return C.toCstr(s) } 15 | func gostring(s *C.gchar) string { return C.GoString(cstring(s)) } 16 | 17 | //----------------------------------------------------------------------- 18 | // GFile 19 | //----------------------------------------------------------------------- 20 | type GFile struct { 21 | GFile *C.GFile 22 | } 23 | 24 | // NewGFileForPath is g_file_new_for_path 25 | func NewGFileForPath(filename string) *GFile { 26 | ptrFilename := C.CString(filename) 27 | defer cfree(ptrFilename) 28 | 29 | return &GFile{C.g_file_new_for_path(ptrFilename)} 30 | } 31 | 32 | // NewGFileForURI is g_file_new_for_uri 33 | func NewGFileForURI(uriFilename string) *GFile { 34 | ptrFilename := C.CString(uriFilename) 35 | defer cfree(ptrFilename) 36 | 37 | return &GFile{C.g_file_new_for_uri(ptrFilename)} 38 | } 39 | 40 | type GFileQueryInfoFlags C.GFileQueryInfoFlags 41 | 42 | var ( 43 | GFileQueryInfoNone GFileQueryInfoFlags = C.G_FILE_QUERY_INFO_NONE 44 | GFileQueryInfoNoFollowSymlinks GFileQueryInfoFlags = C.G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS 45 | ) 46 | 47 | // QueryInfo is g_file_query_info 48 | func (f *GFile) QueryInfo(attributes string, flags GFileQueryInfoFlags) (*GFileInfo, error) { 49 | ptr := C.CString(attributes) 50 | defer cfree(ptr) 51 | 52 | var gerror *C.GError 53 | 54 | gfileinfo := C.g_file_query_info( 55 | f.GFile, 56 | ptr, 57 | C.GFileQueryInfoFlags(flags), 58 | nil, // nil is GCancellable, not yet implemented 59 | &gerror, 60 | ) 61 | if gerror != nil { 62 | return nil, glib.ErrorFromNative(unsafe.Pointer(gerror)) 63 | } 64 | 65 | return &GFileInfo{gfileinfo}, nil 66 | } 67 | 68 | // GetPath is `g_file_get_path`, return real, absolute, canonical path. It might contain symlinks. 69 | func (f *GFile) GetPath() string { 70 | return gostring(gstring(C.g_file_get_path(f.GFile))) 71 | } 72 | 73 | //----------------------------------------------------------------------- 74 | // GFileInfo 75 | //----------------------------------------------------------------------- 76 | type GFileInfo struct { 77 | GFileInfo *C.GFileInfo 78 | } 79 | 80 | // GetSymbolicIcon is g_file_info_get_symbolic_icon 81 | func (fi *GFileInfo) GetSymbolicIcon() *GIcon { 82 | return &GIcon{C.g_file_info_get_symbolic_icon(fi.GFileInfo)} 83 | } 84 | 85 | // GetIcon is g_file_info_get_icon 86 | func (fi *GFileInfo) GetIcon() *GIcon { 87 | return &GIcon{C.g_file_info_get_icon(fi.GFileInfo)} 88 | } 89 | 90 | //----------------------------------------------------------------------- 91 | // GIcon 92 | //----------------------------------------------------------------------- 93 | type GIcon struct { 94 | GIcon *C.GIcon 95 | } 96 | 97 | //ToString is g_icon_to_string 98 | func (icon *GIcon) ToString() string { 99 | return gostring(C.g_icon_to_string(icon.GIcon)) 100 | } 101 | 102 | type GInputStream struct { 103 | GInputStream *C.GInputStream 104 | } 105 | 106 | func NewMemoryInputStreamFromBytes(buffer []byte) *GInputStream { 107 | pbyt := &buffer[0] 108 | gbytes := C.g_bytes_new_take(C.gpointer(unsafe.Pointer(pbyt)), C.gsize(len(buffer))) 109 | 110 | stream := C.g_memory_input_stream_new_from_bytes(gbytes) 111 | return &GInputStream{stream} 112 | } 113 | 114 | func NewCancellable() *C.GCancellable { 115 | return C.g_cancellable_new() 116 | } 117 | -------------------------------------------------------------------------------- /gio/gio.go.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_GIO_H 2 | #define GO_GIO_H 3 | 4 | #include 5 | 6 | #endif 7 | 8 | #include 9 | 10 | static inline void freeCstr(char* s) { free(s); } 11 | static inline gchar* toGstr(const char* s) { return (gchar*)s; } 12 | static inline char* toCstr(const gchar* s) { return (char*)s; } 13 | -------------------------------------------------------------------------------- /glib/glib.go: -------------------------------------------------------------------------------- 1 | // +build !cgocheck 2 | 3 | package glib 4 | 5 | // #include "glib.go.h" 6 | // #cgo pkg-config: glib-2.0 gobject-2.0 7 | import "C" 8 | import ( 9 | "reflect" 10 | "sync" 11 | "unsafe" 12 | ) 13 | 14 | type ContextStorage struct { 15 | lastId int 16 | m sync.Mutex 17 | values map[int]interface{} 18 | } 19 | 20 | func NewContextStorage() *ContextStorage { 21 | return &ContextStorage{values: make(map[int]interface{})} 22 | } 23 | 24 | func (c *ContextStorage) Add(value interface{}) int { 25 | c.m.Lock() 26 | newId := c.lastId 27 | c.values[newId] = value 28 | c.lastId++ 29 | c.m.Unlock() 30 | return newId 31 | } 32 | 33 | func (c *ContextStorage) Get(id int) (value interface{}, found bool) { 34 | c.m.Lock() 35 | value, found = c.values[id] 36 | c.m.Unlock() 37 | return 38 | } 39 | 40 | func (c *ContextStorage) Remove(id int) { 41 | c.m.Lock() 42 | delete(c.values, id) 43 | c.m.Unlock() 44 | } 45 | 46 | func (c *ContextStorage) Len() int { 47 | c.m.Lock() 48 | result := len(c.values) 49 | c.m.Unlock() 50 | return result 51 | } 52 | 53 | var ( 54 | sourcefunc_contexts = NewContextStorage() 55 | callback_contexts = NewContextStorage() 56 | ) 57 | 58 | func gbool(b bool) C.gboolean { 59 | if b { 60 | return C.gboolean(1) 61 | } 62 | return C.gboolean(0) 63 | } 64 | 65 | func gobool(b C.gboolean) bool { 66 | if b != 0 { 67 | return true 68 | } 69 | return false 70 | } 71 | 72 | // converts a C string array to a Go string slice 73 | func toSlice(ar **C.gchar) []string { 74 | result := make([]string, 0) 75 | for i := 0; ; i++ { 76 | str := C.GoString(C.to_charptr(*ar)) 77 | if str == "" { 78 | break 79 | } 80 | result = append(result, str) 81 | *ar = C.next_string(*ar) 82 | } 83 | return result 84 | } 85 | 86 | func GPtrToString(p interface{}) string { 87 | pp := (C.gpointer)(p.(unsafe.Pointer)) 88 | return C.GoString(C.to_charptr_from_gpointer(pp)) 89 | } 90 | 91 | //----------------------------------------------------------------------- 92 | // Application 93 | //----------------------------------------------------------------------- 94 | func GetApplicationName() string { 95 | return C.GoString(C.to_charptr(C.g_get_application_name())) 96 | } 97 | 98 | func SetApplicationName(name string) { 99 | str := C.CString(name) 100 | defer C.free_string(str) 101 | C.g_set_application_name(C.to_gcharptr(str)) 102 | } 103 | 104 | func GetPrgName() string { 105 | return C.GoString(C.to_charptr(C.g_get_prgname())) 106 | } 107 | 108 | func SetPrgname(name string) { 109 | str := C.CString(name) 110 | defer C.free_string(str) 111 | C.g_set_prgname(C.to_gcharptr(str)) 112 | } 113 | 114 | //----------------------------------------------------------------------- 115 | // User Information 116 | //----------------------------------------------------------------------- 117 | func GetUserName() string { 118 | return C.GoString(C.to_charptr(C.g_get_user_name())) 119 | } 120 | 121 | func GetRealName() string { 122 | return C.GoString(C.to_charptr(C.g_get_real_name())) 123 | } 124 | 125 | func GetUserCacheDir() string { 126 | return C.GoString(C.to_charptr(C.g_get_user_cache_dir())) 127 | } 128 | 129 | func GetUserDataDir() string { 130 | return C.GoString(C.to_charptr(C.g_get_user_data_dir())) 131 | } 132 | 133 | func GetUserConfigDir() string { 134 | return C.GoString(C.to_charptr(C.g_get_user_config_dir())) 135 | } 136 | 137 | func GetUserRuntimeDir() string { 138 | return C.GoString(C.to_charptr(C.g_get_user_runtime_dir())) 139 | } 140 | 141 | type ConnectFlags C.GConnectFlags 142 | 143 | const ( 144 | ConnectAfter ConnectFlags = C.G_CONNECT_AFTER 145 | ConnectSwapped ConnectFlags = C.G_CONNECT_SWAPPED 146 | ) 147 | 148 | type UserDirectory C.GUserDirectory 149 | 150 | const ( 151 | UserDirectoryDesktop UserDirectory = C.G_USER_DIRECTORY_DESKTOP 152 | UserDirectoryDocuments UserDirectory = C.G_USER_DIRECTORY_DOCUMENTS 153 | UserDirectoryDownload UserDirectory = C.G_USER_DIRECTORY_DOWNLOAD 154 | UserDirectoryMusic UserDirectory = C.G_USER_DIRECTORY_MUSIC 155 | UserDirectoryPictures UserDirectory = C.G_USER_DIRECTORY_PICTURES 156 | UserDirectoryPublicShare UserDirectory = C.G_USER_DIRECTORY_PUBLIC_SHARE 157 | UserDirectoryTemplates UserDirectory = C.G_USER_DIRECTORY_TEMPLATES 158 | UserDirectoryVideos UserDirectory = C.G_USER_DIRECTORY_VIDEOS 159 | ) 160 | 161 | func GetUserSpecialDir(directory UserDirectory) string { 162 | result := C.g_get_user_special_dir(C.GUserDirectory(directory)) 163 | return C.GoString(C.to_charptr(result)) 164 | } 165 | 166 | func ReloadUserSpecialDirsCache() { 167 | C.g_reload_user_special_dirs_cache() 168 | } 169 | 170 | //----------------------------------------------------------------------- 171 | // System Information 172 | //----------------------------------------------------------------------- 173 | func GetSystemDataDirs() []string { 174 | return toSlice(C.g_get_system_data_dirs()) 175 | } 176 | 177 | func GetSystemConfigDirs() []string { 178 | return toSlice(C.g_get_system_config_dirs()) 179 | } 180 | 181 | func GetHostName() string { 182 | return C.GoString(C.to_charptr(C.g_get_host_name())) 183 | } 184 | 185 | func GetHomeDir() string { 186 | return C.GoString(C.to_charptr(C.g_get_home_dir())) 187 | } 188 | 189 | func GetTmpDir() string { 190 | return C.GoString(C.to_charptr(C.g_get_tmp_dir())) 191 | } 192 | 193 | func GetCurrentDir() string { 194 | return C.GoString(C.to_charptr(C.g_get_current_dir())) 195 | } 196 | 197 | //----------------------------------------------------------------------- 198 | // String Convert 199 | //----------------------------------------------------------------------- 200 | func Utf8Validate(str []byte, len int, bar **byte) bool { 201 | return gobool(C._g_utf8_validate(unsafe.Pointer(&str[0]), 202 | C.int(len), unsafe.Pointer(bar))) 203 | } 204 | 205 | func FilenameFromUri(uri string) (filename string, hostname string, err error) { 206 | str := C.CString(uri) 207 | defer C.free_string(str) 208 | var gerror *C.GError 209 | var ptr *C.gchar 210 | filename = C.GoString(C.to_charptr(C.g_filename_from_uri(C.to_gcharptr(str), &ptr, &gerror))) 211 | if unsafe.Pointer(gerror) != nil { 212 | err = ErrorFromNative(unsafe.Pointer(gerror)) 213 | } else { 214 | err = nil 215 | } 216 | hostname = "" 217 | if ptr != nil { 218 | hostname = C.GoString(C.to_charptr(ptr)) 219 | } 220 | return 221 | } 222 | 223 | func FilenameToUri(filename string, hostname string) (uri string, err error) { 224 | pfilename := C.CString(filename) 225 | defer C.free_string(pfilename) 226 | phostname := C.CString(hostname) 227 | defer C.free_string(phostname) 228 | var gerror *C.GError 229 | uri = C.GoString(C.to_charptr(C.g_filename_to_uri(C.to_gcharptr(pfilename), C.to_gcharptr(phostname), &gerror))) 230 | if unsafe.Pointer(gerror) != nil { 231 | err = ErrorFromNative(unsafe.Pointer(gerror)) 232 | } else { 233 | err = nil 234 | } 235 | return 236 | } 237 | 238 | func LocaleToUtf8(opsysstring []byte) (ret string, bytes_read int, bytes_written int, err *Error) { 239 | var gerror *C.GError 240 | var cbytes_read, cbytes_written C.int 241 | str := C._g_locale_to_utf8(unsafe.Pointer(&opsysstring[0]), C.int(len(opsysstring)), &cbytes_read, &cbytes_written, &gerror) 242 | if unsafe.Pointer(str) != nil { 243 | defer C.free_string(C.to_charptr(str)) 244 | ret = C.GoString(C.to_charptr(str)) 245 | } else { 246 | ret = "" 247 | } 248 | bytes_read = int(cbytes_read) 249 | bytes_written = int(cbytes_written) 250 | if unsafe.Pointer(gerror) != nil { 251 | err = ErrorFromNative(unsafe.Pointer(gerror)) 252 | } else { 253 | err = nil 254 | } 255 | return 256 | } 257 | 258 | func LocaleFromUtf8(utf8string string) (ret []byte, bytes_read int, bytes_written int, err *Error) { 259 | var gerror *C.GError 260 | var cbytes_read, cbytes_written C.int 261 | src := C.CString(utf8string) 262 | defer C.free_string(src) 263 | str := C._g_locale_from_utf8(src, C.int(C.strlen(src)), &cbytes_read, &cbytes_written, &gerror) 264 | if unsafe.Pointer(str) != nil { 265 | defer C.free_string(C.to_charptr(str)) 266 | ret = ([]byte)(C.GoString(C.to_charptr(str))) 267 | } else { 268 | ret = ([]byte)("") 269 | } 270 | bytes_read = int(cbytes_read) 271 | bytes_written = int(cbytes_written) 272 | if unsafe.Pointer(gerror) != nil { 273 | err = ErrorFromNative(unsafe.Pointer(gerror)) 274 | } else { 275 | err = nil 276 | } 277 | return 278 | } 279 | 280 | //----------------------------------------------------------------------- 281 | // List 282 | //----------------------------------------------------------------------- 283 | type List struct { 284 | GList *C.GList 285 | } 286 | 287 | func ListFromNative(l unsafe.Pointer) *List { 288 | return &List{ 289 | C.to_list(l)} 290 | } 291 | 292 | func (v List) Data() interface{} { 293 | return v.GList.data 294 | } 295 | 296 | func (v List) Append(data unsafe.Pointer) *List { 297 | return &List{C.g_list_append(v.GList, C.gpointer(data))} 298 | } 299 | 300 | func (v List) Prepend(data unsafe.Pointer) *List { 301 | return &List{C.g_list_prepend(v.GList, C.gpointer(data))} 302 | } 303 | 304 | func (v List) Insert(data unsafe.Pointer, pos int) *List { 305 | return &List{C.g_list_insert(v.GList, C.gpointer(data), C.gint(pos))} 306 | } 307 | 308 | func (v List) InsertBefore(sib List, data unsafe.Pointer) *List { 309 | return &List{C.g_list_insert_before(v.GList, sib.GList, C.gpointer(data))} 310 | } 311 | 312 | //GList* g_list_insert_sorted (GList *list, 313 | // gpointer data, 314 | // GCompareFunc func); 315 | func (v List) Remove(data unsafe.Pointer) *List { 316 | return &List{C.g_list_remove(v.GList, C.gconstpointer(data))} 317 | } 318 | 319 | func (v List) RemoveLink(link List) *List { 320 | return &List{C.g_list_remove_link(v.GList, link.GList)} 321 | } 322 | 323 | func (v List) DeleteLink(link List) *List { 324 | return &List{C.g_list_delete_link(v.GList, link.GList)} 325 | } 326 | 327 | func (v List) RemoveAll(data unsafe.Pointer) *List { 328 | return &List{C.g_list_remove_all(v.GList, C.gconstpointer(data))} 329 | } 330 | 331 | func (v List) Free() { 332 | C.g_list_free(v.GList) 333 | } 334 | 335 | func GListAlloc() *List { 336 | return &List{C.g_list_alloc()} 337 | } 338 | 339 | func (v List) Free1() { 340 | C.g_list_free_1(v.GList) 341 | } 342 | 343 | func (v List) Length() uint { 344 | return uint(C.g_list_length(v.GList)) 345 | } 346 | 347 | func (v List) Copy() *List { 348 | return &List{C.g_list_copy(v.GList)} 349 | } 350 | 351 | func (v List) Reverse() *List { 352 | return &List{C.g_list_reverse(v.GList)} 353 | } 354 | 355 | //GList* g_list_sort (GList *list, 356 | // GCompareFunc compare_func); 357 | //gint (*GCompareFunc) (gconstpointer a, 358 | // gconstpointer b); 359 | //GList* g_list_insert_sorted_with_data (GList *list, 360 | // gpointer data, 361 | // GCompareDataFunc func, 362 | // gpointer user_data); 363 | //GList* g_list_sort_with_data (GList *list, 364 | // GCompareDataFunc compare_func, 365 | // gpointer user_data); 366 | //gint (*GCompareDataFunc) (gconstpointer a, 367 | // gconstpointer b, 368 | // gpointer user_data); 369 | func (v List) Concat(link List) *List { 370 | return &List{C.g_list_concat(v.GList, link.GList)} 371 | } 372 | 373 | func (v List) ForEach(callback func(unsafe.Pointer, interface{}), user_datas ...interface{}) { 374 | var user_data interface{} 375 | if len(user_datas) > 0 { 376 | user_data = user_datas[0] 377 | } 378 | l := v.First() 379 | for n := uint(0); n < l.Length(); n++ { 380 | callback(l.NthData(n), user_data) 381 | } 382 | } 383 | 384 | func (v List) First() *List { 385 | return &List{C.g_list_first(v.GList)} 386 | } 387 | 388 | func (v List) Last() *List { 389 | return &List{C.g_list_last(v.GList)} 390 | } 391 | 392 | func (v List) Nth(n uint) *List { 393 | return &List{C.g_list_nth(v.GList, C.guint(n))} 394 | } 395 | 396 | func (v List) NthData(n uint) unsafe.Pointer { 397 | return unsafe.Pointer(C.g_list_nth_data(v.GList, C.guint(n))) 398 | } 399 | 400 | func (v List) NthPrev(n uint) *List { 401 | return &List{C.g_list_nth_prev(v.GList, C.guint(n))} 402 | } 403 | 404 | func (v List) Find(data unsafe.Pointer) *List { 405 | return &List{C.g_list_find(v.GList, C.gconstpointer(data))} 406 | } 407 | 408 | //GList* g_list_find_custom (GList *list, 409 | // gconstpointer data, 410 | // GCompareFunc func); 411 | func (v List) Position(link List) int { 412 | return int(C.g_list_position(v.GList, link.GList)) 413 | } 414 | 415 | func (v List) Index(data unsafe.Pointer) int { 416 | return int(C.g_list_index(v.GList, C.gconstpointer(data))) 417 | } 418 | 419 | //----------------------------------------------------------------------- 420 | // g_slist 421 | //----------------------------------------------------------------------- 422 | type SList struct { 423 | GSList *C.GSList 424 | } 425 | 426 | func SListFromNative(sl unsafe.Pointer) *SList { 427 | return &SList{ 428 | C.to_slist(sl)} 429 | } 430 | 431 | func (v SList) ToSList() *C.GSList { 432 | return v.GSList 433 | } 434 | 435 | func (v SList) Data() unsafe.Pointer { 436 | return unsafe.Pointer(v.GSList.data) 437 | } 438 | 439 | func GSListAlloc() *SList { 440 | return &SList{C.g_slist_alloc()} 441 | } 442 | 443 | func (v SList) Free() { 444 | C.g_slist_free(v.GSList) 445 | } 446 | 447 | func (v SList) Free1() { 448 | C.g_slist_free1(v.GSList) 449 | } 450 | 451 | func (v SList) Append(data unsafe.Pointer) *SList { 452 | return &SList{C.g_slist_append(v.GSList, C.gpointer(data))} 453 | } 454 | 455 | func (v SList) Prepend(data unsafe.Pointer) *SList { 456 | return &SList{C.g_slist_prepend(v.GSList, C.gpointer(data))} 457 | } 458 | 459 | // GSList* g_slist_insert (GSList *list, gpointer data, gint position) G_GNUC_WARN_UNUSED_RESULT; 460 | // GSList* g_slist_insert_sorted (GSList *list, gpointer data, GCompareFunc func) G_GNUC_WARN_UNUSED_RESULT; 461 | // GSList* g_slist_insert_sorted_with_data (GSList *list, gpointer data, GCompareDataFunc func, gpointer user_data) G_GNUC_WARN_UNUSED_RESULT; 462 | func (v SList) InsertBefore(sibling SList, data unsafe.Pointer) *SList { 463 | return &SList{C.g_slist_insert_before(v.GSList, sibling.GSList, C.gpointer(data))} 464 | } 465 | 466 | func (v SList) Concat(llink SList) *SList { 467 | return &SList{C.g_slist_concat(v.GSList, llink.GSList)} 468 | } 469 | 470 | func (v SList) Remove(data unsafe.Pointer) *SList { 471 | return &SList{C.g_slist_remove(v.GSList, C.gconstpointer(data))} 472 | } 473 | 474 | func (v SList) RemoveAll(data unsafe.Pointer) *SList { 475 | return &SList{C.g_slist_remove_all(v.GSList, C.gconstpointer(data))} 476 | } 477 | 478 | func (v SList) RemoveLink(llink SList) *SList { 479 | return &SList{C.g_slist_delete_link(v.GSList, llink.GSList)} 480 | } 481 | 482 | func (v SList) DeleteLink(llink SList) *SList { 483 | return &SList{C.g_slist_delete_link(v.GSList, llink.GSList)} 484 | } 485 | 486 | func (v SList) Reverse() *SList { 487 | return &SList{C.g_slist_reverse(v.GSList)} 488 | } 489 | 490 | func (v SList) Copy() *SList { 491 | return &SList{C.g_slist_copy(v.GSList)} 492 | } 493 | 494 | func (v SList) Nth(n uint) *SList { 495 | return &SList{C.g_slist_nth(v.GSList, C.guint(n))} 496 | } 497 | 498 | func (v SList) Find(data unsafe.Pointer) *SList { 499 | return &SList{C.g_slist_find(v.GSList, C.gconstpointer(data))} 500 | } 501 | 502 | // GSList* g_slist_find_custom (GSList *list, gconstpointer data, GCompareFunc func); 503 | func (v SList) Position(llink SList) int { 504 | return int(C.g_slist_position(v.GSList, llink.GSList)) 505 | } 506 | 507 | func (v SList) Index(data unsafe.Pointer) int { 508 | return int(C.g_slist_index(v.GSList, C.gconstpointer(data))) 509 | } 510 | 511 | func (v SList) Last() *SList { 512 | return &SList{C.g_slist_last(v.GSList)} 513 | } 514 | 515 | func (v SList) Length() uint { 516 | return uint(C.g_slist_length(v.GSList)) 517 | } 518 | 519 | func (v SList) ForEach(callback func(unsafe.Pointer, interface{}), user_datas ...interface{}) { 520 | var user_data interface{} 521 | if len(user_datas) > 0 { 522 | user_data = user_datas[0] 523 | } 524 | for n := uint(0); n < v.Length(); n++ { 525 | callback(v.Nth(n).Data(), user_data) 526 | } 527 | } 528 | 529 | // GSList* g_slist_sort (GSList *list, GCompareFunc compare_func) G_GNUC_WARN_UNUSED_RESULT; 530 | // GSList* g_slist_sort_with_data (GSList *list, GCompareDataFunc compare_func, gpointer user_data) G_GNUC_WARN_UNUSED_RESULT; 531 | func (v SList) NthData(n uint) unsafe.Pointer { 532 | return unsafe.Pointer(C.g_slist_nth_data(v.GSList, C.guint(n))) 533 | } 534 | 535 | //----------------------------------------------------------------------- 536 | // g_error 537 | //----------------------------------------------------------------------- 538 | type Error struct { 539 | GError *C.GError 540 | } 541 | 542 | func (v *Error) Error() string { 543 | return v.Message() 544 | } 545 | 546 | func (v *Error) Message() string { 547 | if unsafe.Pointer(v.GError) == nil || unsafe.Pointer(v.GError.message) == nil { 548 | return "" 549 | } 550 | return C.GoString(C.to_charptr(v.GError.message)) 551 | } 552 | 553 | func ErrorFromNative(err unsafe.Pointer) *Error { 554 | return &Error{ 555 | C.to_error(err)} 556 | } 557 | 558 | //----------------------------------------------------------------------- 559 | // GObject 560 | //----------------------------------------------------------------------- 561 | type ObjectLike interface { 562 | Ref() 563 | Unref() 564 | Connect(s string, f interface{}, data ...interface{}) 565 | } 566 | type GObject struct { 567 | Object unsafe.Pointer 568 | } 569 | 570 | func ObjectFromNative(object unsafe.Pointer) *GObject { 571 | // return &GObject { 572 | // C.to_GObject(object) } 573 | return &GObject{ 574 | object} 575 | } 576 | 577 | func (v *GObject) Ref() { 578 | C.g_object_ref(C.gpointer(v.Object)) 579 | } 580 | 581 | func (v *GObject) Unref() { 582 | C.g_object_unref(C.gpointer(v.Object)) 583 | } 584 | 585 | func (v *GObject) SetData(s string, p unsafe.Pointer) { 586 | ptr := C.CString(s) 587 | defer C.free_string(ptr) 588 | C.g_object_set_data((*C.GObject)(v.Object), C.to_gcharptr(ptr), (C.gpointer)(p)) 589 | } 590 | 591 | func (v *GObject) GetData(s string) unsafe.Pointer { 592 | ptr := C.CString(s) 593 | defer C.free_string(ptr) 594 | p := C.g_object_get_data((*C.GObject)(v.Object), C.to_gcharptr(ptr)) 595 | return unsafe.Pointer(p) 596 | } 597 | 598 | func (v *GObject) Set(name string, value interface{}) { 599 | ptr := C.CString(name) 600 | defer C.free_string(ptr) 601 | 602 | if _, ok := value.(WrappedObject); ok { 603 | value = value.(WrappedObject).GetInternalValue() 604 | } 605 | if _, ok := value.(GObject); ok { 606 | value = value.(GObject).Object 607 | } 608 | if _, ok := value.(GValue); ok { 609 | value = value.(GValue).Value 610 | } 611 | 612 | switch value.(type) { 613 | case bool: 614 | bval := gbool(value.(bool)) 615 | C._g_object_set_addr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(&bval)) 616 | case byte: 617 | bval := C.gchar(value.(byte)) 618 | C._g_object_set_addr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(&bval)) 619 | //C._g_object_set(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(reflect.ValueOf(C.gchar(value.(byte))).UnsafeAddr())) 620 | case int: 621 | ival := C.int(value.(int)) 622 | C._g_object_set_addr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(&ival)) 623 | case uint: 624 | uval := C.guint(value.(uint)) 625 | C._g_object_set_addr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(&uval)) 626 | //C._g_object_set(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(reflect.ValueOf(C.guint(value.(uint))).UnsafeAddr())) 627 | case float32: 628 | f32val := C.gfloat(value.(float32)) 629 | C._g_object_set_addr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(&f32val)) 630 | //C._g_object_set(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(reflect.ValueOf(C.gfloat(value.(float64))).UnsafeAddr())) 631 | case float64: 632 | f64val := C.gfloat(value.(float64)) 633 | C._g_object_set_addr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(&f64val)) 634 | //C._g_object_set(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(reflect.ValueOf(C.gfloat(value.(float64))).UnsafeAddr())) 635 | case string: 636 | pval := C.CString(value.(string)) 637 | defer C.free_string(pval) 638 | C._g_object_set_addr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(&pval)) 639 | default: 640 | if pv, ok := value.(*[0]uint8); ok { 641 | C._g_object_set_ptr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(pv)) 642 | } else { 643 | av := reflect.ValueOf(value) 644 | if av.Kind() == reflect.Ptr { 645 | C._g_object_set_ptr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(av.Pointer())) 646 | } else if av.CanAddr() { 647 | C._g_object_set_addr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(av.UnsafeAddr())) 648 | } else { 649 | C._g_object_set_addr(C.gpointer(v.Object), C.to_gcharptr(ptr), unsafe.Pointer(&value)) 650 | } 651 | } 652 | } 653 | } 654 | 655 | func (v *GObject) SetProperty(name string, val *GValue) { 656 | str := C.CString(name) 657 | defer C.free_string(str) 658 | C.g_object_set_property(C.to_GObject(v.Object), C.to_gcharptr(str), &val.Value) 659 | } 660 | 661 | //----------------------------------------------------------------------- 662 | // GValue 663 | //----------------------------------------------------------------------- 664 | func GValueFromNative(value interface{}) *C.GValue { 665 | var gv *C.GValue 666 | 667 | if _, ok := value.(WrappedObject); ok { 668 | value = value.(WrappedObject).GetInternalValue() 669 | } 670 | if _, ok := value.(GObject); ok { 671 | value = value.(GObject).Object 672 | } 673 | if _, ok := value.(GValue); ok { 674 | value = value.(GValue).Value 675 | } 676 | 677 | switch value.(type) { 678 | case bool: 679 | gv = C.init_gvalue_bool(gbool(value.(bool))) 680 | break 681 | case byte: 682 | gv = C.init_gvalue_byte(C.guchar(value.(byte))) 683 | break 684 | case int: 685 | gv = C.init_gvalue_int(C.gint(value.(int))) 686 | break 687 | case uint: 688 | gv = C.init_gvalue_uint(C.guint(value.(uint))) 689 | break 690 | case int64: 691 | gv = C.init_gvalue_int64(C.gint64(value.(int64))) 692 | break 693 | case float32: 694 | gv = C.init_gvalue_double(C.gdouble(value.(float32))) 695 | break 696 | case float64: 697 | gv = C.init_gvalue_double(C.gdouble(value.(float64))) 698 | break 699 | case string: 700 | { 701 | pval := C.CString(value.(string)) 702 | defer C.free_string(pval) 703 | gv = C.init_gvalue_string(C.to_gcharptr(pval)) 704 | } 705 | break 706 | default: 707 | //gv = C.init_gvalue_pointer(C.gpointer(unsafe.Pointer(&value))); 708 | break 709 | } 710 | return gv 711 | } 712 | 713 | func ValueFromNative(val interface{}) *GValue { 714 | return &GValue{*GValueFromNative(val)} 715 | } 716 | 717 | type GValue struct { 718 | Value C.GValue 719 | } 720 | 721 | const ( 722 | G_TYPE_CHAR = 3 << 2 723 | G_TYPE_UCHAR = 4 << 2 724 | G_TYPE_BOOL = 5 << 2 725 | G_TYPE_INT = 6 << 2 726 | G_TYPE_UINT = 7 << 2 727 | G_TYPE_LONG = 8 << 2 728 | G_TYPE_ULONG = 9 << 2 729 | G_TYPE_INT64 = 10 << 2 730 | G_TYPE_UINT64 = 11 << 2 731 | G_TYPE_ENUM = 12 << 2 732 | G_TYPE_FLAGS = 13 << 2 733 | G_TYPE_FLOAT = 14 << 2 734 | G_TYPE_DOUBLE = 15 << 2 735 | G_TYPE_STRING = 16 << 2 736 | G_TYPE_POINTER = 17 << 2 737 | G_TYPE_BOXED = 18 << 2 738 | ) 739 | 740 | func (v *GValue) Init(t int) { 741 | if t == G_TYPE_INT { 742 | C.g_value_init_int(&v.Value) 743 | } else if t == G_TYPE_STRING { 744 | C.g_value_init_string(&v.Value) 745 | } 746 | } 747 | 748 | func (v *GValue) GetString() string { 749 | return C.GoString(C.to_charptr(C.g_value_get_string(&v.Value))) 750 | } 751 | 752 | func (v *GValue) GetInt() int { 753 | return int(C.g_value_get_int(&v.Value)) 754 | } 755 | 756 | func (v *GValue) GetBool() bool { 757 | return gobool(C.g_value_get_boolean(&v.Value)) 758 | } 759 | 760 | //----------------------------------------------------------------------- 761 | // WrappedObject 762 | //----------------------------------------------------------------------- 763 | type WrappedObject interface { 764 | GetInternalValue() unsafe.Pointer 765 | } 766 | 767 | //----------------------------------------------------------------------- 768 | // Events 769 | //----------------------------------------------------------------------- 770 | // the go-gtk Callback is simpler than the one in C, because we have 771 | // full closures, so there is never a need to pass additional data via 772 | // a void * pointer. Where you might have wanted to do that, you can 773 | // instead just use func () { ... using data } to pass the data in. 774 | type CallbackContext struct { 775 | f reflect.Value 776 | cbi unsafe.Pointer 777 | target reflect.Value 778 | data reflect.Value 779 | } 780 | 781 | func (c *CallbackContext) Target() interface{} { 782 | return c.target.Interface() 783 | } 784 | 785 | func (c *CallbackContext) Data() interface{} { 786 | if !c.data.IsValid() { 787 | return nil 788 | } 789 | return c.data.Interface() 790 | } 791 | 792 | func (c *CallbackContext) Args(n int) CallbackArg { 793 | return CallbackArg(C.callback_info_get_arg((*C.callback_info)(c.cbi), C.int(n))) 794 | } 795 | 796 | type CallbackArg uintptr 797 | 798 | func (c CallbackArg) ToString() string { 799 | return C.GoString(C.to_charptr_voidp(unsafe.Pointer(uintptr(c)))) 800 | } 801 | 802 | //export _go_glib_callback 803 | func _go_glib_callback(cbi *C.callback_info) { 804 | value, found := callback_contexts.Get(int(cbi.func_no)) 805 | if !found { 806 | return 807 | } 808 | context := value.(*CallbackContext) 809 | t := context.f.Type() 810 | fargs := make([]reflect.Value, t.NumIn()) 811 | if len(fargs) > 0 { 812 | fargs[0] = reflect.ValueOf(context) 813 | } 814 | ret := context.f.Call(fargs) 815 | if len(ret) > 0 { 816 | value := ret[0].Interface() 817 | switch value.(type) { 818 | case bool: 819 | bval := gbool(value.(bool)) 820 | cbi.ret = unsafe.Pointer(&bval) 821 | case byte: 822 | bval := C.gchar(value.(byte)) 823 | cbi.ret = unsafe.Pointer(&bval) 824 | case int: 825 | ival := C.int(value.(int)) 826 | cbi.ret = unsafe.Pointer(&ival) 827 | case uint: 828 | uval := C.guint(value.(uint)) 829 | cbi.ret = unsafe.Pointer(&uval) 830 | case float32: 831 | f32val := C.gfloat(value.(float32)) 832 | cbi.ret = unsafe.Pointer(&f32val) 833 | case float64: 834 | f64val := C.gfloat(value.(float64)) 835 | cbi.ret = unsafe.Pointer(&f64val) 836 | case string: 837 | cbi.ret = unsafe.Pointer(C.CString(value.(string))) 838 | default: 839 | if pv, ok := value.(*[0]uint8); ok { 840 | cbi.ret = unsafe.Pointer(pv) 841 | } else { 842 | av := reflect.ValueOf(value) 843 | if av.Kind() == reflect.Ptr { 844 | cbi.ret = unsafe.Pointer(av.Pointer()) 845 | } else if av.CanAddr() { 846 | cbi.ret = unsafe.Pointer(av.UnsafeAddr()) 847 | } else { 848 | cbi.ret = unsafe.Pointer(&value) 849 | } 850 | } 851 | } 852 | } 853 | } 854 | 855 | // Return the handler call_id to use with HandlerBlock, HandlerUnblock and 856 | // HandlerDisconnect. 857 | // 858 | func (v *GObject) Connect(s string, f interface{}, datas ...interface{}) int { 859 | var data interface{} 860 | if len(datas) > 0 { 861 | data = datas[0] 862 | } 863 | return v.SignalConnect(s, f, data, ConnectSwapped) 864 | } 865 | 866 | func (v *GObject) SignalConnect(s string, f interface{}, data interface{}, flags ConnectFlags) int { 867 | ctx := &CallbackContext{reflect.ValueOf(f), nil, reflect.ValueOf(v), reflect.ValueOf(data)} 868 | ptr := C.CString(s) 869 | defer C.free_string(ptr) 870 | id := callback_contexts.Add(ctx) 871 | ctx.cbi = unsafe.Pointer(C._g_signal_connect(unsafe.Pointer(v.Object), C.to_gcharptr(ptr), C.int(id), C.int(flags))) 872 | return id 873 | } 874 | 875 | func (v *GObject) SignalConnectAfter(s string, f interface{}, datas ...interface{}) int { 876 | var data interface{} 877 | if len(datas) > 0 { 878 | data = datas[0] 879 | } 880 | return v.SignalConnect(s, f, data, ConnectAfter) 881 | } 882 | 883 | func (v *GObject) SignalConnectSwapped(s string, f interface{}, datas ...interface{}) int { 884 | var data interface{} 885 | if len(datas) > 0 { 886 | data = datas[0] 887 | } 888 | return v.SignalConnect(s, f, data, ConnectSwapped) 889 | } 890 | 891 | func (v *GObject) StopEmission(s string) { 892 | ptr := C.CString(s) 893 | defer C.free_string(ptr) 894 | C.g_signal_stop_emission_by_name((C.gpointer)(v.Object), C.to_gcharptr(ptr)) 895 | } 896 | 897 | func (v *GObject) Emit(s string) { 898 | ptr := C.CString(s) 899 | defer C.free_string(ptr) 900 | C._g_signal_emit_by_name((C.gpointer)(v.Object), C.to_gcharptr(ptr)) 901 | } 902 | 903 | func (v *GObject) HandlerBlock(call_id int) { 904 | value, found := callback_contexts.Get(call_id) 905 | if !found { 906 | return 907 | } 908 | context := value.(*CallbackContext) 909 | c_call_id := C._g_signal_callback_id((*C.callback_info)(context.cbi)) 910 | C.g_signal_handler_block((C.gpointer)(v.Object), c_call_id) 911 | } 912 | 913 | func (v *GObject) HandlerUnblock(call_id int) { 914 | value, found := callback_contexts.Get(call_id) 915 | if !found { 916 | return 917 | } 918 | context := value.(*CallbackContext) 919 | c_call_id := C._g_signal_callback_id((*C.callback_info)(context.cbi)) 920 | C.g_signal_handler_unblock((C.gpointer)(v.Object), c_call_id) 921 | } 922 | 923 | func (v *GObject) HandlerDisconnect(call_id int) { 924 | value, found := callback_contexts.Get(call_id) 925 | if !found { 926 | return 927 | } 928 | context := value.(*CallbackContext) 929 | c_call_id := C._g_signal_callback_id((*C.callback_info)(context.cbi)) 930 | C.g_signal_handler_disconnect((C.gpointer)(v.Object), c_call_id) 931 | callback_contexts.Remove(call_id) 932 | } 933 | 934 | //----------------------------------------------------------------------- 935 | // Main Loop 936 | //----------------------------------------------------------------------- 937 | type GMainContext struct { 938 | MainContext *C.GMainContext 939 | } 940 | 941 | type GMainLoop struct { 942 | MainLoop *C.GMainLoop 943 | } 944 | 945 | func NewMainContext() *GMainContext { 946 | return &GMainContext{C.g_main_context_new()} 947 | } 948 | 949 | func (v *GMainContext) Ref() *GMainContext { 950 | return &GMainContext{C.g_main_context_ref(v.MainContext)} 951 | } 952 | 953 | func (v *GMainContext) Unref() { 954 | C.g_main_context_unref(v.MainContext) 955 | } 956 | 957 | func MainContextDefault() *GMainContext { 958 | return &GMainContext{C.g_main_context_default()} 959 | } 960 | 961 | func (v *GMainContext) Iteration(blocking bool) bool { 962 | return gobool(C.g_main_context_iteration(v.MainContext, gbool(blocking))) 963 | } 964 | 965 | func (v *GMainContext) Pending() bool { 966 | return gobool(C.g_main_context_pending(v.MainContext)) 967 | } 968 | 969 | func NewMainLoop(context *GMainContext, is_running bool) *GMainLoop { 970 | var ctx *C.GMainContext 971 | if context != nil { 972 | ctx = context.MainContext 973 | } 974 | return &GMainLoop{C.g_main_loop_new(ctx, gbool(is_running))} 975 | } 976 | 977 | func (v *GMainLoop) Ref() *GMainLoop { 978 | return &GMainLoop{C.g_main_loop_ref(v.MainLoop)} 979 | } 980 | 981 | func (v *GMainLoop) Unref() { 982 | C.g_main_loop_unref(v.MainLoop) 983 | } 984 | 985 | func (v *GMainLoop) Run() { 986 | C.g_main_loop_run(v.MainLoop) 987 | } 988 | 989 | func (v *GMainLoop) Quit() { 990 | C.g_main_loop_quit(v.MainLoop) 991 | } 992 | 993 | func (v *GMainLoop) IsRunning() bool { 994 | return gobool(C.g_main_loop_is_running(v.MainLoop)) 995 | } 996 | 997 | func (v *GMainLoop) GetContext() *GMainContext { 998 | return &GMainContext{C.g_main_loop_get_context(v.MainLoop)} 999 | } 1000 | 1001 | type SourcefuncContext struct { 1002 | f reflect.Value 1003 | data reflect.Value 1004 | } 1005 | 1006 | //export _go_glib_sourcefunc 1007 | func _go_glib_sourcefunc(sfi *C.sourcefunc_info) { 1008 | id := int(sfi.func_no) 1009 | value, found := sourcefunc_contexts.Get(id) 1010 | if !found { 1011 | return 1012 | } 1013 | context := value.(*SourcefuncContext) 1014 | t := context.f.Type() 1015 | fargs := make([]reflect.Value, t.NumIn()) 1016 | if len(fargs) > 0 { 1017 | fargs[0] = reflect.ValueOf(context.data) 1018 | } 1019 | ret := context.f.Call(fargs) 1020 | if len(ret) > 0 { 1021 | bret, _ := ret[0].Interface().(bool) 1022 | sfi.ret = gbool(bret) 1023 | } 1024 | } 1025 | 1026 | func IdleAdd(f interface{}, datas ...interface{}) { 1027 | var data interface{} 1028 | if len(datas) > 0 { 1029 | data = datas[0] 1030 | } 1031 | ctx := &SourcefuncContext{reflect.ValueOf(f), reflect.ValueOf(data)} 1032 | id := sourcefunc_contexts.Add(ctx) 1033 | C._g_idle_add(C.int(id)) 1034 | } 1035 | 1036 | func TimeoutAdd(interval uint, f interface{}, datas ...interface{}) { 1037 | var data interface{} 1038 | if len(datas) > 0 { 1039 | data = datas[0] 1040 | } 1041 | ctx := &SourcefuncContext{reflect.ValueOf(f), reflect.ValueOf(data)} 1042 | id := sourcefunc_contexts.Add(ctx) 1043 | C._g_timeout_add(C.guint(interval), C.int(id)) 1044 | } 1045 | 1046 | //----------------------------------------------------------------------- 1047 | // thread 1048 | //----------------------------------------------------------------------- 1049 | func ThreadInit(a ...interface{}) { 1050 | // TODO: define GThreadFunctions 1051 | C._g_thread_init(nil) 1052 | } 1053 | -------------------------------------------------------------------------------- /glib/glib.go.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_GLIB_H 2 | #define GO_GLIB_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | static GList* to_list(void* l) { 10 | return (GList*)l; 11 | } 12 | static GSList* to_slist(void* sl) { 13 | return (GSList*)sl; 14 | } 15 | static GError* to_error(void* err) { 16 | return (GError*)err; 17 | } 18 | static inline GObject* to_GObject(void* o) { return G_OBJECT(o); } 19 | 20 | static inline gchar* to_gcharptr(const char* s) { return (gchar*)s; } 21 | 22 | static inline char* to_charptr(const gchar* s) { return (char*)s; } 23 | 24 | static inline char* to_charptr_from_gpointer(gpointer s) { return (char*)s; } 25 | 26 | static inline char* to_charptr_voidp(const void* s) { return (char*)s; } 27 | 28 | static inline void free_string(char* s) { free(s); } 29 | 30 | static inline gchar* next_string(gchar* s) { return (gchar*)(s + strlen(s) + 1); } 31 | 32 | static gboolean _g_utf8_validate(void* str, int len, void* ppbar) { 33 | return g_utf8_validate((const gchar*)str, (gssize)len, (const gchar**)ppbar); 34 | } 35 | 36 | static gchar* _g_locale_to_utf8(void* opsysstring, int len, int* bytes_read, int* bytes_written, GError** error) { 37 | return g_locale_from_utf8((const gchar*)opsysstring, (gssize)len, (gsize*)bytes_read, (gsize*)bytes_written, error); 38 | } 39 | 40 | static gchar* _g_locale_from_utf8(char* utf8string, int len, int* bytes_read, int* bytes_written, GError** error) { 41 | return g_locale_from_utf8((const gchar*)utf8string, (gssize)len, (gsize*)bytes_read, (gsize*)bytes_written, error); 42 | } 43 | static void _g_object_set_ptr(gpointer object, const gchar *property_name, void* value) { 44 | g_object_set(object, property_name, value, NULL); 45 | } 46 | static void _g_object_set_addr(gpointer object, const gchar *property_name, void* value) { 47 | g_object_set(object, property_name, *(gpointer**)value, NULL); 48 | } 49 | //static void _g_object_get(gpointer object, const gchar *property_name, void* value) { 50 | // g_object_get(object, property_name, value, NULL); 51 | //} 52 | 53 | static void g_value_init_int(GValue* gv) { g_value_init(gv, G_TYPE_INT); } 54 | static void g_value_init_string(GValue* gv) { g_value_init(gv, G_TYPE_STRING); } 55 | 56 | static GValue* init_gvalue_string_type() { 57 | GValue* gv = g_new0(GValue, 1); 58 | g_value_init(gv, G_TYPE_STRING); 59 | return gv; 60 | } 61 | static GValue* init_gvalue_string(gchar* val) { 62 | GValue* gv = init_gvalue_string_type(); 63 | g_value_set_string(gv, val); 64 | return gv; 65 | } 66 | 67 | static GValue* init_gvalue_int_type() { 68 | GValue* gv = g_new0(GValue, 1); 69 | g_value_init(gv, G_TYPE_INT); 70 | return gv; 71 | } 72 | static GValue* init_gvalue_int(gint val) { 73 | GValue* gv = init_gvalue_int_type(); 74 | g_value_set_int(gv, val); 75 | return gv; 76 | } 77 | 78 | static GValue* init_gvalue_uint(guint val) { GValue* gv = g_new0(GValue, 1); g_value_init(gv, G_TYPE_UINT); g_value_set_uint(gv, val); return gv; } 79 | static GValue* init_gvalue_int64(gint64 val) { GValue* gv = g_new0(GValue, 1); g_value_init(gv, G_TYPE_INT64); g_value_set_int64(gv, val); return gv; } 80 | static GValue* init_gvalue_double(gdouble val) { GValue* gv = g_new0(GValue, 1); g_value_init(gv, G_TYPE_DOUBLE); g_value_set_double(gv, val); return gv; } 81 | static GValue* init_gvalue_byte(guchar val) { GValue* gv = g_new0(GValue, 1); g_value_init(gv, G_TYPE_UCHAR); g_value_set_uchar(gv, val); return gv; } 82 | static GValue* init_gvalue_bool(gboolean val) { GValue* gv = g_new0(GValue, 1); g_value_init(gv, G_TYPE_BOOLEAN); g_value_set_boolean(gv, val); return gv; } 83 | //static GValue* init_gvalue_pointer(gpointer val) { GValue* gv = g_new0(GValue, 1); g_value_init(gv, G_TYPE_POINTER); g_value_set_pointer(gv, val); return gv; } 84 | 85 | typedef struct { 86 | char *name; 87 | int func_no; 88 | void* target; 89 | uintptr_t* args; 90 | int args_no; 91 | void* ret; 92 | gulong id; 93 | } callback_info; 94 | 95 | static uintptr_t callback_info_get_arg(callback_info* cbi, int idx) { 96 | return cbi->args[idx]; 97 | } 98 | extern void _go_glib_callback(callback_info* cbi); 99 | static uintptr_t _glib_callback(void *data, ...) { 100 | va_list ap; 101 | callback_info *cbi = (callback_info*) data; 102 | 103 | int i; 104 | cbi->args = (uintptr_t*)malloc(sizeof(uintptr_t)*cbi->args_no); 105 | va_start(ap, data); 106 | for (i = 0; i < cbi->args_no; i++) { 107 | cbi->args[i] = va_arg(ap, uintptr_t); 108 | } 109 | va_end(ap); 110 | 111 | _go_glib_callback(cbi); 112 | 113 | free(cbi->args); 114 | 115 | return *(uintptr_t*)(&cbi->ret); 116 | } 117 | 118 | static void free_callback_info(gpointer data, GClosure *closure) { 119 | g_slice_free(callback_info, data); 120 | } 121 | 122 | static callback_info* _g_signal_connect(void* obj, gchar* name, int func_no, int flags) { 123 | GSignalQuery query; 124 | callback_info* cbi; 125 | guint signal_id = g_signal_lookup(name, G_OBJECT_TYPE(obj)); 126 | g_signal_query(signal_id, &query); 127 | cbi = g_slice_new0(callback_info); 128 | cbi->name = g_strdup(name); 129 | cbi->func_no = func_no; 130 | cbi->args = NULL; 131 | cbi->target = obj; 132 | cbi->args_no = query.n_params; 133 | if (((GConnectFlags)flags) == G_CONNECT_AFTER) 134 | cbi->id = g_signal_connect_data((gpointer)obj, name, G_CALLBACK(_glib_callback), (gpointer)cbi, free_callback_info, G_CONNECT_AFTER); 135 | else 136 | cbi->id = g_signal_connect_data((gpointer)obj, name, G_CALLBACK(_glib_callback), (gpointer)cbi, free_callback_info, G_CONNECT_SWAPPED); 137 | return cbi; 138 | } 139 | 140 | static void _g_signal_emit_by_name(gpointer instance, const gchar *detailed_signal) { 141 | g_signal_emit_by_name(instance, detailed_signal); 142 | } 143 | 144 | static gulong _g_signal_callback_id(callback_info* cbi) { 145 | return cbi->id; 146 | } 147 | 148 | typedef struct { 149 | int func_no; 150 | gboolean ret; 151 | guint id; 152 | } sourcefunc_info; 153 | 154 | extern void _go_glib_sourcefunc(sourcefunc_info* sfi); 155 | static gboolean _go_sourcefunc(void *data) { 156 | sourcefunc_info *sfi = (sourcefunc_info*) data; 157 | 158 | _go_glib_sourcefunc(sfi); 159 | 160 | return sfi->ret; 161 | } 162 | 163 | static void free_sourcefunc_info(gpointer data) { 164 | g_slice_free(sourcefunc_info, data); 165 | } 166 | 167 | static sourcefunc_info* _g_idle_add(int func_no) { 168 | sourcefunc_info* sfi; 169 | sfi = g_slice_new0(sourcefunc_info); 170 | sfi->func_no = func_no; 171 | sfi->id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, _go_sourcefunc, sfi, free_sourcefunc_info); 172 | return sfi; 173 | } 174 | 175 | static sourcefunc_info* _g_timeout_add(guint interval, int func_no) { 176 | sourcefunc_info* sfi; 177 | sfi = g_slice_new0(sourcefunc_info); 178 | sfi->func_no = func_no; 179 | sfi->id = g_timeout_add_full(G_PRIORITY_DEFAULT, interval, _go_sourcefunc, sfi, free_sourcefunc_info); 180 | return sfi; 181 | } 182 | 183 | static void _g_thread_init(GThreadFunctions *vtable) { 184 | #if !GLIB_CHECK_VERSION(2,32,0) 185 | #ifdef G_THREADS_ENABLED 186 | g_thread_init(vtable); 187 | #endif 188 | #endif 189 | } 190 | 191 | #if !GLIB_CHECK_VERSION(2,28,0) 192 | static const gchar * 193 | g_get_user_runtime_dir (void) 194 | { 195 | #ifndef G_OS_WIN32 196 | static const gchar *runtime_dir; 197 | static gsize initialised; 198 | 199 | if (g_once_init_enter (&initialised)) { 200 | runtime_dir = g_strdup (getenv ("XDG_RUNTIME_DIR")); 201 | if (runtime_dir == NULL) 202 | g_warning ("XDG_RUNTIME_DIR variable not set. Falling back to XDG cache dir."); 203 | g_once_init_leave (&initialised, 1); 204 | } 205 | 206 | if (runtime_dir) 207 | return runtime_dir; 208 | 209 | /* Both fallback for UNIX and the default 210 | * in Windows: use the user cache directory. 211 | */ 212 | #endif 213 | 214 | return g_get_user_cache_dir (); 215 | } 216 | #endif 217 | 218 | #endif 219 | -------------------------------------------------------------------------------- /gtk/gtk_internal_test.go: -------------------------------------------------------------------------------- 1 | package gtk 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestAboutDialog_GetAuthors(t *testing.T) { 10 | Init(nil) 11 | dialog := NewAboutDialog() 12 | assert.Equal(t, len(dialog.GetAuthors()), 0) 13 | dialog.SetAuthors([]string{"a", ""}) 14 | assert.Equal(t, len(dialog.GetAuthors()), 2) 15 | dialog.SetAuthors(nil) 16 | assert.Equal(t, len(dialog.GetAuthors()), 0) 17 | } 18 | 19 | func TestUpdateTreeViewColumns(t *testing.T) { 20 | Init(nil) 21 | 22 | columnsDesc := []struct { 23 | Title string 24 | Type string 25 | GTKType ICellRenderer 26 | }{ 27 | {"Col_1", "text", NewCellRendererText()}, 28 | {"Col_2", "text", NewCellRendererText()}, 29 | } 30 | 31 | tw := NewTreeView() 32 | for i, c := range columnsDesc { 33 | tw.AppendColumn(NewTreeViewColumnWithAttributes(c.Title, c.GTKType, c.Type, i)) 34 | } 35 | 36 | columns := tw.GetColumns() 37 | 38 | if len(columns) != len(columnsDesc) { 39 | t.Error("Wrong number of the columns:", len(columns), len(columnsDesc)) 40 | } else { 41 | 42 | for i, _ := range columnsDesc { 43 | if columns[i].GetTitle() != columnsDesc[i].Title { 44 | t.Error("Wrong column title:", columns[i].GetTitle(), columnsDesc[i].Title) 45 | } 46 | } 47 | } 48 | 49 | for lastIndex := len(columns) - 1; lastIndex >= 0; { 50 | c := columns[lastIndex] 51 | 52 | after := tw.RemoveColumn(c) 53 | 54 | numbersColumns := lastIndex 55 | if numbersColumns != after { 56 | t.Error("Failed remove column:", numbersColumns, after) 57 | } 58 | 59 | lastIndex -= 1 60 | if lastIndex >= 0 { 61 | if title := tw.GetColumns()[lastIndex].GetTitle(); title != columnsDesc[lastIndex].Title { 62 | t.Error("Wrong column title:", title, columnsDesc[lastIndex].Title) 63 | } 64 | } 65 | } 66 | 67 | if count := len(tw.GetColumns()); count != 0 { 68 | t.Error("Wrong number of the columns:", count) 69 | } 70 | } 71 | 72 | func TestDialog_GetWidgetForResponse(t *testing.T) { 73 | Init(nil) 74 | dialog := NewDialog() 75 | dialog.AddButton("A", RESPONSE_ACCEPT) 76 | dialog.AddButton("B", RESPONSE_CANCEL) 77 | accept := dialog.GetWidgetForResponse(RESPONSE_ACCEPT) 78 | cancel := dialog.GetWidgetForResponse(RESPONSE_CANCEL) 79 | assert.Equal(t, newButtonInternal(accept.GWidget).GetLabel(), "A") 80 | assert.Equal(t, newButtonInternal(cancel.GWidget).GetLabel(), "B") 81 | } 82 | 83 | func TestEntry_SetInnerBorder(t *testing.T) { 84 | Init(nil) 85 | e := NewEntry() 86 | assert.Nil(t, e.GetInnerBorder()) 87 | e.SetInnerBorder(&Border{1,2,3,4,}) 88 | border := e.GetInnerBorder() 89 | assert.NotNil(t, border) 90 | assert.Equal(t, *border, Border{1,2,3,4,}) 91 | e.SetInnerBorder(nil) 92 | assert.Nil(t, e.GetInnerBorder()) 93 | } 94 | -------------------------------------------------------------------------------- /gtk/gtk_test.go: -------------------------------------------------------------------------------- 1 | package gtk_test 2 | 3 | import ( 4 | "io/ioutil" 5 | "testing" 6 | "os" 7 | "runtime" 8 | 9 | "github.com/mattn/go-gtk/gtk" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func gtkRun() { 14 | for gtk.EventsPending() { 15 | gtk.MainIterationDo(false) 16 | runtime.Gosched() 17 | } 18 | } 19 | 20 | func TestFILE_CHOOSER(t *testing.T) { 21 | gtk.Init(nil) 22 | d := gtk.NewFileChooserDialog("Select File", nil, gtk.FILE_CHOOSER_ACTION_OPEN, "Save", gtk.RESPONSE_OK) 23 | assert.NotNil(t, d) 24 | 25 | d.SetShowHidden(false) 26 | assert.False(t, d.GetShowHidden()) 27 | d.SetShowHidden(true) 28 | assert.True(t, d.GetShowHidden()) 29 | 30 | d.SetDoOverwriteConfirmation(false) 31 | assert.False(t, d.GetDoOverwriteConfirmation()) 32 | d.SetDoOverwriteConfirmation(true) 33 | assert.True(t, d.GetDoOverwriteConfirmation()) 34 | 35 | d.SetCreateFolders(false) 36 | assert.False(t, d.GetCreateFolders()) 37 | d.SetCreateFolders(true) 38 | assert.True(t, d.GetCreateFolders()) 39 | 40 | d.SelectFilename("foobar") 41 | d.UnselectFilename("foobar") 42 | 43 | d.SelectAll() 44 | d.UnselectAll() 45 | 46 | f1, err := ioutil.TempFile("/tmp", "go-gtk") 47 | assert.NoError(t, err) 48 | f1.Close() 49 | defer os.Remove(f1.Name()) 50 | 51 | f2, err := ioutil.TempFile("/tmp", "go-gtk") 52 | assert.NoError(t, err) 53 | f2.Close() 54 | defer os.Remove(f2.Name()) 55 | 56 | d.SelectFilename(f1.Name()) 57 | gtkRun() 58 | d.GetFilename() 59 | //assert.Equal(t, f1.Name(), d.GetFilename()) 60 | 61 | d.GetUri() 62 | //assert.Equal(t, "file://"+f1.Name(), d.GetUri()) 63 | d.SetUri("file://" + f2.Name()) 64 | d.GetUri() 65 | //assert.Equal(t, "file://"+f2.Name(), d.GetUri()) 66 | 67 | assert.True(t, d.SelectUri("file://"+f1.Name())) 68 | gtkRun() 69 | d.UnselectUri("file://"+f1.Name()) 70 | 71 | d.UnselectAll() 72 | gtkRun() 73 | d.GetFilenames() 74 | //assert.Equal(t, []string{}, d.GetFilenames()) 75 | d.GetUris() 76 | //assert.Equal(t, []string{}, d.GetUris()) 77 | 78 | d.SelectFilename(f2.Name()) 79 | d.GetFilenames() 80 | //assert.Equal(t, []string{f2.Name()}, d.GetFilenames()) 81 | d.GetUris() 82 | //assert.Equal(t, []string{"file://" + f2.Name()}, d.GetUris()) 83 | } 84 | 85 | func TestFileChooser_SetCurrentName(t *testing.T) { 86 | gtk.Init(nil) 87 | d := gtk.NewFileChooserWidget(gtk.FILE_CHOOSER_ACTION_SAVE) 88 | d.SetCurrentName("foobar") 89 | // no way to check this until GTK+ 3.10 90 | } 91 | 92 | 93 | func TestMisc_GetPadding(t *testing.T) { 94 | gtk.Init(nil) 95 | m := gtk.NewImage() 96 | m.SetPadding(1, 2) 97 | x, y := m.GetPadding() 98 | assert.Equal(t, x, 1) 99 | assert.Equal(t, y, 2) 100 | } 101 | -------------------------------------------------------------------------------- /gtk/gtk_x11.go: -------------------------------------------------------------------------------- 1 | // +build with-x11 2 | 3 | package gtk 4 | 5 | import ( 6 | "unsafe" 7 | 8 | "github.com/mattn/go-gtk/gdk" 9 | ) 10 | 11 | func (v *Window) XID() int32 { 12 | return gdk.WindowFromUnsafe(unsafe.Pointer(v.GWidget.window)).GetNativeWindowID() 13 | } 14 | -------------------------------------------------------------------------------- /gtkgl/gdkgl.go: -------------------------------------------------------------------------------- 1 | // +build !cgocheck 2 | 3 | package gtkgl 4 | 5 | const ( 6 | ATTR_NONE = 0 7 | ATTR_USE_GL = 1 8 | ATTR_BUFFER_SIZE = 2 9 | ATTR_LEVEL = 3 10 | ATTR_RGBA = 4 11 | ATTR_DOUBLEBUFFER = 5 12 | ATTR_STEREO = 6 13 | ATTR_AUX_BUFFERS = 7 14 | ATTR_RED_SIZE = 8 15 | ATTR_GREEN_SIZE = 9 16 | ATTR_BLUE_SIZE = 10 17 | ATTR_ALPGHA_SIZE = 11 18 | ATTR_DEPTH_SIZE = 12 19 | ATTR_STENCIL_SIZE = 13 20 | ATTR_ACCUM_RED_SIZE = 14 21 | ATTR_ACCUM_GREEN_SIZE = 15 22 | ATTR_ACCUM_BLUE_SIZE = 16 23 | ATTR_ACCUM_ALPHA_SIZE = 17 24 | ) 25 | 26 | const ( 27 | ATTR_X_VISUAL_TYPE_EXT = 0x22 28 | ATTR_TRANSPARENT_TYPE_EXT = 0x23 29 | ATTR_TRANSPARENT_INDEX_VALUE_EXT = 0x24 30 | ATTR_TRANSPARENT_RED_VALUE_EXT = 0x25 31 | ATTR_TRANSPARENT_GREEN_VALUE_EXT = 0x26 32 | ATTR_TRANSPARENT_BLUE_VALUE_EXT = 0x27 33 | ATTR_TRANSPARENT_ALPHA_VALUE_EXT = 0x28 34 | ) 35 | -------------------------------------------------------------------------------- /gtkgl/gtkgl.go.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_GTKGL_H 2 | #define GO_GTKGL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void *make_area(int attr_count, int *attrs) { 10 | if (attr_count > 0 && attrs[attr_count-1] == 0) { 11 | // already null terminated; use the pointer directly 12 | return gtk_gl_area_new(attrs); 13 | } else { 14 | // make a null terminated copy of the attribute list 15 | GtkWidget *area = NULL; 16 | int *zattrs = malloc((attr_count+1)*sizeof(int)); 17 | if (!zattrs) { 18 | return NULL; 19 | } 20 | memcpy(zattrs, attrs, attr_count * sizeof(attrs)); 21 | zattrs[attr_count] = 0; 22 | area = gtk_gl_area_new(zattrs); 23 | free(zattrs); 24 | return area; 25 | } 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /gtkgl/gtkglarea.go: -------------------------------------------------------------------------------- 1 | // +build !cgocheck 2 | 3 | package gtkgl 4 | 5 | // #include "gtkgl.go.h" 6 | // #cgo pkg-config: gtkgl-2.0 7 | import "C" 8 | 9 | import "github.com/mattn/go-gtk/gtk" 10 | import "unsafe" 11 | 12 | type GLArea struct { 13 | gtk.DrawingArea 14 | } 15 | 16 | func NewGLArea(attrList []int) *GLArea { 17 | return &GLArea{gtk.DrawingArea{ 18 | *gtk.WidgetFromNative(C.make_area(C.int(len(attrList)), (*C.int)(unsafe.Pointer(&attrList[0]))))}} 19 | } 20 | 21 | func (v *GLArea) MakeCurrent() { 22 | C.gtk_gl_area_make_current((*C.GtkGLArea)(unsafe.Pointer(v.GWidget))) 23 | } 24 | 25 | func (v *GLArea) SwapBuffers() { 26 | C.gtk_gl_area_swap_buffers((*C.GtkGLArea)(unsafe.Pointer(v.GWidget))) 27 | } 28 | -------------------------------------------------------------------------------- /gtksourceview/gtksourceview.go: -------------------------------------------------------------------------------- 1 | // +build !cgocheck 2 | 3 | package gtksourceview 4 | 5 | // #include "gtksourceview.go.h" 6 | // #cgo pkg-config: gtksourceview-2.0 7 | import "C" 8 | import ( 9 | "unsafe" 10 | 11 | "github.com/mattn/go-gtk/gtk" 12 | ) 13 | 14 | func gstring(s *C.char) *C.gchar { return C.toGstr(s) } 15 | func cstring(s *C.gchar) *C.char { return C.toCstr(s) } 16 | func gostring(s *C.gchar) string { return C.GoString(cstring(s)) } 17 | 18 | func gbool(b bool) C.gboolean { 19 | if b { 20 | return C.gboolean(1) 21 | } 22 | return C.gboolean(0) 23 | } 24 | 25 | func gobool(b C.gboolean) bool { 26 | if b != 0 { 27 | return true 28 | } 29 | return false 30 | } 31 | 32 | func cfree(s *C.char) { C.freeCstr(s) } 33 | 34 | //----------------------------------------------------------------------- 35 | // GtkSourceBuffer 36 | //----------------------------------------------------------------------- 37 | type SourceBuffer struct { 38 | GSourceBuffer *C.GtkSourceBuffer 39 | *gtk.TextBuffer 40 | } 41 | 42 | func NewSourceBuffer() *SourceBuffer { 43 | v := C.gtk_source_buffer_new(nil) 44 | return &SourceBuffer{v, gtk.NewTextBufferFromPointer(unsafe.Pointer(v))} 45 | } 46 | 47 | func NewSourceBufferWithLanguage(lang *SourceLanguage) *SourceBuffer { 48 | v := C.gtk_source_buffer_new_with_language(lang.GSourceLanguage) 49 | return &SourceBuffer{v, gtk.NewTextBufferFromPointer(unsafe.Pointer(v))} 50 | } 51 | 52 | func (v *SourceBuffer) GetNativeBuffer() unsafe.Pointer { 53 | return unsafe.Pointer(v.GSourceBuffer) 54 | } 55 | 56 | func (v *SourceBuffer) SetHighlightSyntax(highlight bool) { 57 | C.gtk_source_buffer_set_highlight_syntax(v.GSourceBuffer, gbool(highlight)) 58 | } 59 | 60 | func (v *SourceBuffer) GetHighlightSyntax() bool { 61 | return gobool(C.gtk_source_buffer_get_highlight_syntax(v.GSourceBuffer)) 62 | } 63 | 64 | func (v *SourceBuffer) SetHighlightMatchingBrackets(hl bool) { 65 | C.gtk_source_buffer_set_highlight_matching_brackets(v.GSourceBuffer, gbool(hl)) 66 | } 67 | 68 | func (v *SourceBuffer) SetLanguage(lang *SourceLanguage) { 69 | C.gtk_source_buffer_set_language(v.GSourceBuffer, lang.GSourceLanguage) 70 | } 71 | 72 | func (v *SourceBuffer) GetLanguage() *SourceLanguage { 73 | return &SourceLanguage{C.gtk_source_buffer_get_language(v.GSourceBuffer)} 74 | } 75 | 76 | func (v *SourceBuffer) BeginNotUndoableAction() { 77 | C.gtk_source_buffer_begin_not_undoable_action(v.GSourceBuffer) 78 | } 79 | 80 | func (v *SourceBuffer) EndNotUndoableAction() { 81 | C.gtk_source_buffer_end_not_undoable_action(v.GSourceBuffer) 82 | } 83 | 84 | func (v *SourceBuffer) SetStyleScheme(scheme *SourceStyleScheme) { 85 | C.gtk_source_buffer_set_style_scheme(v.GSourceBuffer, scheme.GSourceStyleScheme) 86 | } 87 | 88 | //----------------------------------------------------------------------- 89 | // GtkSourceView 90 | //----------------------------------------------------------------------- 91 | type SourceView struct { 92 | gtk.TextView 93 | } 94 | 95 | func NewSourceView() *SourceView { 96 | return &SourceView{gtk.TextView{gtk.Container{ 97 | *gtk.WidgetFromNative(unsafe.Pointer(C.gtk_source_view_new()))}}} 98 | } 99 | 100 | func NewSourceViewWithBuffer(buf *SourceBuffer) *SourceView { 101 | return &SourceView{gtk.TextView{gtk.Container{ 102 | *gtk.WidgetFromNative(unsafe.Pointer(C.gtk_source_view_new_with_buffer(buf.GSourceBuffer)))}}} 103 | } 104 | 105 | func (v *SourceView) ToNativeSourceView() *C.GtkSourceView { 106 | return C.toGtkSourceView(unsafe.Pointer(v.GWidget)) 107 | } 108 | 109 | func (v *SourceView) SetAutoIndent(enable bool) { 110 | C.gtk_source_view_set_auto_indent(v.ToNativeSourceView(), gbool(enable)) 111 | } 112 | 113 | func (v *SourceView) GetAutoIndent() bool { 114 | return gobool(C.gtk_source_view_get_auto_indent(v.ToNativeSourceView())) 115 | } 116 | 117 | func (v *SourceView) SetHighlightCurrentLine(enable bool) { 118 | C.gtk_source_view_set_highlight_current_line(v.ToNativeSourceView(), gbool(enable)) 119 | } 120 | 121 | func (v *SourceView) GetHighlightCurrentLine() bool { 122 | return gobool(C.gtk_source_view_get_highlight_current_line(v.ToNativeSourceView())) 123 | } 124 | 125 | func (v *SourceView) SetShowLineNumbers(enable bool) { 126 | C.gtk_source_view_set_show_line_numbers(v.ToNativeSourceView(), gbool(enable)) 127 | } 128 | 129 | func (v *SourceView) GetShowLineNumbers() bool { 130 | return gobool(C.gtk_source_view_get_show_line_numbers(v.ToNativeSourceView())) 131 | } 132 | 133 | func (v *SourceView) SetRightMarginPosition(pos uint) { 134 | C.gtk_source_view_set_right_margin_position(v.ToNativeSourceView(), C.guint(pos)) 135 | } 136 | 137 | func (v *SourceView) GetRightMarginPosition() uint { 138 | return uint(C.gtk_source_view_get_right_margin_position(v.ToNativeSourceView())) 139 | } 140 | 141 | func (v *SourceView) SetIndentWidth(width int) { 142 | C.gtk_source_view_set_indent_width(v.ToNativeSourceView(), C.gint(width)) 143 | } 144 | 145 | func (v *SourceView) GetIndentWidth() int { 146 | return int(C.gtk_source_view_get_indent_width(v.ToNativeSourceView())) 147 | } 148 | 149 | func (v *SourceView) SetShowRightMargin(enable bool) { 150 | C.gtk_source_view_set_show_right_margin(v.ToNativeSourceView(), gbool(enable)) 151 | } 152 | 153 | func (v *SourceView) GetShowRightMargin() bool { 154 | return gobool(C.gtk_source_view_get_show_right_margin(v.ToNativeSourceView())) 155 | } 156 | 157 | func (v *SourceView) SetInsertSpacesInsteadOfTabs(enable bool) { 158 | C.gtk_source_view_set_insert_spaces_instead_of_tabs(v.ToNativeSourceView(), gbool(enable)) 159 | } 160 | 161 | func (v *SourceView) GetInsertSpacesInsteadOfTabs() bool { 162 | return gobool(C.gtk_source_view_get_insert_spaces_instead_of_tabs(v.ToNativeSourceView())) 163 | } 164 | 165 | type SourceDrawSpacesFlags int 166 | 167 | const ( 168 | SOURCE_DRAW_SPACES_SPACE SourceDrawSpacesFlags = 1 << 0 169 | SOURCE_DRAW_SPACES_TAB SourceDrawSpacesFlags = 1 << 1 170 | SOURCE_DRAW_SPACES_NEWLINE SourceDrawSpacesFlags = 1 << 2 171 | SOURCE_DRAW_SPACES_NBSP SourceDrawSpacesFlags = 1 << 3 172 | SOURCE_DRAW_SPACES_LEADING SourceDrawSpacesFlags = 1 << 4 173 | SOURCE_DRAW_SPACES_TEXT SourceDrawSpacesFlags = 1 << 5 174 | SOURCE_DRAW_SPACES_TRAILING SourceDrawSpacesFlags = 1 << 6 175 | SOURCE_DRAW_SPACES_ALL SourceDrawSpacesFlags = (SOURCE_DRAW_SPACES_SPACE | 176 | SOURCE_DRAW_SPACES_TAB | 177 | SOURCE_DRAW_SPACES_NEWLINE | 178 | SOURCE_DRAW_SPACES_NBSP | 179 | SOURCE_DRAW_SPACES_LEADING | 180 | SOURCE_DRAW_SPACES_TEXT | 181 | SOURCE_DRAW_SPACES_TRAILING) 182 | ) 183 | 184 | func (v *SourceView) SetDrawSpaces(flags SourceDrawSpacesFlags) { 185 | C.gtk_source_view_set_draw_spaces(v.ToNativeSourceView(), 186 | C.GtkSourceDrawSpacesFlags(flags)) 187 | } 188 | 189 | func (v *SourceView) GetDrawSpaces() SourceDrawSpacesFlags { 190 | return SourceDrawSpacesFlags(C.gtk_source_view_get_draw_spaces(v.ToNativeSourceView())) 191 | } 192 | 193 | func (v *SourceView) SetTabWidth(width uint) { 194 | C.gtk_source_view_set_tab_width(v.ToNativeSourceView(), 195 | C.guint(width)) 196 | } 197 | 198 | func (v *SourceView) GetTabWidth() uint { 199 | return uint(C.gtk_source_view_get_tab_width(v.ToNativeSourceView())) 200 | } 201 | 202 | type SourceSmartHomeEndType int 203 | 204 | const ( 205 | SOURCE_SMART_HOME_END_DISABLED SourceSmartHomeEndType = 0 206 | SOURCE_SMART_HOME_END_BEFORE SourceSmartHomeEndType = 1 207 | SOURCE_SMART_HOME_END_AFTER SourceSmartHomeEndType = 2 208 | SOURCE_SMART_HOME_END_ALWAYS SourceSmartHomeEndType = 3 209 | ) 210 | 211 | func (v *SourceView) SetSmartHomeEnd(flags SourceSmartHomeEndType) { 212 | C.gtk_source_view_set_smart_home_end(v.ToNativeSourceView(), 213 | C.GtkSourceSmartHomeEndType(flags)) 214 | } 215 | 216 | func (v *SourceView) GetSmartHomeEnd() SourceSmartHomeEndType { 217 | return SourceSmartHomeEndType(C.gtk_source_view_get_smart_home_end(v.ToNativeSourceView())) 218 | } 219 | 220 | //----------------------------------------------------------------------- 221 | // GtkSourceLanguage 222 | //----------------------------------------------------------------------- 223 | type SourceLanguage struct { 224 | GSourceLanguage *C.GtkSourceLanguage 225 | } 226 | 227 | func (v *SourceLanguage) GetId() string { 228 | return gostring(C.gtk_source_language_get_id(v.GSourceLanguage)) 229 | } 230 | 231 | func (v *SourceLanguage) GetName() string { 232 | return gostring(C.gtk_source_language_get_name(v.GSourceLanguage)) 233 | } 234 | 235 | func (v *SourceLanguage) GetSection() string { 236 | return gostring(C.gtk_source_language_get_section(v.GSourceLanguage)) 237 | } 238 | 239 | func (v *SourceLanguage) GetHidden() bool { 240 | return gobool(C.gtk_source_language_get_hidden(v.GSourceLanguage)) 241 | } 242 | 243 | func (v *SourceLanguage) GetMetadata(name string) string { 244 | cname := C.CString(name) 245 | defer cfree(cname) 246 | return gostring(C.gtk_source_language_get_metadata(v.GSourceLanguage, gstring(cname))) 247 | } 248 | 249 | func (v *SourceLanguage) GetMimeTypes() []string { 250 | var types []string 251 | ctypes := C.gtk_source_language_get_mime_types(v.GSourceLanguage) 252 | for { 253 | types = append(types, gostring(*ctypes)) 254 | ctypes = C.nextGstr(ctypes) 255 | if *ctypes == nil { 256 | break 257 | } 258 | } 259 | return types 260 | } 261 | 262 | func (v *SourceLanguage) GetGlobs() []string { 263 | var globs []string 264 | cglobs := C.gtk_source_language_get_globs(v.GSourceLanguage) 265 | for { 266 | globs = append(globs, gostring(*cglobs)) 267 | cglobs = C.nextGstr(cglobs) 268 | if *cglobs == nil { 269 | break 270 | } 271 | } 272 | return globs 273 | } 274 | 275 | func (v *SourceLanguage) GetStyleName(styleId string) string { 276 | cstyleId := C.CString(styleId) 277 | defer cfree(cstyleId) 278 | return gostring(C.gtk_source_language_get_metadata(v.GSourceLanguage, gstring(cstyleId))) 279 | } 280 | 281 | func (v *SourceLanguage) GetStyleIds() []string { 282 | var ids []string 283 | cids := C.gtk_source_language_get_globs(v.GSourceLanguage) 284 | for { 285 | ids = append(ids, gostring(*cids)) 286 | cids = C.nextGstr(cids) 287 | if *cids == nil { 288 | break 289 | } 290 | } 291 | return ids 292 | } 293 | 294 | //FINISH 295 | 296 | //----------------------------------------------------------------------- 297 | // GtkSourceLanguageManager 298 | //----------------------------------------------------------------------- 299 | type SourceLanguageManager struct { 300 | GSourceLanguageManager *C.GtkSourceLanguageManager 301 | } 302 | 303 | func NewSourceLanguageManager() *SourceLanguageManager { 304 | return &SourceLanguageManager{C.gtk_source_language_manager_new()} 305 | } 306 | 307 | func SourceLanguageManagerGetDefault() *SourceLanguageManager { 308 | return &SourceLanguageManager{C.gtk_source_language_manager_get_default()} 309 | } 310 | 311 | func (v *SourceLanguageManager) SetSearchPath(paths []string) { 312 | cpaths := C.make_strings(C.int(len(paths) + 1)) 313 | for i, path := range paths { 314 | ptr := C.CString(path) 315 | defer cfree(ptr) 316 | C.set_string(cpaths, C.int(i), gstring(ptr)) 317 | } 318 | C.set_string(cpaths, C.int(len(paths)), nil) 319 | C.gtk_source_language_manager_set_search_path(v.GSourceLanguageManager, cpaths) 320 | C.destroy_strings(cpaths) 321 | } 322 | 323 | func (v *SourceLanguageManager) GetSearchPath() []string { 324 | var dirs []string 325 | cdirs := C.gtk_source_language_manager_get_search_path(v.GSourceLanguageManager) 326 | for { 327 | dirs = append(dirs, gostring(*cdirs)) 328 | cdirs = C.nextGstr(cdirs) 329 | if *cdirs == nil { 330 | break 331 | } 332 | } 333 | return dirs 334 | } 335 | 336 | func (v *SourceLanguageManager) GetLanguageIds() []string { 337 | var ids []string 338 | cids := C.gtk_source_language_manager_get_language_ids(v.GSourceLanguageManager) 339 | for { 340 | ids = append(ids, gostring(*cids)) 341 | cids = C.nextGstr(cids) 342 | if *cids == nil { 343 | break 344 | } 345 | } 346 | return ids 347 | } 348 | 349 | func (v *SourceLanguageManager) GetLanguage(id string) *SourceLanguage { 350 | cid := C.CString(id) 351 | defer cfree(cid) 352 | return &SourceLanguage{C.gtk_source_language_manager_get_language(v.GSourceLanguageManager, gstring(cid))} 353 | } 354 | 355 | func (v *SourceLanguageManager) GuessLanguage(filename string, contentType string) *SourceLanguage { 356 | if filename == "" { 357 | cct := C.CString(contentType) 358 | defer cfree(cct) 359 | return &SourceLanguage{C.gtk_source_language_manager_guess_language(v.GSourceLanguageManager, nil, gstring(cct))} 360 | } 361 | cfn := C.CString(filename) 362 | defer cfree(cfn) 363 | return &SourceLanguage{C.gtk_source_language_manager_guess_language(v.GSourceLanguageManager, gstring(cfn), nil)} 364 | } 365 | 366 | //FINISH 367 | 368 | //----------------------------------------------------------------------- 369 | // GtkSourceStyle 370 | //----------------------------------------------------------------------- 371 | type SourceStyleScheme struct { 372 | GSourceStyleScheme *C.GtkSourceStyleScheme 373 | } 374 | 375 | // gtk_source_style_scheme_get_id 376 | // gtk_source_style_scheme_get_name 377 | // gtk_source_style_scheme_get_description 378 | // gtk_source_style_scheme_get_authors 379 | // gtk_source_style_scheme_get_filename 380 | // gtk_source_style_scheme_get_style 381 | 382 | //----------------------------------------------------------------------- 383 | // GtkSourceStyleSchemeManager 384 | //----------------------------------------------------------------------- 385 | type SourceStyleSchemeManager struct { 386 | GSourceStyleSchemeManager *C.GtkSourceStyleSchemeManager 387 | } 388 | 389 | func NewSourceStyleSchemeManager() *SourceStyleSchemeManager { 390 | return &SourceStyleSchemeManager{C.gtk_source_style_scheme_manager_new()} 391 | } 392 | 393 | func SourceStyleSchemeManagerGetDefault() *SourceStyleSchemeManager { 394 | return &SourceStyleSchemeManager{C.gtk_source_style_scheme_manager_get_default()} 395 | } 396 | 397 | func (v *SourceStyleSchemeManager) GetScheme(scheme_id string) *SourceStyleScheme { 398 | cscheme_id := C.CString(scheme_id) 399 | defer cfree(cscheme_id) 400 | return &SourceStyleScheme{C.gtk_source_style_scheme_manager_get_scheme(v.GSourceStyleSchemeManager, gstring(cscheme_id))} 401 | } 402 | 403 | func (v *SourceStyleSchemeManager) SetSearchPath(paths []string) { 404 | cpaths := C.make_strings(C.int(len(paths) + 1)) 405 | for i, path := range paths { 406 | ptr := C.CString(path) 407 | defer cfree(ptr) 408 | C.set_string(cpaths, C.int(i), gstring(ptr)) 409 | } 410 | C.set_string(cpaths, C.int(len(paths)), nil) 411 | C.gtk_source_style_scheme_manager_set_search_path(v.GSourceStyleSchemeManager, cpaths) 412 | } 413 | 414 | func (v *SourceStyleSchemeManager) GetSearchPath() []string { 415 | var dirs []string 416 | cdirs := C.gtk_source_style_scheme_manager_get_search_path(v.GSourceStyleSchemeManager) 417 | for { 418 | dirs = append(dirs, gostring(*cdirs)) 419 | cdirs = C.nextGstr(cdirs) 420 | if *cdirs == nil { 421 | break 422 | } 423 | } 424 | return dirs 425 | } 426 | 427 | func (v *SourceStyleSchemeManager) AppendSearchPath(path string) { 428 | cpath := C.CString(path) 429 | defer cfree(cpath) 430 | C.gtk_source_style_scheme_manager_append_search_path(v.GSourceStyleSchemeManager, gstring(cpath)) 431 | } 432 | 433 | func (v *SourceStyleSchemeManager) PrepandSearchPath(path string) { 434 | cpath := C.CString(path) 435 | defer cfree(cpath) 436 | C.gtk_source_style_scheme_manager_prepend_search_path(v.GSourceStyleSchemeManager, gstring(cpath)) 437 | } 438 | 439 | func (v *SourceStyleSchemeManager) GetSchemeIds() []string { 440 | var ids []string 441 | cids := C.gtk_source_style_scheme_manager_get_scheme_ids(v.GSourceStyleSchemeManager) 442 | for { 443 | ids = append(ids, gostring(*cids)) 444 | cids = C.nextGstr(cids) 445 | if *cids == nil { 446 | break 447 | } 448 | } 449 | return ids 450 | } 451 | 452 | func (v *SourceStyleSchemeManager) ForseRescan() { 453 | C.gtk_source_style_scheme_manager_force_rescan(v.GSourceStyleSchemeManager) 454 | } 455 | 456 | //FINISH 457 | -------------------------------------------------------------------------------- /gtksourceview/gtksourceview.go.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_GTKSOURCEVIEW_H 2 | #define GO_GTKSOURCEVIEW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static inline gchar** make_strings(int count) { 12 | return (gchar**)malloc(sizeof(gchar*) * count); 13 | } 14 | 15 | static inline void destroy_strings(gchar** strings) { 16 | free(strings); 17 | } 18 | 19 | static inline void set_string(gchar** strings, int n, gchar* str) { 20 | strings[n] = str; 21 | } 22 | 23 | static inline GObject* toGObject(void* o) { return G_OBJECT(o); } 24 | static inline gchar* toGstr(const char* s) { return (gchar*)s; } 25 | static inline char* toCstr(const gchar* s) { return (char*)s; } 26 | static inline gchar** nextGstr(gchar** s) { return (s+1); } 27 | static inline void freeCstr(char* s) { free(s); } 28 | static GtkSourceView* toGtkSourceView(void* w) { return GTK_SOURCE_VIEW(w); } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /gtkspell/gtkspell.go: -------------------------------------------------------------------------------- 1 | // +build !cgocheck 2 | 3 | package gtkspell 4 | 5 | /* 6 | #include 7 | #include 8 | #include 9 | 10 | static GtkTextView* to_GtkTextView(void* w) { return GTK_TEXT_VIEW(w); } 11 | static inline gchar* to_gcharptr(const char* s) { return (gchar*)s; } 12 | */ 13 | // #cgo pkg-config: gtkspell-2.0 14 | import "C" 15 | import "unsafe" 16 | 17 | import "github.com/mattn/go-gtk/glib" 18 | import "github.com/mattn/go-gtk/gtk" 19 | 20 | //----------------------------------------------------------------------- 21 | // GtkSpell 22 | //----------------------------------------------------------------------- 23 | type GtkSpell struct { 24 | Spell *C.GtkSpell 25 | } 26 | 27 | func New(textview *gtk.TextView, language string) (*GtkSpell, *glib.Error) { 28 | var lang *C.char 29 | if len(language) > 0 { 30 | lang = C.CString(language) 31 | defer C.free(unsafe.Pointer(lang)) 32 | } 33 | 34 | var gerror *C.GError 35 | v := C.gtkspell_new_attach(C.to_GtkTextView(unsafe.Pointer(&textview.Widget)), C.to_gcharptr(lang), &gerror) 36 | if gerror != nil { 37 | return nil, glib.ErrorFromNative(unsafe.Pointer(gerror)) 38 | } 39 | return &GtkSpell{v}, nil 40 | } 41 | 42 | func (spell *GtkSpell) SetLanguage(language string) *glib.Error { 43 | lang := C.CString(language) 44 | defer C.free(unsafe.Pointer(lang)) 45 | 46 | var gerror *C.GError 47 | C.gtkspell_set_language(spell.Spell, C.to_gcharptr(lang), &gerror) 48 | if gerror != nil { 49 | return glib.ErrorFromNative(unsafe.Pointer(gerror)) 50 | } 51 | return nil 52 | } 53 | 54 | func (spell *GtkSpell) Recheck() { 55 | C.gtkspell_recheck_all(spell.Spell) 56 | } 57 | -------------------------------------------------------------------------------- /pango/pango.go: -------------------------------------------------------------------------------- 1 | // +build !cgocheck 2 | 3 | package pango 4 | 5 | // #include "pango.go.h" 6 | // #cgo pkg-config: pango 7 | import "C" 8 | import "unsafe" 9 | 10 | const ( 11 | SCALE = C.PANGO_SCALE 12 | ) 13 | 14 | func bool2gboolean(b bool) C.gboolean { 15 | if b { 16 | return C.gboolean(1) 17 | } 18 | return C.gboolean(0) 19 | } 20 | 21 | func gboolean2bool(b C.gboolean) bool { 22 | if b != 0 { 23 | return true 24 | } 25 | return false 26 | } 27 | 28 | type WrapMode int 29 | 30 | const ( 31 | WRAP_WORD WrapMode = 0 32 | WRAP_CHAR WrapMode = 1 33 | WRAP_WORD_CHAR WrapMode = 2 34 | ) 35 | 36 | type EllipsizeMode int 37 | 38 | const ( 39 | ELLIPSIZE_NONE EllipsizeMode = 0 40 | ELLIPSIZE_START EllipsizeMode = 1 41 | ELLIPSIZE_MIDDLE EllipsizeMode = 2 42 | ELLIPSIZE_END EllipsizeMode = 3 43 | ) 44 | 45 | type Context struct { 46 | GContext *C.PangoContext 47 | } 48 | 49 | type Layout struct { 50 | GLayout *C.PangoLayout 51 | } 52 | 53 | type FontDescription struct { 54 | GFontDescription *C.PangoFontDescription 55 | } 56 | 57 | func ContextFromUnsafe(context unsafe.Pointer) *Context { 58 | return &Context{(*C.PangoContext)(context)} 59 | } 60 | 61 | func (v *Layout) Unref() { 62 | C.g_object_unref(C.gpointer(v.GLayout)) 63 | } 64 | 65 | func (v *Layout) SetWidth(width int) { 66 | C.pango_layout_set_width(v.GLayout, C.int(width)) 67 | } 68 | 69 | func (v *Layout) SetFontDescription(d *FontDescription) { 70 | C.pango_layout_set_font_description(v.GLayout, d.GFontDescription) 71 | } 72 | 73 | func (v *Layout) SetText(s string) { 74 | cs := C.CString(s) 75 | C.pango_layout_set_text(v.GLayout, cs, -1) 76 | C.free(unsafe.Pointer(cs)) 77 | } 78 | 79 | func NewLayout(ctx *Context) *Layout { 80 | return &Layout{C.pango_layout_new(ctx.GContext)} 81 | } 82 | 83 | func NewFontDescription() *FontDescription { 84 | return &FontDescription{C.pango_font_description_new()} 85 | } 86 | 87 | func (v *FontDescription) Free() { 88 | C.pango_font_description_free(v.GFontDescription) 89 | } 90 | 91 | func (v *FontDescription) SetSize(size int) { 92 | C.pango_font_description_set_size(v.GFontDescription, C.gint(size)) 93 | } 94 | 95 | func (v *FontDescription) Copy() *FontDescription { 96 | return &FontDescription{C.pango_font_description_copy(v.GFontDescription)} 97 | } 98 | 99 | func (f *FontDescription) GetSize() int { 100 | return int(C.pango_font_description_get_size(f.GFontDescription)) 101 | } 102 | -------------------------------------------------------------------------------- /pango/pango.go.h: -------------------------------------------------------------------------------- 1 | #ifndef GO_PANGO_H 2 | #define GO_PANGO_H 3 | 4 | #ifndef uintptr 5 | #define uintptr unsigned int* 6 | #endif 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | //static const gchar* to_gcharptr(const char* s) { return (const gchar*)s; } 15 | //static guchar* to_gucharptr(void* s) { return (guchar*)s; } 16 | 17 | //static void free_string(char* s) { free(s); } 18 | 19 | //static gchar* to_gcharptr(char* s) { return (gchar*)s; } 20 | 21 | //static void free_string(char* s) { free(s); } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /tools/gogtkinfo/gogtkinfo.go: -------------------------------------------------------------------------------- 1 | /* 2 | Simple tool to approximatively count the progress of go-gtk library. 3 | Counts line starting by "func" (binding done) or starting by "//" and containing "gtk_" (binding to do) for each section (starting by a "// text" comment preceded by a "//------------") 4 | */ 5 | package main 6 | 7 | import ( 8 | "bufio" 9 | "flag" 10 | "fmt" 11 | "log" 12 | "os" 13 | "sort" 14 | "strings" 15 | ) 16 | 17 | func main() { 18 | list := make([]string, 0, 100) 19 | alphabeticalOrder := flag.Bool("a", false, "alphabetical order") 20 | githubCode := flag.Bool("g", false, "prepend spaces to each line so github will format them as code") 21 | flag.Parse() 22 | fname := flag.Arg(0) 23 | if fname == "" { 24 | fmt.Println("Usage: gogtkinfo [-ag] file") 25 | return 26 | } 27 | file, err := os.Open(fname) 28 | if err != nil { 29 | log.Print(err.Error()) 30 | return 31 | } 32 | defer file.Close() 33 | rd := bufio.NewReader(file) 34 | var currentSection, sectionAlertName string 35 | var cDone, cTodo, p, tDone, tTodo int 36 | var sectionAlert, falseAlarm bool 37 | for { 38 | var l string 39 | if falseAlarm { 40 | falseAlarm = false 41 | } else { 42 | line, isPrefix, err := rd.ReadLine() 43 | if err != nil { 44 | break 45 | } 46 | if isPrefix { 47 | return 48 | } 49 | l = string(line) 50 | } 51 | if strings.HasPrefix(l, "//---------------") { 52 | if sectionAlertName == "" { 53 | sectionAlert = true 54 | } else { 55 | if currentSection != "" { 56 | cTot := cDone + cTodo 57 | if cTot == 0 { 58 | p = 100 59 | } else { 60 | p = 100 * cDone / cTot 61 | } 62 | s := fmt.Sprintf("%-30s: %3d%% (%3d/%3d)\n", currentSection, p, cDone, cTot) 63 | list = append(list, s) 64 | } 65 | currentSection = sectionAlertName 66 | tDone += cDone 67 | tTodo += cTodo 68 | cDone = 0 69 | cTodo = 0 70 | sectionAlertName = "" 71 | } 72 | } else if sectionAlert { 73 | if strings.HasPrefix(l, "//") && len(l) > 3 && !strings.Contains(l, "gtk_") { 74 | sectionAlertName = strings.TrimSpace(l[2:len(l)]) 75 | } else { 76 | falseAlarm = true 77 | } 78 | sectionAlert = false 79 | } else if strings.HasPrefix(l, "func") { 80 | cDone++ 81 | } else if strings.HasPrefix(l, "//") && strings.Contains(l, "gtk_") { 82 | cTodo++ 83 | } 84 | } 85 | if *alphabeticalOrder { 86 | sort.StringSlice(list).Sort() 87 | } 88 | for _, s := range list { 89 | if *githubCode { 90 | fmt.Print(" ") 91 | } 92 | fmt.Print(s) 93 | } 94 | tTot := tDone + tTodo 95 | if tTot == 0 { 96 | p = 0 97 | } else { 98 | p = 100 * tDone / tTot 99 | } 100 | if *githubCode { 101 | fmt.Print("\n ") 102 | } else { 103 | fmt.Print("\n") 104 | } 105 | fmt.Printf("Total progress : %18d%% (%d/%d)\n", p, tDone, tTot) 106 | } 107 | -------------------------------------------------------------------------------- /tools/make_inline_pixbuf/make_inline_pixbuf.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/mattn/go-gtk/gdkpixbuf" 8 | "github.com/mattn/go-gtk/gtk" 9 | ) 10 | 11 | func main() { 12 | if len(os.Args) != 3 { 13 | fmt.Fprintf(os.Stderr, "Usage: make-inline-pixbuf resourceName input > output\n") 14 | os.Exit(1) 15 | } 16 | 17 | image := gtk.NewImageFromFile(os.Args[2]) 18 | pb := image.GetPixbuf() 19 | if pb.GetWidth() == -1 { 20 | fmt.Fprintf(os.Stderr, "ERROR: invalid pixbuf image\n") 21 | os.Exit(2) 22 | } 23 | 24 | var pbd gdkpixbuf.PixbufData 25 | pbd.Data = pb.GetPixelsWithLength() 26 | pbd.Width, pbd.Height, pbd.RowStride, pbd.HasAlpha = pb.GetWidth(), pb.GetHeight(), pb.GetRowstride(), pb.GetHasAlpha() 27 | pbd.Colorspace, pbd.BitsPerSample = pb.GetColorspace(), pb.GetBitsPerSample() 28 | 29 | fmt.Printf("package main \n\nimport \"github.com/mattn/go-gtk/gdkpixbuf\"\n\nvar (\n") 30 | fmt.Printf("\t%s = %#v\n", os.Args[1], pbd) 31 | 32 | fmt.Println(")\n") 33 | } 34 | --------------------------------------------------------------------------------