mirror of https://github.com/subgraph/fw-daemon
commit
4babfbbd14
@ -0,0 +1,37 @@
|
|||||||
|
Before running fw-daemon, make sure to export: GODEBUG=cgocheck=0
|
||||||
|
|
||||||
|
Also, here's a default fw-daemon-socks.json config file:
|
||||||
|
|
||||||
|
root@subgraph:/# cat /etc/fw-daemon-socks.json
|
||||||
|
{
|
||||||
|
"SocksListener": "tcp|127.0.0.1:9998",
|
||||||
|
"TorSocks": "tcp|127.0.0.1:9050"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Remember that fw-settings will need to be compiled separately with go install .../fw-daemon/fw-settings
|
||||||
|
And the gnome-shell interface must be refreshed with ALT+F2, r
|
||||||
|
*** All changes require on the interoperation between the latest versions of fw-daemon, fw-settings, and the gnome-shell Javascript frontend.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
These rules will need to be sent to ensure that all passed through/sandboxed(clearnet) traffic will be picked up by the firewall:
|
||||||
|
iptables -t mangle -I PREROUTING 1 -m conntrack --ctstate NEW --proto tcp -j NFQUEUE --queue-num 0 --queue-bypass
|
||||||
|
iptables -I FORWARD 1 -m mark --mark 0x1 -j REJECT --reject-with icmp-host-prohibited
|
||||||
|
|
||||||
|
The following rules are likewise necessary for fw-daemon to catch udp and icmp data:
|
||||||
|
iptables -t mangle -I PREROUTING 1 --proto udp -j NFQUEUE --queue-num 0 --queue-bypass
|
||||||
|
iptables -t mangle -I PREROUTING 1 --proto icmp -j NFQUEUE --queue-num 0 --queue-bypass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Here are some examples of the newly formatted rules in /var/lib/sgfw/sgfw_rules:
|
||||||
|
|
||||||
|
#[[unknown]] is used to match an unknown process; this is necessary because even though we can sometimes figure out who's sending an ICMP packet, it's functionally impossible for us to tell who the recipient of an ICMP packet is.
|
||||||
|
[[unknown]]
|
||||||
|
ALLOW|icmp:4.2.2.4:0|SYSTEM||
|
||||||
|
|
||||||
|
#Note the use of wildcards. These rules are of course redundant, but get the same basic job done.
|
||||||
|
[/usr/sbin/ntpd]
|
||||||
|
ALLOW|udp:*.ntp.org:123|SYSTEM||
|
||||||
|
ALLOW|udp:*:123|SYSTEM||
|
@ -0,0 +1,4 @@
|
|||||||
|
iptables rules necessary to get bridge traffic routed through fw-daemon:
|
||||||
|
|
||||||
|
iptables -t mangle -I PREROUTING 1 -m conntrack --ctstate NEW --proto tcp -j NFQUEUE --queue-num 0 --queue-bypass
|
||||||
|
iptables -I FORWARD 1 -m mark --mark 0x1 -j REJECT --reject-with icmp-host-prohibited
|
@ -0,0 +1,90 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"flag"
|
||||||
|
"strconv"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ReceiverSocketPath = "/var/run/fw-daemon/fwoz.sock"
|
||||||
|
|
||||||
|
func reader(r io.Reader) {
|
||||||
|
buf := make([]byte, 1024)
|
||||||
|
|
||||||
|
for {
|
||||||
|
n, err := r.Read(buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(string(buf[0:n]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
dump := flag.Bool("d", false, "dump current oz-fw rules")
|
||||||
|
whitelist := flag.Bool("w", false, "submit whitelist rule")
|
||||||
|
blacklist := flag.Bool("b", false, "submit blacklist rule")
|
||||||
|
src := flag.String("src", "", "source IP address")
|
||||||
|
dst := flag.String("dst", "", "destination IP address")
|
||||||
|
port := flag.Int("port", 0, "destination port number")
|
||||||
|
rm := flag.Bool("rm", false, "remove entry from rules (default is add)")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if !*dump {
|
||||||
|
|
||||||
|
if *src == "" {
|
||||||
|
log.Fatal("Error: must specify source address with -src")
|
||||||
|
} else if *dst == "" {
|
||||||
|
log.Fatal("Error: must specify destination address with -dst")
|
||||||
|
} else if *port == 0 {
|
||||||
|
log.Fatal("Error: must specify destination port with -port")
|
||||||
|
} else if *port <= 0 || *port > 65535 {
|
||||||
|
log.Fatal("Error: invalid port was specified")
|
||||||
|
} else if !*whitelist && !*blacklist {
|
||||||
|
log.Fatal("Error: -w or -b must be specified to whitelist or blacklist entry")
|
||||||
|
} else if *whitelist && *blacklist {
|
||||||
|
log.Fatal("Error: -w and -b cannot be specified together")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fmt.Println("Attempting to dump active rule list.")
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := net.Dial("unix", ReceiverSocketPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Could not establish connection to listener:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
if *dump {
|
||||||
|
c.Write([]byte("dump\n"))
|
||||||
|
reader(c)
|
||||||
|
fmt.Println("Done.")
|
||||||
|
} else {
|
||||||
|
reqstr := ""
|
||||||
|
|
||||||
|
if *rm {
|
||||||
|
reqstr += "remove "
|
||||||
|
} else {
|
||||||
|
reqstr += "add "
|
||||||
|
}
|
||||||
|
|
||||||
|
if *whitelist {
|
||||||
|
reqstr += "whitelist"
|
||||||
|
} else {
|
||||||
|
reqstr += "blacklist"
|
||||||
|
}
|
||||||
|
|
||||||
|
reqstr += " " + *src + " " + *dst + " " + strconv.Itoa(*port) + "\n"
|
||||||
|
c.Write([]byte(reqstr))
|
||||||
|
reader(c)
|
||||||
|
fmt.Println("Done.")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
|||||||
|
To get this to work, first edit /usr/share/gnome-shell/modes/subgraph.json
|
||||||
|
Remove the entry for "firewall@subgraph.com", hit CTRL+F2 and then issue the reload "r" command.
|
||||||
|
Reset these changes to revert back to the old gnome-shell prompt.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Changes for getting this working in ubuntu:
|
||||||
|
(this is the crux of, but not all of the steps necessary to get this running)
|
||||||
|
|
||||||
|
apt-get install libnetfilter-queue-dev
|
||||||
|
#apt-get install all dependencies: gtk3/cairo/pango/glib etc.
|
||||||
|
|
||||||
|
|
||||||
|
mkdir /etc/sgfw
|
||||||
|
cat >> /etc/sgfw/sgfw.conf << EOF
|
||||||
|
log_level="NOTICE"
|
||||||
|
log_redact=false
|
||||||
|
prompt_expanded=true
|
||||||
|
prompt_expert=true
|
||||||
|
default_action="SESSION"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
cp ./src/github.com/subgraph/fw-daemon/sources/etc/dbus-1/system.d/com.subgraph.Firewall.conf /etc/dbus-1/system.d/com.subgraph.Firewall.conf
|
||||||
|
iptables -t mangle -I PREROUTING 1 -m conntrack --ctstate NEW --proto tcp -j NFQUEUE --queue-num 0 --queue-bypass; iptables -I FORWARD 1 -m mark --mark 0x1 -j REJECT --reject-with icmp-host-prohibited
|
||||||
|
|
||||||
|
go install github.com/subgraph/fw-daemon
|
||||||
|
go install github.com/subgraph/fw-daemon/fw-settings
|
||||||
|
go install github.com/subgraph/fw-daemon/fw-prompt
|
||||||
|
|
||||||
|
GODEBUG=cgocheck=0 ./fw-daemon
|
||||||
|
Then launch ./fw-prompt
|
@ -0,0 +1,80 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/godbus/dbus"
|
||||||
|
"log"
|
||||||
|
// "github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type dbusServer struct {
|
||||||
|
conn *dbus.Conn
|
||||||
|
run bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type promptData struct {
|
||||||
|
Application string
|
||||||
|
Icon string
|
||||||
|
Path string
|
||||||
|
Address string
|
||||||
|
Port int
|
||||||
|
IP string
|
||||||
|
Origin string
|
||||||
|
Proto string
|
||||||
|
UID int
|
||||||
|
GID int
|
||||||
|
Username string
|
||||||
|
Groupname string
|
||||||
|
Pid int
|
||||||
|
Sandbox string
|
||||||
|
OptString string
|
||||||
|
Expanded bool
|
||||||
|
Expert bool
|
||||||
|
Action int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func newDbusServer() (*dbusServer, error) {
|
||||||
|
conn, err := dbus.SystemBus()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reply, err := conn.RequestName("com.subgraph.FirewallPrompt", dbus.NameFlagDoNotQueue)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if reply != dbus.RequestNameReplyPrimaryOwner {
|
||||||
|
return nil, errors.New("Bus name is already owned")
|
||||||
|
}
|
||||||
|
|
||||||
|
ds := &dbusServer{}
|
||||||
|
|
||||||
|
if err := conn.Export(ds, "/com/subgraph/FirewallPrompt", "com.subgraph.FirewallPrompt"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ds.conn = conn
|
||||||
|
ds.run = true
|
||||||
|
|
||||||
|
return ds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *dbusServer) RequestPrompt(application, icon, path, address string, port int32, ip, origin, proto string, uid, gid int32, username, groupname string, pid int32, sandbox string,
|
||||||
|
optstring string, expanded, expert bool, action int32) (int32, string, *dbus.Error) {
|
||||||
|
log.Printf("request prompt: app = %s, icon = %s, path = %s, address = %s, action = %v\n", application, icon, path, address, action)
|
||||||
|
decision := addRequest(nil, path, proto, int(pid), ip, address, int(port), int(uid), int(gid), origin, optstring, sandbox)
|
||||||
|
log.Print("Waiting on decision...")
|
||||||
|
decision.Cond.L.Lock()
|
||||||
|
for !decision.Ready {
|
||||||
|
decision.Cond.Wait()
|
||||||
|
}
|
||||||
|
log.Print("Decision returned: ", decision.Rule)
|
||||||
|
decision.Cond.L.Unlock()
|
||||||
|
// glib.IdleAdd(func, data)
|
||||||
|
return int32(decision.Scope), decision.Rule, nil
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
@ -1,41 +0,0 @@
|
|||||||
package nfqueue
|
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
type multiQueue struct {
|
|
||||||
qs []*nfQueue
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMultiQueue(min, max uint16) (mq *multiQueue) {
|
|
||||||
mq = &multiQueue{make([]*nfQueue, 0, max-min)}
|
|
||||||
for i := min; i < max; i++ {
|
|
||||||
mq.qs = append(mq.qs, NewNFQueue(i))
|
|
||||||
}
|
|
||||||
return mq
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mq *multiQueue) Process() <-chan *Packet {
|
|
||||||
var (
|
|
||||||
wg sync.WaitGroup
|
|
||||||
out = make(chan *Packet, len(mq.qs))
|
|
||||||
)
|
|
||||||
for _, q := range mq.qs {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(ch <-chan *Packet) {
|
|
||||||
for pkt := range ch {
|
|
||||||
out <- pkt
|
|
||||||
}
|
|
||||||
wg.Done()
|
|
||||||
}(q.Process())
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
close(out)
|
|
||||||
}()
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
func (mq *multiQueue) Destroy() {
|
|
||||||
for _, q := range mq.qs {
|
|
||||||
q.Destroy()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
#include "nfqueue.h"
|
|
||||||
#include "_cgo_export.h"
|
|
||||||
|
|
||||||
|
|
||||||
int nfqueue_cb_new(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) {
|
|
||||||
|
|
||||||
struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfa);
|
|
||||||
|
|
||||||
if(ph == NULL) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int id = ntohl(ph->packet_id);
|
|
||||||
|
|
||||||
unsigned char * payload;
|
|
||||||
unsigned char * saddr, * daddr;
|
|
||||||
uint16_t sport = 0, dport = 0, checksum = 0;
|
|
||||||
uint32_t mark = nfq_get_nfmark(nfa);
|
|
||||||
|
|
||||||
int len = nfq_get_payload(nfa, &payload);
|
|
||||||
|
|
||||||
if(len < sizeof(struct iphdr)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iphdr * ip = (struct iphdr *) payload;
|
|
||||||
|
|
||||||
if(ip->version == 4) {
|
|
||||||
uint32_t ipsz = (ip->ihl << 2);
|
|
||||||
if(len < ipsz) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
len -= ipsz;
|
|
||||||
payload += ipsz;
|
|
||||||
|
|
||||||
saddr = (unsigned char *)&ip->saddr;
|
|
||||||
daddr = (unsigned char *)&ip->daddr;
|
|
||||||
|
|
||||||
if(ip->protocol == IPPROTO_TCP) {
|
|
||||||
if(len < sizeof(struct tcphdr)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
struct tcphdr *tcp = (struct tcphdr *) payload;
|
|
||||||
uint32_t tcpsz = (tcp->doff << 2);
|
|
||||||
if(len < tcpsz) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
len -= tcpsz;
|
|
||||||
payload += tcpsz;
|
|
||||||
|
|
||||||
sport = ntohs(tcp->source);
|
|
||||||
dport = ntohs(tcp->dest);
|
|
||||||
checksum = ntohs(tcp->check);
|
|
||||||
} else if(ip->protocol == IPPROTO_UDP) {
|
|
||||||
if(len < sizeof(struct udphdr)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
struct udphdr *u = (struct udphdr *) payload;
|
|
||||||
len -= sizeof(struct udphdr);
|
|
||||||
payload += sizeof(struct udphdr);
|
|
||||||
|
|
||||||
sport = ntohs(u->source);
|
|
||||||
dport = ntohs(u->dest);
|
|
||||||
checksum = ntohs(u->check);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
struct ipv6hdr *ip6 = (struct ipv6hdr*) payload;
|
|
||||||
saddr = (unsigned char *)&ip6->saddr;
|
|
||||||
daddr = (unsigned char *)&ip6->daddr;
|
|
||||||
//ipv6
|
|
||||||
}
|
|
||||||
//pass everything we can and let Go handle it, I'm not a big fan of C
|
|
||||||
uint32_t verdict = go_nfq_callback(id, ntohs(ph->hw_protocol), ph->hook, &mark, ip->version, ip->protocol,
|
|
||||||
ip->tos, ip->ttl, saddr, daddr, sport, dport, checksum, len, payload, data);
|
|
||||||
return nfq_set_verdict2(qh, id, verdict, mark, 0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop_for_packets(struct nfq_handle *h) {
|
|
||||||
int fd = nfq_fd(h);
|
|
||||||
char buf[4096] __attribute__ ((aligned));
|
|
||||||
int rv;
|
|
||||||
while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
|
|
||||||
nfq_handle_packet(h, buf, rv);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
package nfqueue
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo LDFLAGS: -lnetfilter_queue
|
|
||||||
#cgo CFLAGS: -Wall
|
|
||||||
#include "nfqueue.h"
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
type nfQueue struct {
|
|
||||||
DefaultVerdict Verdict
|
|
||||||
Timeout time.Duration
|
|
||||||
qid uint16
|
|
||||||
h *C.struct_nfq_handle
|
|
||||||
//qh *C.struct_q_handle
|
|
||||||
qh *C.struct_nfq_q_handle
|
|
||||||
fd int
|
|
||||||
lk sync.Mutex
|
|
||||||
|
|
||||||
pktch chan *Packet
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNFQueue(qid uint16) (nfq *nfQueue) {
|
|
||||||
if os.Geteuid() != 0 {
|
|
||||||
|
|
||||||
}
|
|
||||||
if os.Geteuid() != 0 {
|
|
||||||
panic("Must be ran by root.")
|
|
||||||
}
|
|
||||||
nfq = &nfQueue{DefaultVerdict: ACCEPT, Timeout: time.Microsecond * 5, qid: qid}
|
|
||||||
return nfq
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
This returns a channel that will recieve packets,
|
|
||||||
the user then must call pkt.Accept() or pkt.Drop()
|
|
||||||
*/
|
|
||||||
func (this *nfQueue) Process() <-chan *Packet {
|
|
||||||
if this.h != nil {
|
|
||||||
return this.pktch
|
|
||||||
}
|
|
||||||
this.init()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
runtime.LockOSThread()
|
|
||||||
C.loop_for_packets(this.h)
|
|
||||||
}()
|
|
||||||
|
|
||||||
return this.pktch
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *nfQueue) init() {
|
|
||||||
var err error
|
|
||||||
if this.h, err = C.nfq_open(); err != nil || this.h == nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
//if this.qh, err = C.nfq_create_queue(this.h, qid, C.get_cb(), unsafe.Pointer(nfq)); err != nil || this.qh == nil {
|
|
||||||
|
|
||||||
this.pktch = make(chan *Packet, 1)
|
|
||||||
|
|
||||||
if C.nfq_unbind_pf(this.h, C.AF_INET) < 0 {
|
|
||||||
this.Destroy()
|
|
||||||
panic("nfq_unbind_pf(AF_INET) failed, are you running root?.")
|
|
||||||
}
|
|
||||||
if C.nfq_unbind_pf(this.h, C.AF_INET6) < 0 {
|
|
||||||
this.Destroy()
|
|
||||||
panic("nfq_unbind_pf(AF_INET6) failed.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if C.nfq_bind_pf(this.h, C.AF_INET) < 0 {
|
|
||||||
this.Destroy()
|
|
||||||
panic("nfq_bind_pf(AF_INET) failed.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if C.nfq_bind_pf(this.h, C.AF_INET6) < 0 {
|
|
||||||
this.Destroy()
|
|
||||||
panic("nfq_bind_pf(AF_INET6) failed.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if this.qh, err = C.create_queue(this.h, C.uint16_t(this.qid), unsafe.Pointer(this)); err != nil || this.qh == nil {
|
|
||||||
C.nfq_close(this.h)
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.fd = int(C.nfq_fd(this.h))
|
|
||||||
|
|
||||||
if C.nfq_set_mode(this.qh, C.NFQNL_COPY_PACKET, 0xffff) < 0 {
|
|
||||||
this.Destroy()
|
|
||||||
panic("nfq_set_mode(NFQNL_COPY_PACKET) failed.")
|
|
||||||
}
|
|
||||||
if C.nfq_set_queue_maxlen(this.qh, 1024*8) < 0 {
|
|
||||||
this.Destroy()
|
|
||||||
panic("nfq_set_queue_maxlen(1024 * 8) failed.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *nfQueue) Destroy() {
|
|
||||||
this.lk.Lock()
|
|
||||||
defer this.lk.Unlock()
|
|
||||||
|
|
||||||
if this.fd != 0 && this.Valid() {
|
|
||||||
syscall.Close(this.fd)
|
|
||||||
}
|
|
||||||
if this.qh != nil {
|
|
||||||
C.nfq_destroy_queue(this.qh)
|
|
||||||
this.qh = nil
|
|
||||||
}
|
|
||||||
if this.h != nil {
|
|
||||||
C.nfq_close(this.h)
|
|
||||||
this.h = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if this.pktch != nil {
|
|
||||||
close(this.pktch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *nfQueue) Valid() bool {
|
|
||||||
return this.h != nil && this.qh != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//export go_nfq_callback
|
|
||||||
func go_nfq_callback(id uint32, hwproto uint16, hook uint8, mark *uint32,
|
|
||||||
version, protocol, tos, ttl uint8, saddr, daddr unsafe.Pointer,
|
|
||||||
sport, dport, checksum uint16, payload_len uint32, payload, nfqptr unsafe.Pointer) (v uint32) {
|
|
||||||
|
|
||||||
var (
|
|
||||||
nfq = (*nfQueue)(nfqptr)
|
|
||||||
ipver = IPVersion(version)
|
|
||||||
ipsz = C.int(ipver.Size())
|
|
||||||
)
|
|
||||||
bs := C.GoBytes(payload, (C.int)(payload_len))
|
|
||||||
|
|
||||||
verdict := make(chan uint32, 1)
|
|
||||||
pkt := Packet{
|
|
||||||
QueueId: nfq.qid,
|
|
||||||
Id: id,
|
|
||||||
HWProtocol: hwproto,
|
|
||||||
Hook: hook,
|
|
||||||
Mark: *mark,
|
|
||||||
Payload: bs,
|
|
||||||
IPHeader: &IPHeader{
|
|
||||||
Version: ipver,
|
|
||||||
Protocol: IPProtocol(protocol),
|
|
||||||
Tos: tos,
|
|
||||||
TTL: ttl,
|
|
||||||
Src: net.IP(C.GoBytes(saddr, ipsz)),
|
|
||||||
Dst: net.IP(C.GoBytes(daddr, ipsz)),
|
|
||||||
},
|
|
||||||
|
|
||||||
TCPUDPHeader: &TCPUDPHeader{
|
|
||||||
SrcPort: sport,
|
|
||||||
DstPort: dport,
|
|
||||||
Checksum: checksum,
|
|
||||||
},
|
|
||||||
|
|
||||||
verdict: verdict,
|
|
||||||
}
|
|
||||||
nfq.pktch <- &pkt
|
|
||||||
|
|
||||||
select {
|
|
||||||
case v = <-pkt.verdict:
|
|
||||||
*mark = pkt.Mark
|
|
||||||
case <-time.After(nfq.Timeout):
|
|
||||||
v = uint32(nfq.DefaultVerdict)
|
|
||||||
}
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
// #define _BSD_SOURCE
|
|
||||||
// #define __BSD_SOURCE
|
|
||||||
|
|
||||||
// #define __FAVOR_BSD // Just Using _BSD_SOURCE didn't work on my system for some reason
|
|
||||||
// #define __USE_BSD
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <linux/ip.h>
|
|
||||||
#include <linux/tcp.h>
|
|
||||||
#include <linux/udp.h>
|
|
||||||
#include <linux/ipv6.h>
|
|
||||||
#include <linux/netfilter.h>
|
|
||||||
#include <libnetfilter_queue/libnetfilter_queue.h>
|
|
||||||
|
|
||||||
// extern int nfq_callback(uint8_t version, uint8_t protocol, unsigned char *saddr, unsigned char *daddr,
|
|
||||||
// uint16_t sport, uint16_t dport, unsigned char * extra, void* data);
|
|
||||||
|
|
||||||
int nfqueue_cb_new(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data);
|
|
||||||
void loop_for_packets(struct nfq_handle *h);
|
|
||||||
|
|
||||||
static inline struct nfq_q_handle * create_queue(struct nfq_handle *h, uint16_t num, void *data) {
|
|
||||||
//we use this because it's more convient to pass the callback in C
|
|
||||||
return nfq_create_queue(h, num, &nfqueue_cb_new, data);
|
|
||||||
}
|
|
@ -1,145 +0,0 @@
|
|||||||
package nfqueue
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
IPVersion uint8
|
|
||||||
IPProtocol uint8
|
|
||||||
Verdict uint8
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
IPv4 = IPVersion(4)
|
|
||||||
IPv6 = IPVersion(6)
|
|
||||||
|
|
||||||
//convience really
|
|
||||||
IGMP = IPProtocol(syscall.IPPROTO_IGMP)
|
|
||||||
RAW = IPProtocol(syscall.IPPROTO_RAW)
|
|
||||||
TCP = IPProtocol(syscall.IPPROTO_TCP)
|
|
||||||
UDP = IPProtocol(syscall.IPPROTO_UDP)
|
|
||||||
ICMP = IPProtocol(syscall.IPPROTO_ICMP)
|
|
||||||
ICMPv6 = IPProtocol(syscall.IPPROTO_ICMPV6)
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
DROP Verdict = iota
|
|
||||||
ACCEPT
|
|
||||||
STOLEN
|
|
||||||
QUEUE
|
|
||||||
REPEAT
|
|
||||||
STOP
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrVerdictSentOrTimedOut error = fmt.Errorf("The verdict was already sent or timed out.")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (v IPVersion) String() string {
|
|
||||||
switch v {
|
|
||||||
case IPv4:
|
|
||||||
return "IPv4"
|
|
||||||
case IPv6:
|
|
||||||
return "IPv6"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("<unknown ip version, %d>", uint8(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the byte size of the ip, IPv4 = 4 bytes, IPv6 = 16
|
|
||||||
func (v IPVersion) Size() int {
|
|
||||||
switch v {
|
|
||||||
case IPv4:
|
|
||||||
return 4
|
|
||||||
case IPv6:
|
|
||||||
return 16
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p IPProtocol) String() string {
|
|
||||||
switch p {
|
|
||||||
case RAW:
|
|
||||||
return "RAW"
|
|
||||||
case TCP:
|
|
||||||
return "TCP"
|
|
||||||
case UDP:
|
|
||||||
return "UDP"
|
|
||||||
case ICMP:
|
|
||||||
return "ICMP"
|
|
||||||
case ICMPv6:
|
|
||||||
return "ICMPv6"
|
|
||||||
case IGMP:
|
|
||||||
return "IGMP"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("<unknown protocol, %d>", uint8(p))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v Verdict) String() string {
|
|
||||||
switch v {
|
|
||||||
case DROP:
|
|
||||||
return "DROP"
|
|
||||||
case ACCEPT:
|
|
||||||
return "ACCEPT"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("<unsupported verdict, %d>", uint8(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
type IPHeader struct {
|
|
||||||
Version IPVersion
|
|
||||||
|
|
||||||
Tos, TTL uint8
|
|
||||||
Protocol IPProtocol
|
|
||||||
Src, Dst net.IP
|
|
||||||
}
|
|
||||||
|
|
||||||
type TCPUDPHeader struct {
|
|
||||||
SrcPort, DstPort uint16
|
|
||||||
Checksum uint16 //not implemented
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO handle other protocols
|
|
||||||
|
|
||||||
type Packet struct {
|
|
||||||
QueueId uint16
|
|
||||||
Id uint32
|
|
||||||
HWProtocol uint16
|
|
||||||
Hook uint8
|
|
||||||
Mark uint32
|
|
||||||
Payload []byte
|
|
||||||
*IPHeader
|
|
||||||
*TCPUDPHeader
|
|
||||||
|
|
||||||
verdict chan uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pkt *Packet) String() string {
|
|
||||||
return fmt.Sprintf("<Packet QId: %d, Id: %d, Type: %s, Src: %s:%d, Dst: %s:%d, Mark: 0x%X, Checksum: 0x%X, TOS: 0x%X, TTL: %d>",
|
|
||||||
pkt.QueueId, pkt.Id, pkt.Protocol, pkt.Src, pkt.SrcPort, pkt.Dst, pkt.DstPort, pkt.Mark, pkt.Checksum, pkt.Tos, pkt.TTL)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pkt *Packet) setVerdict(v Verdict) (err error) {
|
|
||||||
defer func() {
|
|
||||||
if x := recover(); x != nil {
|
|
||||||
err = ErrVerdictSentOrTimedOut
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
pkt.verdict <- uint32(v)
|
|
||||||
close(pkt.verdict)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pkt *Packet) Accept() error {
|
|
||||||
return pkt.setVerdict(ACCEPT)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pkt *Packet) Drop() error {
|
|
||||||
return pkt.setVerdict(DROP)
|
|
||||||
}
|
|
||||||
|
|
||||||
//HUGE warning, if the iptables rules aren't set correctly this can cause some problems.
|
|
||||||
// func (pkt *Packet) Repeat() error {
|
|
||||||
// return this.SetVerdict(REPEAT)
|
|
||||||
// }
|
|
@ -0,0 +1,170 @@
|
|||||||
|
package pcoroner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
"strings"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type WatchProcess struct {
|
||||||
|
Pid int
|
||||||
|
Inode uint64
|
||||||
|
Ppid int
|
||||||
|
Stime int
|
||||||
|
}
|
||||||
|
|
||||||
|
type CallbackEntry struct {
|
||||||
|
fn procCB
|
||||||
|
param interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type procCB func(int, interface{})
|
||||||
|
|
||||||
|
|
||||||
|
var Callbacks []CallbackEntry
|
||||||
|
|
||||||
|
|
||||||
|
var pmutex = &sync.Mutex{}
|
||||||
|
var pidMap map[int]WatchProcess = make(map[int]WatchProcess)
|
||||||
|
|
||||||
|
|
||||||
|
func MonitorProcess(pid int) bool {
|
||||||
|
pmutex.Lock()
|
||||||
|
defer pmutex.Unlock()
|
||||||
|
|
||||||
|
_, ok := pidMap[pid]
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
watcher := WatchProcess{Pid: pid}
|
||||||
|
watcher.Inode = 0
|
||||||
|
res := checkProcess(&watcher, true)
|
||||||
|
|
||||||
|
if res {
|
||||||
|
pidMap[pid] = watcher
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmonitorProcess(pid int) {
|
||||||
|
pmutex.Lock()
|
||||||
|
defer pmutex.Unlock()
|
||||||
|
delete(pidMap, pid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddCallback(cbfunc procCB, param interface{}) {
|
||||||
|
cbe := CallbackEntry{cbfunc, param}
|
||||||
|
Callbacks = append(Callbacks, cbe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonitorThread(cbfunc procCB, param interface{}) {
|
||||||
|
for {
|
||||||
|
/* if len(pidMap) == 0 {
|
||||||
|
fmt.Println("TICK")
|
||||||
|
} else { fmt.Println("len = ", len(pidMap)) } */
|
||||||
|
pmutex.Lock()
|
||||||
|
pmutex.Unlock()
|
||||||
|
|
||||||
|
for pkey, pval := range pidMap {
|
||||||
|
// fmt.Printf("PID %v -> %v\n", pkey, pval)
|
||||||
|
res := checkProcess(&pval, false)
|
||||||
|
|
||||||
|
if !res {
|
||||||
|
delete(pidMap, pkey)
|
||||||
|
|
||||||
|
if cbfunc != nil {
|
||||||
|
cbfunc(pkey, param)
|
||||||
|
}
|
||||||
|
for i := 0; i < len(Callbacks); i++ {
|
||||||
|
Callbacks[i].fn(pkey, Callbacks[i].param)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkProcess(proc *WatchProcess, init bool) bool {
|
||||||
|
ppath := fmt.Sprintf("/proc/%d/stat", proc.Pid)
|
||||||
|
f, err := os.Open(ppath)
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Error opening path %s: %s\n", ppath, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error calling stat on file %s: %s\n", ppath, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sb, ok := fi.Sys().(*syscall.Stat_t)
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("Unexpected error reading stat information from proc file")
|
||||||
|
} else if init {
|
||||||
|
proc.Inode = sb.Ino
|
||||||
|
} else {
|
||||||
|
if sb.Ino != proc.Inode {
|
||||||
|
fmt.Printf("/proc inode mismatch for process %d: %v vs %v\n", proc.Pid, sb.Ino, proc.Inode)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf [512]byte
|
||||||
|
nread, err := f.Read(buf[:])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error reading stat for process %d: %v", proc.Pid, err)
|
||||||
|
return true
|
||||||
|
} else if nread <= 0 {
|
||||||
|
fmt.Printf("Unexpected error reading stat for process %d", proc.Pid)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
bstr := string(buf[:])
|
||||||
|
// fmt.Println("sstr = ", bstr)
|
||||||
|
|
||||||
|
fields := strings.Split(bstr, " ")
|
||||||
|
|
||||||
|
if len(fields) < 22 {
|
||||||
|
fmt.Printf("Unexpected error reading data from /proc stat for process %d", proc.Pid)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
ppid, err := strconv.Atoi(fields[3])
|
||||||
|
if err != nil {
|
||||||
|
ppid = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if init {
|
||||||
|
proc.Ppid = ppid
|
||||||
|
} else if proc.Ppid != ppid {
|
||||||
|
fmt.Printf("Cached process ppid did not match value in /proc: %v vs %v\n", proc.Ppid, ppid)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
stime, err := strconv.Atoi(fields[21])
|
||||||
|
if err != nil {
|
||||||
|
stime = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if init {
|
||||||
|
proc.Stime = stime
|
||||||
|
} else if proc.Stime != stime {
|
||||||
|
fmt.Printf("Cached process start time did not match value in /proc: %v vs %v\n", proc.Stime, stime)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* client.go - SOCSK5 client implementation.
|
||||||
|
*
|
||||||
|
* To the extent possible under law, Yawning Angel has waived all copyright and
|
||||||
|
* related or neighboring rights to or-ctl-filter, using the creative commons
|
||||||
|
* "cc0" public domain dedication. See LICENSE or
|
||||||
|
* <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sgfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Redispatch dials the provided proxy and redispatches an existing request.
|
||||||
|
func Redispatch(proxyNet, proxyAddr string, req *Request) (conn net.Conn, bndAddr *Address, err error) {
|
||||||
|
defer func() {
|
||||||
|
if err != nil && conn != nil {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
conn, err = clientHandshake(proxyNet, proxyAddr, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
bndAddr, err = clientCmd(conn, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientHandshake(proxyNet, proxyAddr string, req *Request) (net.Conn, error) {
|
||||||
|
conn, err := net.Dial(proxyNet, proxyAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := conn.SetDeadline(time.Now().Add(requestTimeout)); err != nil {
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
authMethod, err := clientNegotiateAuth(conn, req)
|
||||||
|
if err != nil {
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
if err := clientAuthenticate(conn, req, authMethod); err != nil {
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientNegotiateAuth(conn net.Conn, req *Request) (byte, error) {
|
||||||
|
useRFC1929 := req.Auth.Uname != nil && req.Auth.Passwd != nil
|
||||||
|
// XXX: Validate uname/passwd lengths, though should always be valid.
|
||||||
|
|
||||||
|
var buf [3]byte
|
||||||
|
buf[0] = version
|
||||||
|
buf[1] = 1
|
||||||
|
if useRFC1929 {
|
||||||
|
buf[2] = authUsernamePassword
|
||||||
|
} else {
|
||||||
|
buf[2] = authNoneRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := conn.Write(buf[:]); err != nil {
|
||||||
|
return authNoAcceptableMethods, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp [2]byte
|
||||||
|
if _, err := io.ReadFull(conn, resp[:]); err != nil {
|
||||||
|
return authNoAcceptableMethods, err
|
||||||
|
}
|
||||||
|
if err := validateByte("version", resp[0], version); err != nil {
|
||||||
|
return authNoAcceptableMethods, err
|
||||||
|
}
|
||||||
|
if err := validateByte("method", resp[1], buf[2]); err != nil {
|
||||||
|
return authNoAcceptableMethods, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp[1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientAuthenticate(conn net.Conn, req *Request, authMethod byte) error {
|
||||||
|
switch authMethod {
|
||||||
|
case authNoneRequired:
|
||||||
|
case authUsernamePassword:
|
||||||
|
var buf []byte
|
||||||
|
buf = append(buf, authRFC1929Ver)
|
||||||
|
buf = append(buf, byte(len(req.Auth.Uname)))
|
||||||
|
buf = append(buf, req.Auth.Uname...)
|
||||||
|
buf = append(buf, byte(len(req.Auth.Passwd)))
|
||||||
|
buf = append(buf, req.Auth.Passwd...)
|
||||||
|
if _, err := conn.Write(buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp [2]byte
|
||||||
|
if _, err := io.ReadFull(conn, resp[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := validateByte("version", resp[0], authRFC1929Ver); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := validateByte("status", resp[1], authRFC1929Success); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unknown authentication method: 0x%02x", authMethod))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientCmd(conn net.Conn, req *Request) (*Address, error) {
|
||||||
|
var buf []byte
|
||||||
|
buf = append(buf, version)
|
||||||
|
buf = append(buf, byte(req.Cmd))
|
||||||
|
buf = append(buf, rsv)
|
||||||
|
buf = append(buf, req.Addr.raw...)
|
||||||
|
if _, err := conn.Write(buf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var respHdr [3]byte
|
||||||
|
if _, err := io.ReadFull(conn, respHdr[:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validateByte("version", respHdr[0], version); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := validateByte("rep", respHdr[1], byte(ReplySucceeded)); err != nil {
|
||||||
|
return nil, clientError(respHdr[1])
|
||||||
|
}
|
||||||
|
if err := validateByte("rsv", respHdr[2], rsv); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var bndAddr Address
|
||||||
|
if err := bndAddr.read(conn); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &bndAddr, nil
|
||||||
|
}
|
@ -0,0 +1,280 @@
|
|||||||
|
/*
|
||||||
|
* common.go - SOCSK5 common definitons/routines.
|
||||||
|
*
|
||||||
|
* To the extent possible under law, Yawning Angel has waived all copyright and
|
||||||
|
* related or neighboring rights to or-ctl-filter, using the creative commons
|
||||||
|
* "cc0" public domain dedication. See LICENSE or
|
||||||
|
* <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package socks5 implements a SOCKS5 client/server. For more information see
|
||||||
|
// RFC 1928 and RFC 1929.
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// * GSSAPI authentication, is NOT supported.
|
||||||
|
// * The authentication provided by the client is always accepted.
|
||||||
|
// * A lot of the code is shamelessly stolen from obfs4proxy.
|
||||||
|
package sgfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
version = 0x05
|
||||||
|
rsv = 0x00
|
||||||
|
|
||||||
|
atypIPv4 = 0x01
|
||||||
|
atypDomainName = 0x03
|
||||||
|
atypIPv6 = 0x04
|
||||||
|
|
||||||
|
authNoneRequired = 0x00
|
||||||
|
authUsernamePassword = 0x02
|
||||||
|
authNoAcceptableMethods = 0xff
|
||||||
|
|
||||||
|
inboundTimeout = 5 * time.Second
|
||||||
|
requestTimeout = 30 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
var errInvalidAtyp = errors.New("invalid address type")
|
||||||
|
|
||||||
|
// ReplyCode is a SOCKS 5 reply code.
|
||||||
|
type ReplyCode byte
|
||||||
|
|
||||||
|
// The various SOCKS 5 reply codes from RFC 1928.
|
||||||
|
const (
|
||||||
|
ReplySucceeded ReplyCode = iota
|
||||||
|
ReplyGeneralFailure
|
||||||
|
ReplyConnectionNotAllowed
|
||||||
|
ReplyNetworkUnreachable
|
||||||
|
ReplyHostUnreachable
|
||||||
|
ReplyConnectionRefused
|
||||||
|
ReplyTTLExpired
|
||||||
|
ReplyCommandNotSupported
|
||||||
|
ReplyAddressNotSupported
|
||||||
|
)
|
||||||
|
|
||||||
|
// Command is a SOCKS 5 command.
|
||||||
|
type Command byte
|
||||||
|
|
||||||
|
// The various SOCKS 5 commands.
|
||||||
|
const (
|
||||||
|
CommandConnect Command = 0x01
|
||||||
|
CommandTorResolve Command = 0xf0
|
||||||
|
CommandTorResolvePTR Command = 0xf1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Address is a SOCKS 5 address + port.
|
||||||
|
type Address struct {
|
||||||
|
atyp uint8
|
||||||
|
raw []byte
|
||||||
|
addrStr string
|
||||||
|
portStr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromString parses the provided "host:port" format address and populates the
|
||||||
|
// Address fields.
|
||||||
|
func (addr *Address) FromString(addrStr string) (err error) {
|
||||||
|
addr.addrStr, addr.portStr, err = net.SplitHostPort(addrStr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var raw []byte
|
||||||
|
if ip := net.ParseIP(addr.addrStr); ip != nil {
|
||||||
|
if v4Addr := ip.To4(); v4Addr != nil {
|
||||||
|
raw = append(raw, atypIPv4)
|
||||||
|
raw = append(raw, v4Addr...)
|
||||||
|
} else if v6Addr := ip.To16(); v6Addr != nil {
|
||||||
|
raw = append(raw, atypIPv6)
|
||||||
|
raw = append(raw, v6Addr...)
|
||||||
|
} else {
|
||||||
|
return errors.New("unsupported IP address type")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Must be a FQDN.
|
||||||
|
if len(addr.addrStr) > 255 {
|
||||||
|
return fmt.Errorf("invalid FQDN, len > 255 bytes (%d bytes)", len(addr.addrStr))
|
||||||
|
}
|
||||||
|
raw = append(raw, atypDomainName)
|
||||||
|
raw = append(raw, addr.addrStr...)
|
||||||
|
}
|
||||||
|
|
||||||
|
var port uint64
|
||||||
|
if port, err = strconv.ParseUint(addr.portStr, 10, 16); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
raw = append(raw, byte(port>>8))
|
||||||
|
raw = append(raw, byte(port&0xff))
|
||||||
|
|
||||||
|
addr.raw = raw
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of the address, in "host:port"
|
||||||
|
// format.
|
||||||
|
func (addr *Address) String() string {
|
||||||
|
return addr.addrStr + ":" + addr.portStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostPort returns the string representation of the addess, split into the
|
||||||
|
// host and port components.
|
||||||
|
func (addr *Address) HostPort() (string, string) {
|
||||||
|
return addr.addrStr, addr.portStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type returns the address type from the connect command this address was
|
||||||
|
// parsed from
|
||||||
|
func (addr *Address) Type() uint8 {
|
||||||
|
return addr.atyp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (addr *Address) read(conn net.Conn) (err error) {
|
||||||
|
// The address looks like:
|
||||||
|
// uint8_t atyp
|
||||||
|
// uint8_t addr[] (Length depends on atyp)
|
||||||
|
// uint16_t port
|
||||||
|
|
||||||
|
// Read the atype.
|
||||||
|
var atyp byte
|
||||||
|
if atyp, err = readByte(conn); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addr.raw = append(addr.raw, atyp)
|
||||||
|
|
||||||
|
// Read the address.
|
||||||
|
var rawAddr []byte
|
||||||
|
switch atyp {
|
||||||
|
case atypIPv4:
|
||||||
|
rawAddr = make([]byte, net.IPv4len)
|
||||||
|
if _, err = io.ReadFull(conn, rawAddr); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v4Addr := net.IPv4(rawAddr[0], rawAddr[1], rawAddr[2], rawAddr[3])
|
||||||
|
addr.addrStr = v4Addr.String()
|
||||||
|
case atypDomainName:
|
||||||
|
var alen byte
|
||||||
|
if alen, err = readByte(conn); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if alen == 0 {
|
||||||
|
return fmt.Errorf("domain name with 0 length")
|
||||||
|
}
|
||||||
|
rawAddr = make([]byte, alen)
|
||||||
|
addr.raw = append(addr.raw, alen)
|
||||||
|
if _, err = io.ReadFull(conn, rawAddr); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addr.addrStr = string(rawAddr)
|
||||||
|
case atypIPv6:
|
||||||
|
rawAddr = make([]byte, net.IPv6len)
|
||||||
|
if _, err = io.ReadFull(conn, rawAddr); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v6Addr := make(net.IP, net.IPv6len)
|
||||||
|
copy(v6Addr[:], rawAddr)
|
||||||
|
addr.addrStr = fmt.Sprintf("[%s]", v6Addr.String())
|
||||||
|
default:
|
||||||
|
return errInvalidAtyp
|
||||||
|
}
|
||||||
|
addr.atyp = atyp
|
||||||
|
addr.raw = append(addr.raw, rawAddr...)
|
||||||
|
|
||||||
|
// Read the port.
|
||||||
|
var rawPort [2]byte
|
||||||
|
if _, err = io.ReadFull(conn, rawPort[:]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
port := int(rawPort[0])<<8 | int(rawPort[1])
|
||||||
|
addr.portStr = fmt.Sprintf("%d", port)
|
||||||
|
addr.raw = append(addr.raw, rawPort[:]...)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorToReplyCode converts an error to the "best" reply code.
|
||||||
|
func ErrorToReplyCode(err error) ReplyCode {
|
||||||
|
if cErr, ok := err.(clientError); ok {
|
||||||
|
return ReplyCode(cErr)
|
||||||
|
}
|
||||||
|
opErr, ok := err.(*net.OpError)
|
||||||
|
if !ok {
|
||||||
|
return ReplyGeneralFailure
|
||||||
|
}
|
||||||
|
|
||||||
|
errno, ok := opErr.Err.(syscall.Errno)
|
||||||
|
if !ok {
|
||||||
|
return ReplyGeneralFailure
|
||||||
|
}
|
||||||
|
switch errno {
|
||||||
|
case syscall.EADDRNOTAVAIL:
|
||||||
|
return ReplyAddressNotSupported
|
||||||
|
case syscall.ETIMEDOUT:
|
||||||
|
return ReplyTTLExpired
|
||||||
|
case syscall.ENETUNREACH:
|
||||||
|
return ReplyNetworkUnreachable
|
||||||
|
case syscall.EHOSTUNREACH:
|
||||||
|
return ReplyHostUnreachable
|
||||||
|
case syscall.ECONNREFUSED, syscall.ECONNRESET:
|
||||||
|
return ReplyConnectionRefused
|
||||||
|
default:
|
||||||
|
return ReplyGeneralFailure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request describes a SOCKS 5 request.
|
||||||
|
type Request struct {
|
||||||
|
Auth AuthInfo
|
||||||
|
Cmd Command
|
||||||
|
Addr Address
|
||||||
|
|
||||||
|
conn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
type clientError ReplyCode
|
||||||
|
|
||||||
|
func (e clientError) Error() string {
|
||||||
|
switch ReplyCode(e) {
|
||||||
|
case ReplySucceeded:
|
||||||
|
return "socks5: succeeded"
|
||||||
|
case ReplyGeneralFailure:
|
||||||
|
return "socks5: general failure"
|
||||||
|
case ReplyConnectionNotAllowed:
|
||||||
|
return "socks5: connection not allowed"
|
||||||
|
case ReplyNetworkUnreachable:
|
||||||
|
return "socks5: network unreachable"
|
||||||
|
case ReplyHostUnreachable:
|
||||||
|
return "socks5: host unreachable"
|
||||||
|
case ReplyConnectionRefused:
|
||||||
|
return "socks5: connection refused"
|
||||||
|
case ReplyTTLExpired:
|
||||||
|
return "socks5: ttl expired"
|
||||||
|
case ReplyCommandNotSupported:
|
||||||
|
return "socks5: command not supported"
|
||||||
|
case ReplyAddressNotSupported:
|
||||||
|
return "socks5: address not supported"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("socks5: reply code: 0x%02x", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readByte(conn net.Conn) (byte, error) {
|
||||||
|
var tmp [1]byte
|
||||||
|
if _, err := conn.Read(tmp[:]); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return tmp[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateByte(descr string, val, expected byte) error {
|
||||||
|
if val != expected {
|
||||||
|
return fmt.Errorf("message field '%s' was 0x%02x (expected 0x%02x)", descr, val, expected)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,381 @@
|
|||||||
|
package sgfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"bufio"
|
||||||
|
"strings"
|
||||||
|
"strconv"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/subgraph/oz/ipc"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ReceiverSocketPath = "/var/run/fw-daemon/fwoz.sock"
|
||||||
|
|
||||||
|
|
||||||
|
type OzInitProc struct {
|
||||||
|
Name string
|
||||||
|
Pid int
|
||||||
|
SandboxID int
|
||||||
|
}
|
||||||
|
|
||||||
|
var OzInitPids []OzInitProc = []OzInitProc{}
|
||||||
|
|
||||||
|
|
||||||
|
func addInitPid(pid int, name string, sboxid int) {
|
||||||
|
fmt.Println("::::::::::: init pid added: ", pid, " -> ", name)
|
||||||
|
for i := 0; i < len(OzInitPids); i++ {
|
||||||
|
if OzInitPids[i].Pid == pid {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ozi := OzInitProc{Name: name, Pid: pid, SandboxID: sboxid}
|
||||||
|
OzInitPids = append(OzInitPids, ozi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeInitPid(pid int) {
|
||||||
|
fmt.Println("::::::::::: removing PID: ", pid)
|
||||||
|
for i := 0; i < len(OzInitPids); i++ {
|
||||||
|
if OzInitPids[i].Pid == pid {
|
||||||
|
OzInitPids = append(OzInitPids[:i], OzInitPids[i+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFWRule(fw *Firewall, whitelist bool, srchost, dsthost, dstport string) error {
|
||||||
|
policy := fw.PolicyForPath("*")
|
||||||
|
rulestr := ""
|
||||||
|
|
||||||
|
if whitelist {
|
||||||
|
rulestr += "ALLOW"
|
||||||
|
} else {
|
||||||
|
rulestr += "DENY"
|
||||||
|
}
|
||||||
|
|
||||||
|
rulestr += "|" + dsthost + ":" + dstport + "|SESSION|" + srchost
|
||||||
|
_, err := policy.parseRule(rulestr, true)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeAllByIP(fw *Firewall, srcip string) bool {
|
||||||
|
log.Notice("XXX: Attempting to remove all rules associated with Oz interface: ", srcip)
|
||||||
|
saddr := net.ParseIP(srcip)
|
||||||
|
|
||||||
|
if saddr == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
policy := fw.PolicyForPath("*")
|
||||||
|
nrm := 0
|
||||||
|
|
||||||
|
for _, rr := range policy.rules {
|
||||||
|
if rr.saddr != nil && rr.saddr.Equal(saddr) {
|
||||||
|
log.Notice("XXX: removing ephemeral rules by Oz interface ", srcip, ": ", rr)
|
||||||
|
policy.removeRule(rr)
|
||||||
|
nrm++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nrm == 0 {
|
||||||
|
log.Notice("XXX: did not remove any rules for interface")
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReceiverLoop(fw *Firewall, c net.Conn) {
|
||||||
|
defer c.Close()
|
||||||
|
bio := bufio.NewReader(c)
|
||||||
|
|
||||||
|
for {
|
||||||
|
buf, err := bio.ReadBytes('\n')
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Notice("Error reading data from IPC client: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := string(buf)
|
||||||
|
|
||||||
|
log.Notice("Received incoming IPC:",data)
|
||||||
|
|
||||||
|
if data[len(data)-1] == '\n' {
|
||||||
|
data = data[0:len(data)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if data == "dump" {
|
||||||
|
log.Notice("Dumping oz-firewall rule set to client...")
|
||||||
|
rl := fw.PolicyForPath("*").rules
|
||||||
|
|
||||||
|
totalIRules := 0
|
||||||
|
|
||||||
|
for r := 0; r < len(rl); r++ {
|
||||||
|
if rl[r].saddr != nil {
|
||||||
|
totalIRules++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
banner := fmt.Sprintf("There are a total of %d rule(s).\n", totalIRules)
|
||||||
|
|
||||||
|
c.Write([]byte(banner))
|
||||||
|
|
||||||
|
for r := 0; r < len(rl); r++ {
|
||||||
|
hostname := ""
|
||||||
|
|
||||||
|
if rl[r].hostname != "" {
|
||||||
|
hostname = " (" + rl[r].hostname + ") "
|
||||||
|
}
|
||||||
|
|
||||||
|
portstr := strconv.Itoa(int(rl[r].port))
|
||||||
|
|
||||||
|
if rl[r].port == 0 {
|
||||||
|
portstr = "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
ruledesc := fmt.Sprintf("id %v, %v | %v, src:%v -> %v%v: %v\n", rl[r].id, RuleModeString[rl[r].mode], RuleActionString[rl[r].rtype], rl[r].saddr, rl[r].addr, hostname, portstr)
|
||||||
|
c.Write([]byte(ruledesc))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for i := 0; i < len(sandboxRules); i++ {
|
||||||
|
rulestr := ""
|
||||||
|
|
||||||
|
if sandboxRules[i].Whitelist {
|
||||||
|
rulestr += "whitelist"
|
||||||
|
} else {
|
||||||
|
rulestr += "blacklist"
|
||||||
|
}
|
||||||
|
|
||||||
|
rulestr += " " + sandboxRules[i].SrcIf.String() + " -> " + sandboxRules[i].DstIP.String() + " : " + strconv.Itoa(int(sandboxRules[i].DstPort)) + "\n"
|
||||||
|
c.Write([]byte(rulestr))
|
||||||
|
} */
|
||||||
|
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
tokens := strings.Split(data, " ")
|
||||||
|
|
||||||
|
if len(tokens) == 2 && tokens[0] == "removeall" {
|
||||||
|
log.Notice("Attempting to remove all: ", tokens[1])
|
||||||
|
removeAllByIP(fw, tokens[1])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tokens[0] == "register-init" && len(tokens) >= 3 {
|
||||||
|
initp := tokens[1]
|
||||||
|
|
||||||
|
initpid, err := strconv.Atoi(initp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Notice("IPC received invalid oz-init pid: ", initp)
|
||||||
|
c.Write([]byte("Bad command: init pid was invalid"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sboxid, err := strconv.Atoi(tokens[3])
|
||||||
|
if err != nil {
|
||||||
|
log.Notice("IPC received invalid oz sbox number: ",tokens[3])
|
||||||
|
log.Notice("Data: %v", data)
|
||||||
|
c.Write([]byte("Bad command: sandbox id was invalid"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ozname := strings.Join(tokens[2:], " ")
|
||||||
|
log.Notice("IPC message for register-init OK.")
|
||||||
|
addInitPid(initpid, tokens[2], sboxid)
|
||||||
|
c.Write([]byte("OK"))
|
||||||
|
return
|
||||||
|
} else if tokens[0] == "unregister-init" && len(tokens) == 2 {
|
||||||
|
initp := tokens[1]
|
||||||
|
initpid, err := strconv.Atoi(initp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Notice("IPC received invalid oz-init pid: ", initp)
|
||||||
|
c.Write([]byte("Bad command: init pid was invalid"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
removeInitPid(initpid)
|
||||||
|
c.Write([]byte("OK.\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tokens) != 6 {
|
||||||
|
log.Notice("IPC received invalid command: " + data)
|
||||||
|
c.Write([]byte("Received bad number of parameters.\n"))
|
||||||
|
return
|
||||||
|
} else if tokens[0] != "add" && tokens[0] != "remove" {
|
||||||
|
log.Notice("IPC received invalid command: " + data)
|
||||||
|
c.Write([]byte("Unrecognized command.\n"))
|
||||||
|
return
|
||||||
|
} else if tokens[1] != "whitelist" && tokens[1] != "blacklist" {
|
||||||
|
log.Notice("IPC received invalid command: " + data)
|
||||||
|
c.Write([]byte("Bad command: must specify either whitelist or blacklist.\n"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
add := true
|
||||||
|
|
||||||
|
if tokens[0] == "remove" {
|
||||||
|
add = false
|
||||||
|
}
|
||||||
|
|
||||||
|
w := true
|
||||||
|
|
||||||
|
if tokens[1] == "blacklist" {
|
||||||
|
w = false
|
||||||
|
}
|
||||||
|
|
||||||
|
srchost := tokens[2]
|
||||||
|
dsthost := tokens[3]
|
||||||
|
srcip := net.ParseIP(srchost)
|
||||||
|
|
||||||
|
if srcip == nil {
|
||||||
|
log.Notice("IP conversion failed: ", srchost)
|
||||||
|
srcip = net.IP{0,0,0,0}
|
||||||
|
}
|
||||||
|
|
||||||
|
dstport := tokens[4]
|
||||||
|
dstp, err := strconv.Atoi(dstport)
|
||||||
|
|
||||||
|
if dstport != "*" && (err != nil || dstp < 0 || dstp > 65535) {
|
||||||
|
log.Notice("IPC received invalid destination port: ", tokens[4])
|
||||||
|
c.Write([]byte("Bad command: dst port was invalid"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initp := tokens[5]
|
||||||
|
initpid, err := strconv.Atoi(initp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Notice("IPC received invalid oz-init pid: ", initp)
|
||||||
|
c.Write([]byte("Bad command: init pid was invalid"))
|
||||||
|
return
|
||||||
|
} */
|
||||||
|
|
||||||
|
if add {
|
||||||
|
log.Noticef("Adding new rule to oz sandbox/fw: %v / %v -> %v : %v", w, srchost, dsthost, dstport)
|
||||||
|
// addInitPid(initpid)
|
||||||
|
err := addFWRule(fw, w, srchost, dsthost, dstport)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error adding dynamic OZ firewall rule to fw-daemon: ", err)
|
||||||
|
} else {
|
||||||
|
log.Notice("XXX: rule also successfully added to fw-daemon")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Notice("Removing new rule from oz sandbox/fw... ")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log.Notice("IPC received command: " + data)
|
||||||
|
c.Write([]byte("OK.\n"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func OzReceiver(fw *Firewall) {
|
||||||
|
log.Notice("XXX: dispatching oz receiver...")
|
||||||
|
|
||||||
|
sboxes, err := getSandboxes()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Warning("Error retrieving list of running Oz sandbox init processes: ", err)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if len(sboxes) > 0 {
|
||||||
|
log.Warning("Adding existing Oz sandbox init pids...")
|
||||||
|
for s := 0; s < len(sboxes); s++ {
|
||||||
|
//profname := fmt.Sprintf("%s (%d)", sboxes[s].Profile, sboxes[s].Id)
|
||||||
|
addInitPid(sboxes[s].InitPid, sboxes[s].Profile, sboxes[s].Id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warning("It does not appear there were any Oz sandboxed processes already launched.")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(ReceiverSocketPath)
|
||||||
|
lfd, err := net.Listen("unix", ReceiverSocketPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Could not open oz receiver socket:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
fd, err := lfd.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Could not accept receiver client:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go ReceiverLoop(fw, fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type ListProxiesMsg struct {
|
||||||
|
_ string "ListProxies"
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListProxiesResp struct {
|
||||||
|
Proxies []string "ListProxiesResp"
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListProxies() ([]string, error) {
|
||||||
|
resp, err := clientSend(&ListProxiesMsg{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
body, ok := resp.Body.(*ListProxiesResp)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("ListProxies response was not expected type")
|
||||||
|
}
|
||||||
|
return body.Proxies, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const OzSocketName = "@oz-control"
|
||||||
|
var bSockName = OzSocketName
|
||||||
|
|
||||||
|
var messageFactory = ipc.NewMsgFactory(
|
||||||
|
new(ListProxiesMsg),
|
||||||
|
new(ListProxiesResp),
|
||||||
|
)
|
||||||
|
|
||||||
|
func clientConnect() (*ipc.MsgConn, error) {
|
||||||
|
bSockName = os.Getenv("SOCKET_NAME")
|
||||||
|
|
||||||
|
if bSockName != "" {
|
||||||
|
fmt.Println("Attempting to connect on custom socket provided through environment: ", bSockName)
|
||||||
|
|
||||||
|
if bSockName[0:1] != "@" {
|
||||||
|
fmt.Println("Environment variable specified invalid socket name... prepending @")
|
||||||
|
bSockName = "@" + bSockName
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
bSockName = OzSocketName
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipc.Connect(bSockName, messageFactory, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func clientSend(msg interface{}) (*ipc.Message, error) {
|
||||||
|
c, err := clientConnect()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
rr, err := c.ExchangeMsg(msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := <-rr.Chan()
|
||||||
|
rr.Done()
|
||||||
|
return resp, nil
|
||||||
|
}
|
@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
* server.go - SOCSK5 server implementation.
|
||||||
|
*
|
||||||
|
* To the extent possible under law, Yawning Angel has waived all copyright and
|
||||||
|
* related or neighboring rights to or-ctl-filter, using the creative commons
|
||||||
|
* "cc0" public domain dedication. See LICENSE or
|
||||||
|
* <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sgfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handshake attempts to handle a incoming client handshake over the provided
|
||||||
|
// connection and receive the SOCKS5 request. The routine handles sending
|
||||||
|
// appropriate errors if applicable, but will not close the connection.
|
||||||
|
func Handshake(conn net.Conn) (*Request, error) {
|
||||||
|
// Arm the handshake timeout.
|
||||||
|
var err error
|
||||||
|
if err = conn.SetDeadline(time.Now().Add(inboundTimeout)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
// Disarm the handshake timeout, only propagate the error if
|
||||||
|
// the handshake was successful.
|
||||||
|
nerr := conn.SetDeadline(time.Time{})
|
||||||
|
if err == nil {
|
||||||
|
err = nerr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
req := new(Request)
|
||||||
|
req.conn = conn
|
||||||
|
|
||||||
|
// Negotiate the protocol version and authentication method.
|
||||||
|
var method byte
|
||||||
|
if method, err = req.negotiateAuth(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate if neccecary.
|
||||||
|
if err = req.authenticate(method); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the client command.
|
||||||
|
if err = req.readCommand(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reply sends a SOCKS5 reply to the corresponding request. The BND.ADDR and
|
||||||
|
// BND.PORT fields are always set to an address/port corresponding to
|
||||||
|
// "0.0.0.0:0".
|
||||||
|
func (req *Request) Reply(code ReplyCode) error {
|
||||||
|
return req.ReplyAddr(code, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplyAddr sends a SOCKS5 reply to the corresponding request. The BND.ADDR
|
||||||
|
// and BND.PORT fields are specified by addr, or "0.0.0.0:0" if not provided.
|
||||||
|
func (req *Request) ReplyAddr(code ReplyCode, addr *Address) error {
|
||||||
|
// The server sends a reply message.
|
||||||
|
// uint8_t ver (0x05)
|
||||||
|
// uint8_t rep
|
||||||
|
// uint8_t rsv (0x00)
|
||||||
|
// uint8_t atyp
|
||||||
|
// uint8_t bnd_addr[]
|
||||||
|
// uint16_t bnd_port
|
||||||
|
|
||||||
|
resp := []byte{version, byte(code), rsv}
|
||||||
|
if addr == nil {
|
||||||
|
var nilAddr [net.IPv4len + 2]byte
|
||||||
|
resp = append(resp, atypIPv4)
|
||||||
|
resp = append(resp, nilAddr[:]...)
|
||||||
|
} else {
|
||||||
|
resp = append(resp, addr.raw...)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := req.conn.Write(resp[:])
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req *Request) negotiateAuth() (byte, error) {
|
||||||
|
// The client sends a version identifier/selection message.
|
||||||
|
// uint8_t ver (0x05)
|
||||||
|
// uint8_t nmethods (>= 1).
|
||||||
|
// uint8_t methods[nmethods]
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if err = req.readByteVerify("version", version); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the number of methods, and the methods.
|
||||||
|
var nmethods byte
|
||||||
|
method := byte(authNoAcceptableMethods)
|
||||||
|
if nmethods, err = req.readByte(); err != nil {
|
||||||
|
return method, err
|
||||||
|
}
|
||||||
|
methods := make([]byte, nmethods)
|
||||||
|
if _, err := io.ReadFull(req.conn, methods); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick the best authentication method, prioritizing authenticating
|
||||||
|
// over not if both options are present.
|
||||||
|
if bytes.IndexByte(methods, authUsernamePassword) != -1 {
|
||||||
|
method = authUsernamePassword
|
||||||
|
} else if bytes.IndexByte(methods, authNoneRequired) != -1 {
|
||||||
|
method = authNoneRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
// The server sends a method selection message.
|
||||||
|
// uint8_t ver (0x05)
|
||||||
|
// uint8_t method
|
||||||
|
msg := []byte{version, method}
|
||||||
|
if _, err = req.conn.Write(msg); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return method, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req *Request) authenticate(method byte) error {
|
||||||
|
switch method {
|
||||||
|
case authNoneRequired:
|
||||||
|
return nil
|
||||||
|
case authUsernamePassword:
|
||||||
|
return req.authRFC1929()
|
||||||
|
case authNoAcceptableMethods:
|
||||||
|
return fmt.Errorf("no acceptable authentication methods")
|
||||||
|
default:
|
||||||
|
// This should never happen as only supported auth methods should be
|
||||||
|
// negotiated.
|
||||||
|
return fmt.Errorf("negotiated unsupported method 0x%02x", method)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req *Request) readCommand() error {
|
||||||
|
// The client sends the request details.
|
||||||
|
// uint8_t ver (0x05)
|
||||||
|
// uint8_t cmd
|
||||||
|
// uint8_t rsv (0x00)
|
||||||
|
// uint8_t atyp
|
||||||
|
// uint8_t dst_addr[]
|
||||||
|
// uint16_t dst_port
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var cmd byte
|
||||||
|
if err = req.readByteVerify("version", version); err != nil {
|
||||||
|
req.Reply(ReplyGeneralFailure)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cmd, err = req.readByte(); err != nil {
|
||||||
|
req.Reply(ReplyGeneralFailure)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch Command(cmd) {
|
||||||
|
case CommandConnect, CommandTorResolve, CommandTorResolvePTR:
|
||||||
|
req.Cmd = Command(cmd)
|
||||||
|
default:
|
||||||
|
req.Reply(ReplyCommandNotSupported)
|
||||||
|
return fmt.Errorf("unsupported SOCKS command: 0x%02x", cmd)
|
||||||
|
}
|
||||||
|
if err = req.readByteVerify("reserved", rsv); err != nil {
|
||||||
|
req.Reply(ReplyGeneralFailure)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the destination address/port.
|
||||||
|
err = req.Addr.read(req.conn)
|
||||||
|
if err == errInvalidAtyp {
|
||||||
|
req.Reply(ReplyAddressNotSupported)
|
||||||
|
} else if err != nil {
|
||||||
|
req.Reply(ReplyGeneralFailure)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req *Request) readByte() (byte, error) {
|
||||||
|
return readByte(req.conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req *Request) readByteVerify(descr string, expected byte) error {
|
||||||
|
val, err := req.readByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return validateByte(descr, val, expected)
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* server_rfc1929.go - SOCSK 5 server authentication.
|
||||||
|
*
|
||||||
|
* To the extent possible under law, Yawning Angel has waived all copyright and
|
||||||
|
* related or neighboring rights to or-ctl-filter, using the creative commons
|
||||||
|
* "cc0" public domain dedication. See LICENSE or
|
||||||
|
* <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sgfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
authRFC1929Ver = 0x01
|
||||||
|
authRFC1929Success = 0x00
|
||||||
|
authRFC1929Fail = 0x01
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthInfo is the RFC 1929 Username/Password authentication data.
|
||||||
|
type AuthInfo struct {
|
||||||
|
Uname []byte
|
||||||
|
Passwd []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req *Request) authRFC1929() (err error) {
|
||||||
|
sendErrResp := func() {
|
||||||
|
// Swallow write/flush errors, the auth failure is the relevant error.
|
||||||
|
resp := []byte{authRFC1929Ver, authRFC1929Fail}
|
||||||
|
req.conn.Write(resp[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// The client sends a Username/Password request.
|
||||||
|
// uint8_t ver (0x01)
|
||||||
|
// uint8_t ulen (>= 1)
|
||||||
|
// uint8_t uname[ulen]
|
||||||
|
// uint8_t plen (>= 1)
|
||||||
|
// uint8_t passwd[plen]
|
||||||
|
|
||||||
|
if err = req.readByteVerify("auth version", authRFC1929Ver); err != nil {
|
||||||
|
sendErrResp()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the username.
|
||||||
|
var ulen byte
|
||||||
|
if ulen, err = req.readByte(); err != nil {
|
||||||
|
sendErrResp()
|
||||||
|
return
|
||||||
|
} else if ulen < 1 {
|
||||||
|
sendErrResp()
|
||||||
|
return fmt.Errorf("username with 0 length")
|
||||||
|
}
|
||||||
|
uname := make([]byte, ulen)
|
||||||
|
if _, err = io.ReadFull(req.conn, uname); err != nil {
|
||||||
|
sendErrResp()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the password.
|
||||||
|
var plen byte
|
||||||
|
if plen, err = req.readByte(); err != nil {
|
||||||
|
sendErrResp()
|
||||||
|
return
|
||||||
|
} else if plen < 1 {
|
||||||
|
sendErrResp()
|
||||||
|
return fmt.Errorf("password with 0 length")
|
||||||
|
}
|
||||||
|
passwd := make([]byte, plen)
|
||||||
|
if _, err = io.ReadFull(req.conn, passwd); err != nil {
|
||||||
|
sendErrResp()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Auth.Uname = uname
|
||||||
|
req.Auth.Passwd = passwd
|
||||||
|
|
||||||
|
resp := []byte{authRFC1929Ver, authRFC1929Success}
|
||||||
|
_, err = req.conn.Write(resp[:])
|
||||||
|
return
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package sgfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/subgraph/ozipc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListSandboxesMsg struct {
|
||||||
|
_ string "ListSandboxes"
|
||||||
|
}
|
||||||
|
|
||||||
|
type SandboxInfo struct {
|
||||||
|
Id int
|
||||||
|
Address string
|
||||||
|
Profile string
|
||||||
|
Mounts []string
|
||||||
|
InitPid int
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListSandboxesResp struct {
|
||||||
|
Sandboxes []SandboxInfo "ListSandboxesResp"
|
||||||
|
}
|
||||||
|
|
||||||
|
const socketPath = "@oz-control"
|
||||||
|
|
||||||
|
var ozCtrlFactory = ipc.NewMsgFactory(
|
||||||
|
new(ListSandboxesMsg),
|
||||||
|
new(ListSandboxesResp),
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSandboxes() ([]SandboxInfo, error) {
|
||||||
|
c, err := ipc.Connect(socketPath, ozCtrlFactory, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer c.Close()
|
||||||
|
rr, err := c.ExchangeMsg(&ListSandboxesMsg{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := <-rr.Chan()
|
||||||
|
rr.Done()
|
||||||
|
sboxes := resp.Body.(*ListSandboxesResp)
|
||||||
|
return sboxes.Sandboxes, nil
|
||||||
|
}
|
@ -0,0 +1,426 @@
|
|||||||
|
package sgfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/subgraph/go-procsnitch"
|
||||||
|
"strings"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type socksChainConfig struct {
|
||||||
|
TargetSocksNet string
|
||||||
|
TargetSocksAddr string
|
||||||
|
ListenSocksNet string
|
||||||
|
ListenSocksAddr string
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type socksChain struct {
|
||||||
|
cfg *socksChainConfig
|
||||||
|
fw *Firewall
|
||||||
|
listener net.Listener
|
||||||
|
wg *sync.WaitGroup
|
||||||
|
procInfo procsnitch.ProcInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type socksChainSession struct {
|
||||||
|
cfg *socksChainConfig
|
||||||
|
clientConn net.Conn
|
||||||
|
upstreamConn net.Conn
|
||||||
|
req *Request
|
||||||
|
bndAddr *Address
|
||||||
|
optData []byte
|
||||||
|
procInfo procsnitch.ProcInfo
|
||||||
|
pinfo *procsnitch.Info
|
||||||
|
server *socksChain
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
socksVerdictDrop = 1
|
||||||
|
socksVerdictAccept = 2
|
||||||
|
socksVerdictAcceptTLSOnly = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
type pendingSocksConnection struct {
|
||||||
|
pol *Policy
|
||||||
|
hname string
|
||||||
|
srcIP net.IP
|
||||||
|
destIP net.IP
|
||||||
|
sourcePort uint16
|
||||||
|
destPort uint16
|
||||||
|
pinfo *procsnitch.Info
|
||||||
|
verdict chan int
|
||||||
|
prompting bool
|
||||||
|
optstr string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) sandbox() string {
|
||||||
|
return sc.pinfo.Sandbox
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) policy() *Policy {
|
||||||
|
return sc.pol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) procInfo() *procsnitch.Info {
|
||||||
|
return sc.pinfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) getOptString() string {
|
||||||
|
return sc.optstr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) hostname() string {
|
||||||
|
return sc.hname
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) dst() net.IP {
|
||||||
|
return sc.destIP
|
||||||
|
}
|
||||||
|
func (sc *pendingSocksConnection) proto() string {
|
||||||
|
return "tcp"
|
||||||
|
}
|
||||||
|
func (sc *pendingSocksConnection) srcPort() uint16 {
|
||||||
|
return sc.sourcePort
|
||||||
|
}
|
||||||
|
func (sc *pendingSocksConnection) dstPort() uint16 {
|
||||||
|
return sc.destPort
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) src() net.IP {
|
||||||
|
return sc.srcIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) deliverVerdict(v int) {
|
||||||
|
sc.verdict <- v
|
||||||
|
close(sc.verdict)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) accept() { sc.deliverVerdict(socksVerdictAccept) }
|
||||||
|
|
||||||
|
// need to generalize special accept
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) acceptTLSOnly() {sc.deliverVerdict(socksVerdictAcceptTLSOnly) }
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) drop() { sc.deliverVerdict(socksVerdictDrop) }
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) getPrompting() bool { return sc.prompting }
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) setPrompting(val bool) { sc.prompting = val }
|
||||||
|
|
||||||
|
func (sc *pendingSocksConnection) print() string { return "socks connection" }
|
||||||
|
|
||||||
|
func NewSocksChain(cfg *socksChainConfig, wg *sync.WaitGroup, fw *Firewall) *socksChain {
|
||||||
|
chain := socksChain{
|
||||||
|
cfg: cfg,
|
||||||
|
fw: fw,
|
||||||
|
wg: wg,
|
||||||
|
procInfo: procsnitch.SystemProcInfo{},
|
||||||
|
}
|
||||||
|
return &chain
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start initializes the SOCKS 5 server and starts
|
||||||
|
// accepting connections.
|
||||||
|
func (s *socksChain) start() {
|
||||||
|
var err error
|
||||||
|
s.listener, err = net.Listen(s.cfg.ListenSocksNet, s.cfg.ListenSocksAddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("ERR/socks: Failed to listen on the socks address: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.wg.Add(1)
|
||||||
|
go s.socksAcceptLoop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *socksChain) socksAcceptLoop() error {
|
||||||
|
defer s.wg.Done()
|
||||||
|
defer s.listener.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := s.listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
if e, ok := err.(net.Error); ok && !e.Temporary() {
|
||||||
|
log.Infof("ERR/socks: Failed to Accept(): %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
session := &socksChainSession{cfg: s.cfg, clientConn: conn, procInfo: s.procInfo, server: s}
|
||||||
|
go session.sessionWorker()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *socksChainSession) sessionWorker() {
|
||||||
|
defer c.clientConn.Close()
|
||||||
|
|
||||||
|
clientAddr := c.clientConn.RemoteAddr()
|
||||||
|
log.Infof("INFO/socks: New connection from: %v", clientAddr)
|
||||||
|
|
||||||
|
// Do the SOCKS handshake with the client, and read the command.
|
||||||
|
var err error
|
||||||
|
if c.req, err = Handshake(c.clientConn); err != nil {
|
||||||
|
log.Infof("ERR/socks: Failed SOCKS5 handshake: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.req.Auth.Uname) == 0 && len(c.req.Auth.Passwd) == 0 {
|
||||||
|
// Randomize username and password to force a new TOR circuit with each connection
|
||||||
|
rndbytes := []byte("sgfw" + strconv.Itoa(int(time.Now().UnixNano()) ^ os.Getpid()))
|
||||||
|
c.req.Auth.Uname = rndbytes
|
||||||
|
c.req.Auth.Passwd = rndbytes
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c.req.Cmd {
|
||||||
|
case CommandTorResolve, CommandTorResolvePTR:
|
||||||
|
err = c.dispatchTorSOCKS()
|
||||||
|
|
||||||
|
// If we reach here, the request has been dispatched and completed.
|
||||||
|
if err == nil {
|
||||||
|
// Successfully even, send the response back with the address.
|
||||||
|
c.req.ReplyAddr(ReplySucceeded, c.bndAddr)
|
||||||
|
}
|
||||||
|
case CommandConnect:
|
||||||
|
verdict, tls := c.filterConnect()
|
||||||
|
|
||||||
|
if !verdict {
|
||||||
|
c.req.Reply(ReplyConnectionRefused)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.handleConnect(tls)
|
||||||
|
default:
|
||||||
|
// Should *NEVER* happen, validated as part of handshake.
|
||||||
|
log.Infof("BUG/socks: Unsupported SOCKS command: 0x%02x", c.req.Cmd)
|
||||||
|
c.req.Reply(ReplyCommandNotSupported)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *socksChainSession) addressDetails() (string, net.IP, uint16) {
|
||||||
|
addr := c.req.Addr
|
||||||
|
host, pstr := addr.HostPort()
|
||||||
|
port, err := strconv.ParseUint(pstr, 10, 16)
|
||||||
|
if err != nil || port == 0 || port > 0xFFFF {
|
||||||
|
log.Warningf("Illegal port value in socks address: %v", addr)
|
||||||
|
return "", nil, 0
|
||||||
|
}
|
||||||
|
if addr.Type() == 3 {
|
||||||
|
return host, nil, uint16(port)
|
||||||
|
}
|
||||||
|
ip := net.ParseIP(host)
|
||||||
|
if ip == nil {
|
||||||
|
log.Warningf("Failed to extract address information from socks address: %v", addr)
|
||||||
|
}
|
||||||
|
return "", ip, uint16(port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findProxyEndpoint(pdata []string, conn net.Conn) (*procsnitch.Info, string) {
|
||||||
|
for _, pstr := range pdata {
|
||||||
|
toks := strings.Split(pstr, " ")
|
||||||
|
|
||||||
|
if len(toks) != 6 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s1, d1, s2, d2 := toks[0], toks[2], toks[3], toks[5]
|
||||||
|
|
||||||
|
if strings.HasSuffix(d1, ",") {
|
||||||
|
d1 = d1[0:len(d1)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if conn.LocalAddr().String() == d2 && conn.RemoteAddr().String() == s2 {
|
||||||
|
srcips, srcps, err := net.SplitHostPort(s1)
|
||||||
|
dstips, dstps, err2 := net.SplitHostPort(d1)
|
||||||
|
|
||||||
|
if err != nil && err2 != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
srcip := net.ParseIP(srcips)
|
||||||
|
dstip := net.ParseIP(dstips)
|
||||||
|
|
||||||
|
if srcip == nil || dstip == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
srcport, err := strconv.Atoi(srcps)
|
||||||
|
dstport, err2 := strconv.Atoi(dstps)
|
||||||
|
|
||||||
|
if err != nil || err2 != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
res := procsnitch.LookupTCPSocketProcessAll(srcip, uint16(srcport), dstip, uint16(dstport), nil)
|
||||||
|
res, optstr := LookupSandboxProc(srcip, uint16(srcport), dstip, uint16(dstport), "tcp", procsnitch.MATCH_STRICT, 0)
|
||||||
|
|
||||||
|
if res != nil {
|
||||||
|
return res, optstr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *socksChainSession) filterConnect() (bool, bool) {
|
||||||
|
// return filter verdict, tlsguard
|
||||||
|
|
||||||
|
allProxies, err := ListProxies()
|
||||||
|
var pinfo *procsnitch.Info = nil
|
||||||
|
var optstr = ""
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
pinfo, optstr = findProxyEndpoint(allProxies, c.clientConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pinfo == nil {
|
||||||
|
pinfo = procsnitch.FindProcessForConnection(c.clientConn, c.procInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pinfo == nil {
|
||||||
|
log.Warningf("No proc found for [socks5] connection from: %s", c.clientConn.RemoteAddr())
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
c.pinfo = pinfo
|
||||||
|
|
||||||
|
if optstr == "" {
|
||||||
|
optstr = "Via SOCKS5: " + c.cfg.Name
|
||||||
|
} else {
|
||||||
|
optstr = "[Via SOCKS5: " + c.cfg.Name + "] " + optstr
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warningf("Lookup policy for %v %v",pinfo.ExePath,pinfo.Sandbox)
|
||||||
|
policy := c.server.fw.PolicyForPathAndSandbox(GetRealRoot(pinfo.ExePath,pinfo.Pid),pinfo.Sandbox)
|
||||||
|
|
||||||
|
hostname, ip, port := c.addressDetails()
|
||||||
|
if ip == nil && hostname == "" {
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
result := policy.rules.filter(nil, nil, ip, port, hostname, pinfo, optstr)
|
||||||
|
log.Errorf("result %v",result)
|
||||||
|
switch result {
|
||||||
|
case FILTER_DENY:
|
||||||
|
return false, false
|
||||||
|
case FILTER_ALLOW:
|
||||||
|
return true, false
|
||||||
|
case FILTER_ALLOW_TLSONLY:
|
||||||
|
return true, true
|
||||||
|
case FILTER_PROMPT:
|
||||||
|
caddr := c.clientConn.RemoteAddr().String()
|
||||||
|
caddrt := strings.Split(caddr, ":")
|
||||||
|
caddrIP := net.IP{0,0,0,0}
|
||||||
|
caddrPort := uint16(0)
|
||||||
|
|
||||||
|
if len(caddrt) != 2 {
|
||||||
|
log.Errorf("Error reading peer information from SOCKS client connection")
|
||||||
|
} else {
|
||||||
|
srcp, err := strconv.Atoi(caddrt[1])
|
||||||
|
|
||||||
|
if err != nil || srcp <= 0 || srcp > 65535 {
|
||||||
|
log.Errorf("Error getting port of SOCKS client connection")
|
||||||
|
} else {
|
||||||
|
caddrPort = uint16(srcp)
|
||||||
|
ip := net.ParseIP(caddrt[0])
|
||||||
|
|
||||||
|
if ip == nil {
|
||||||
|
log.Errorf("Error getting host IP of SOCKS5 client connection: %v", err)
|
||||||
|
} else {
|
||||||
|
caddrIP = ip
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pending := &pendingSocksConnection{
|
||||||
|
pol: policy,
|
||||||
|
hname: hostname,
|
||||||
|
destIP: ip,
|
||||||
|
srcIP: caddrIP,
|
||||||
|
sourcePort: caddrPort,
|
||||||
|
destPort: port,
|
||||||
|
pinfo: pinfo,
|
||||||
|
verdict: make(chan int),
|
||||||
|
prompting: false,
|
||||||
|
optstr: optstr,
|
||||||
|
}
|
||||||
|
policy.processPromptResult(pending)
|
||||||
|
v := <-pending.verdict
|
||||||
|
if v == socksVerdictAccept {
|
||||||
|
return true, false
|
||||||
|
} else if v == socksVerdictAcceptTLSOnly {
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *socksChainSession) handleConnect(tls bool) {
|
||||||
|
err := c.dispatchTorSOCKS()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.req.Reply(ReplySucceeded)
|
||||||
|
defer c.upstreamConn.Close()
|
||||||
|
|
||||||
|
if c.optData != nil {
|
||||||
|
if _, err = c.upstreamConn.Write(c.optData); err != nil {
|
||||||
|
log.Infof("ERR/socks: Failed writing OptData: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.optData = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A upstream connection has been established, push data back and forth
|
||||||
|
// till the session is done.
|
||||||
|
c.forwardTraffic(tls)
|
||||||
|
log.Infof("INFO/socks: Closed SOCKS connection from: %v", c.clientConn.RemoteAddr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *socksChainSession) forwardTraffic(tls bool) {
|
||||||
|
if tls == true {
|
||||||
|
err := TLSGuard(c.clientConn, c.upstreamConn, c.req.Addr.addrStr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if c.pinfo.Sandbox != "" {
|
||||||
|
log.Errorf("Dropping traffic from %s (sandbox: %s) to %s due to TLSGuard violation: %v", c.pinfo.ExePath, c.pinfo.Sandbox, c.req.Addr.addrStr, err)
|
||||||
|
} else {
|
||||||
|
log.Errorf("Dropping traffic from %s (unsandboxed) to %s due to TLSGuard violation: %v", c.pinfo.ExePath, c.req.Addr.addrStr, err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
log.Notice("TLSGuard approved certificate presented for connection to: ", c.req.Addr.addrStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
copyLoop := func(dst, src net.Conn) {
|
||||||
|
defer wg.Done()
|
||||||
|
defer dst.Close()
|
||||||
|
|
||||||
|
io.Copy(dst, src)
|
||||||
|
}
|
||||||
|
go copyLoop(c.upstreamConn, c.clientConn)
|
||||||
|
go copyLoop(c.clientConn, c.upstreamConn)
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *socksChainSession) dispatchTorSOCKS() (err error) {
|
||||||
|
c.upstreamConn, c.bndAddr, err = Redispatch(c.cfg.TargetSocksNet, c.cfg.TargetSocksAddr, c.req)
|
||||||
|
if err != nil {
|
||||||
|
c.req.Reply(ErrorToReplyCode(err))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
@ -0,0 +1,305 @@
|
|||||||
|
package sgfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/subgraph/fw-daemon/socks5"
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MortalService can be killed at any time.
|
||||||
|
type MortalService struct {
|
||||||
|
network string
|
||||||
|
address string
|
||||||
|
connectionCallback func(net.Conn) error
|
||||||
|
|
||||||
|
conns []net.Conn
|
||||||
|
quit chan bool
|
||||||
|
listener net.Listener
|
||||||
|
waitGroup *sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMortalService creates a new MortalService
|
||||||
|
func NewMortalService(network, address string, connectionCallback func(net.Conn) error) *MortalService {
|
||||||
|
l := MortalService{
|
||||||
|
network: network,
|
||||||
|
address: address,
|
||||||
|
connectionCallback: connectionCallback,
|
||||||
|
|
||||||
|
conns: make([]net.Conn, 0, 10),
|
||||||
|
quit: make(chan bool),
|
||||||
|
waitGroup: &sync.WaitGroup{},
|
||||||
|
}
|
||||||
|
return &l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop will kill our listener and all it's connections
|
||||||
|
func (l *MortalService) Stop() {
|
||||||
|
log.Infof("stopping listener service %s:%s", l.network, l.address)
|
||||||
|
close(l.quit)
|
||||||
|
if l.listener != nil {
|
||||||
|
l.listener.Close()
|
||||||
|
}
|
||||||
|
l.waitGroup.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *MortalService) acceptLoop() {
|
||||||
|
defer l.waitGroup.Done()
|
||||||
|
defer func() {
|
||||||
|
log.Infof("stoping listener service %s:%s", l.network, l.address)
|
||||||
|
for i, conn := range l.conns {
|
||||||
|
if conn != nil {
|
||||||
|
log.Infof("Closing connection #%d", i)
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
defer l.listener.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := l.listener.Accept()
|
||||||
|
if nil != err {
|
||||||
|
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
log.Infof("MortalService connection accept failure: %s\n", err)
|
||||||
|
select {
|
||||||
|
case <-l.quit:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l.conns = append(l.conns, conn)
|
||||||
|
go l.handleConnection(conn, len(l.conns)-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *MortalService) createDeadlinedListener() error {
|
||||||
|
if l.network == "tcp" {
|
||||||
|
tcpAddr, err := net.ResolveTCPAddr("tcp", l.address)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("MortalService.createDeadlinedListener %s %s failure: %s", l.network, l.address, err)
|
||||||
|
}
|
||||||
|
tcpListener, err := net.ListenTCP("tcp", tcpAddr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("MortalService.createDeadlinedListener %s %s failure: %s", l.network, l.address, err)
|
||||||
|
}
|
||||||
|
tcpListener.SetDeadline(time.Now().Add(1e9))
|
||||||
|
l.listener = tcpListener
|
||||||
|
return nil
|
||||||
|
} else if l.network == "unix" {
|
||||||
|
unixAddr, err := net.ResolveUnixAddr("unix", l.address)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("MortalService.createDeadlinedListener %s %s failure: %s", l.network, l.address, err)
|
||||||
|
}
|
||||||
|
unixListener, err := net.ListenUnix("unix", unixAddr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("MortalService.createDeadlinedListener %s %s failure: %s", l.network, l.address, err)
|
||||||
|
}
|
||||||
|
unixListener.SetDeadline(time.Now().Add(1e9))
|
||||||
|
l.listener = unixListener
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
panic("")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the MortalService
|
||||||
|
func (l *MortalService) Start() error {
|
||||||
|
var err error
|
||||||
|
err = l.createDeadlinedListener()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
l.waitGroup.Add(1)
|
||||||
|
go l.acceptLoop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *MortalService) handleConnection(conn net.Conn, id int) error {
|
||||||
|
defer func() {
|
||||||
|
log.Infof("Closing connection #%d", id)
|
||||||
|
conn.Close()
|
||||||
|
l.conns[id] = nil
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.Infof("Starting connection #%d", id)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if err := l.connectionCallback(conn); err != nil {
|
||||||
|
log.Error(err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccumulatingService struct {
|
||||||
|
net, address string
|
||||||
|
banner string
|
||||||
|
buffer bytes.Buffer
|
||||||
|
mortalService *MortalService
|
||||||
|
hasProtocolInfo bool
|
||||||
|
hasAuthenticate bool
|
||||||
|
receivedChan chan bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAccumulatingService(net, address, banner string) *AccumulatingService {
|
||||||
|
l := AccumulatingService{
|
||||||
|
net: net,
|
||||||
|
address: address,
|
||||||
|
banner: banner,
|
||||||
|
hasProtocolInfo: true,
|
||||||
|
hasAuthenticate: true,
|
||||||
|
receivedChan: make(chan bool, 0),
|
||||||
|
}
|
||||||
|
return &l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccumulatingService) Start() {
|
||||||
|
a.mortalService = NewMortalService(a.net, a.address, a.SessionWorker)
|
||||||
|
a.mortalService.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccumulatingService) Stop() {
|
||||||
|
fmt.Println("AccumulatingService STOP")
|
||||||
|
a.mortalService.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccumulatingService) WaitUntilReceived() {
|
||||||
|
<-a.receivedChan
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccumulatingService) SessionWorker(conn net.Conn) error {
|
||||||
|
connReader := bufio.NewReader(conn)
|
||||||
|
conn.Write([]byte(a.banner))
|
||||||
|
for {
|
||||||
|
line, err := connReader.ReadBytes('\n')
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("AccumulatingService read error: %s\n", err)
|
||||||
|
}
|
||||||
|
lineStr := strings.TrimSpace(string(line))
|
||||||
|
a.buffer.WriteString(lineStr + "\n")
|
||||||
|
a.receivedChan <- true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fakeSocksSessionWorker(clientConn net.Conn, targetNet, targetAddr string) error {
|
||||||
|
defer clientConn.Close()
|
||||||
|
|
||||||
|
clientAddr := clientConn.RemoteAddr()
|
||||||
|
fmt.Printf("INFO/socks: New connection from: %v\n", clientAddr)
|
||||||
|
|
||||||
|
// Do the SOCKS handshake with the client, and read the command.
|
||||||
|
req, err := socks5.Handshake(clientConn)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("ERR/socks: Failed SOCKS5 handshake: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
var upstreamConn net.Conn
|
||||||
|
upstreamConn, err = net.Dial(targetNet, targetAddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer upstreamConn.Close()
|
||||||
|
req.Reply(socks5.ReplySucceeded)
|
||||||
|
|
||||||
|
// A upstream connection has been established, push data back and forth
|
||||||
|
// till the session is done.
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2)
|
||||||
|
copyLoop := func(dst, src net.Conn) {
|
||||||
|
defer wg.Done()
|
||||||
|
defer dst.Close()
|
||||||
|
|
||||||
|
io.Copy(dst, src)
|
||||||
|
}
|
||||||
|
go copyLoop(upstreamConn, clientConn)
|
||||||
|
go copyLoop(clientConn, upstreamConn)
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
fmt.Printf("INFO/socks: Closed SOCKS connection from: %v\n", clientAddr)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSocksServerProxyChain(t *testing.T) {
|
||||||
|
// socks client ---> socks chain ---> socks server ---> service
|
||||||
|
socksChainNet := "tcp"
|
||||||
|
socksChainAddr := "127.0.0.1:7750"
|
||||||
|
socksServerNet := "tcp"
|
||||||
|
socksServerAddr := "127.0.0.1:8850"
|
||||||
|
serviceNet := "tcp"
|
||||||
|
serviceAddr := "127.0.0.1:9950"
|
||||||
|
|
||||||
|
banner := "meow 123\r\n"
|
||||||
|
// setup the service listener
|
||||||
|
service := NewAccumulatingService(serviceNet, serviceAddr, banner)
|
||||||
|
service.Start()
|
||||||
|
defer service.Stop()
|
||||||
|
|
||||||
|
// setup the "socks server"
|
||||||
|
session := func(clientConn net.Conn) error {
|
||||||
|
return fakeSocksSessionWorker(clientConn, serviceNet, serviceAddr)
|
||||||
|
}
|
||||||
|
socksService := NewMortalService(socksServerNet, socksServerAddr, session)
|
||||||
|
socksService.Start()
|
||||||
|
defer socksService.Stop()
|
||||||
|
|
||||||
|
// setup the SOCKS proxy chain
|
||||||
|
socksConfig := socksChainConfig{
|
||||||
|
TargetSocksNet: socksServerNet,
|
||||||
|
TargetSocksAddr: socksServerAddr,
|
||||||
|
ListenSocksNet: socksChainNet,
|
||||||
|
ListenSocksAddr: socksChainAddr,
|
||||||
|
}
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
ds := dbusServer{}
|
||||||
|
chain := NewSocksChain(&socksConfig, &wg, &ds)
|
||||||
|
chain.start()
|
||||||
|
|
||||||
|
// setup the SOCKS client
|
||||||
|
auth := proxy.Auth{
|
||||||
|
User: "",
|
||||||
|
Password: "",
|
||||||
|
}
|
||||||
|
forward := proxy.NewPerHost(proxy.Direct, proxy.Direct)
|
||||||
|
socksClient, err := proxy.SOCKS5(socksChainNet, socksChainAddr, &auth, forward)
|
||||||
|
conn, err := socksClient.Dial(serviceNet, serviceAddr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// read a banner from the service
|
||||||
|
rd := bufio.NewReader(conn)
|
||||||
|
line := []byte{}
|
||||||
|
line, err = rd.ReadBytes('\n')
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if string(line) != banner {
|
||||||
|
t.Errorf("Did not receive expected banner. Got %s, wanted %s\n", string(line), banner)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the service some data and verify it was received
|
||||||
|
clientData := "hello world\r\n"
|
||||||
|
conn.Write([]byte(clientData))
|
||||||
|
service.WaitUntilReceived()
|
||||||
|
if service.buffer.String() != strings.TrimSpace(clientData)+"\n" {
|
||||||
|
t.Errorf("Client sent %s but service only received %s\n", "hello world\n", service.buffer.String())
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,180 @@
|
|||||||
|
package sgfw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func TLSGuard(conn, conn2 net.Conn, fqdn string) error {
|
||||||
|
// Should this be a requirement?
|
||||||
|
// if strings.HasSuffix(request.DestAddr.FQDN, "onion") {
|
||||||
|
|
||||||
|
handshakeByte, err := readNBytes(conn, 1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if handshakeByte[0] != 0x16 {
|
||||||
|
return errors.New("Blocked client from attempting non-TLS connection")
|
||||||
|
}
|
||||||
|
|
||||||
|
vers, err := readNBytes(conn, 2)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
length, err := readNBytes(conn, 2)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ffslen := int(int(length[0])<<8 | int(length[1]))
|
||||||
|
|
||||||
|
ffs, err := readNBytes(conn, ffslen)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmit client hello
|
||||||
|
conn2.Write(handshakeByte)
|
||||||
|
conn2.Write(vers)
|
||||||
|
conn2.Write(length)
|
||||||
|
conn2.Write(ffs)
|
||||||
|
|
||||||
|
// Read ServerHello
|
||||||
|
bytesRead := 0
|
||||||
|
var s byte // 0x0e is done
|
||||||
|
var responseBuf []byte = []byte{}
|
||||||
|
valid := false
|
||||||
|
sendToClient := false
|
||||||
|
|
||||||
|
for sendToClient == false {
|
||||||
|
// Handshake byte
|
||||||
|
serverhandshakeByte, err := readNBytes(conn2, 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
responseBuf = append(responseBuf, serverhandshakeByte[0])
|
||||||
|
bytesRead += 1
|
||||||
|
|
||||||
|
if serverhandshakeByte[0] != 0x16 {
|
||||||
|
return errors.New("Expected TLS server handshake byte was not received")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protocol version, 2 bytes
|
||||||
|
serverProtocolVer, err := readNBytes(conn2, 2)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesRead += 2
|
||||||
|
responseBuf = append(responseBuf, serverProtocolVer...)
|
||||||
|
|
||||||
|
// Record length, 2 bytes
|
||||||
|
serverRecordLen, err := readNBytes(conn2, 2)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesRead += 2
|
||||||
|
responseBuf = append(responseBuf, serverRecordLen...)
|
||||||
|
serverRecordLenInt := int(int(serverRecordLen[0])<<8 | int(serverRecordLen[1]))
|
||||||
|
|
||||||
|
// Record type byte
|
||||||
|
serverMsg, err := readNBytes(conn2, serverRecordLenInt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesRead += len(serverMsg)
|
||||||
|
responseBuf = append(responseBuf, serverMsg...)
|
||||||
|
s = serverMsg[0]
|
||||||
|
|
||||||
|
// Message len, 3 bytes
|
||||||
|
serverMessageLen := serverMsg[1:4]
|
||||||
|
serverMessageLenInt := int(int(serverMessageLen[0])<<16 | int(serverMessageLen[1])<<8 | int(serverMessageLen[2]))
|
||||||
|
|
||||||
|
// serverHelloBody, err := readNBytes(conn2, serverMessageLenInt)
|
||||||
|
serverHelloBody := serverMsg[4 : 4+serverMessageLenInt]
|
||||||
|
|
||||||
|
if s == 0x0b {
|
||||||
|
certChainLen := int(int(serverHelloBody[0])<<16 | int(serverHelloBody[1])<<8 | int(serverHelloBody[2]))
|
||||||
|
remaining := certChainLen
|
||||||
|
pos := serverHelloBody[3:certChainLen]
|
||||||
|
|
||||||
|
// var certChain []*x509.Certificate
|
||||||
|
var verifyOptions x509.VerifyOptions
|
||||||
|
|
||||||
|
if fqdn != "" {
|
||||||
|
verifyOptions.DNSName = fqdn
|
||||||
|
}
|
||||||
|
|
||||||
|
pool := x509.NewCertPool()
|
||||||
|
var c *x509.Certificate
|
||||||
|
|
||||||
|
for remaining > 0 {
|
||||||
|
certLen := int(int(pos[0])<<16 | int(pos[1])<<8 | int(pos[2]))
|
||||||
|
// fmt.Printf("Certs chain len %d, cert 1 len %d:\n", certChainLen, certLen)
|
||||||
|
cert := pos[3 : 3+certLen]
|
||||||
|
certs, err := x509.ParseCertificates(cert)
|
||||||
|
if remaining == certChainLen {
|
||||||
|
c = certs[0]
|
||||||
|
} else {
|
||||||
|
pool.AddCert(certs[0])
|
||||||
|
}
|
||||||
|
// certChain = append(certChain, certs[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
remaining = remaining - certLen - 3
|
||||||
|
if remaining > 0 {
|
||||||
|
pos = pos[3+certLen:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
verifyOptions.Intermediates = pool
|
||||||
|
|
||||||
|
_, err = c.Verify(verifyOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
valid = true
|
||||||
|
}
|
||||||
|
// else if s == 0x0d { fmt.Printf("found a client cert request, sending buf to client\n") }
|
||||||
|
} else if s == 0x0e {
|
||||||
|
sendToClient = true
|
||||||
|
} else if s == 0x0d {
|
||||||
|
sendToClient = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("Version bytes: %x %x\n", responseBuf[1], responseBuf[2])
|
||||||
|
// fmt.Printf("Len bytes: %x %x\n", responseBuf[3], responseBuf[4])
|
||||||
|
// fmt.Printf("Message type: %x\n", responseBuf[5])
|
||||||
|
// fmt.Printf("Message len: %x %x %x\n", responseBuf[6], responseBuf[7], responseBuf[8])
|
||||||
|
// fmt.Printf("Message body: %v\n", responseBuf[9:])
|
||||||
|
conn.Write(responseBuf)
|
||||||
|
responseBuf = []byte{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
return errors.New("Unknown error: TLS connection could not be validated")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readNBytes(conn net.Conn, numBytes int) ([]byte, error) {
|
||||||
|
res := make([]byte, 0)
|
||||||
|
temp := make([]byte, 1)
|
||||||
|
for i := 0; i < numBytes; i++ {
|
||||||
|
_, err := io.ReadAtLeast(conn, temp, 1)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res = append(res, temp[0])
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
|
||||||
|
|
||||||
|
<!DOCTYPE busconfig PUBLIC
|
||||||
|
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||||
|
<busconfig>
|
||||||
|
|
||||||
|
<!-- Only 'user' can own this service -->
|
||||||
|
<policy user="1000">
|
||||||
|
<allow own="com.subgraph.fwprompt.EventNotifier"/>
|
||||||
|
</policy>
|
||||||
|
|
||||||
|
<!-- Anyone can send messages to com.subgraph.fwprompt.EventNotifier -->
|
||||||
|
<policy user="0">
|
||||||
|
<allow send_destination="com.subgraph.fwprompt.EventNotifier"/>
|
||||||
|
</policy>
|
||||||
|
|
||||||
|
|
||||||
|
</busconfig>
|
||||||
|
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"Name": "Tor",
|
||||||
|
"SocksListener": "tcp|127.0.0.1:9998",
|
||||||
|
"TorSocks": "tcp|127.0.0.1:9050"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
|
Documentation=https://github.com/subgraph/fw-daemon
|
||||||
Description=Subgraph Firewall Daemon
|
Description=Subgraph Firewall Daemon
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Environment="GODEBUG=cgocheck=0"
|
Environment="GODEBUG=cgocheck=0"
|
||||||
|
ExecStartPre=/usr/bin/install -d /var/run/fw-daemon
|
||||||
ExecStart=/usr/sbin/fw-daemon
|
ExecStart=/usr/sbin/fw-daemon
|
||||||
ExecReload=/bin/kill -HUP ${MAINPID}
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
Copyright (c) 2013-2014 Conformal Systems LLC.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
@ -0,0 +1,28 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Antialias is a representation of Cairo's cairo_antialias_t.
|
||||||
|
type Antialias int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ANTIALIAS_DEFAULT Antialias = C.CAIRO_ANTIALIAS_DEFAULT
|
||||||
|
ANTIALIAS_NONE Antialias = C.CAIRO_ANTIALIAS_NONE
|
||||||
|
ANTIALIAS_GRAY Antialias = C.CAIRO_ANTIALIAS_GRAY
|
||||||
|
ANTIALIAS_SUBPIXEL Antialias = C.CAIRO_ANTIALIAS_SUBPIXEL
|
||||||
|
// ANTIALIAS_FAST Antialias = C.CAIRO_ANTIALIAS_FAST (since 1.12)
|
||||||
|
// ANTIALIAS_GOOD Antialias = C.CAIRO_ANTIALIAS_GOOD (since 1.12)
|
||||||
|
// ANTIALIAS_BEST Antialias = C.CAIRO_ANTIALIAS_BEST (since 1.12)
|
||||||
|
)
|
||||||
|
|
||||||
|
func marshalAntialias(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return Antialias(c), nil
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (c) 2013-2014 Conformal Systems <info@conformal.com>
|
||||||
|
//
|
||||||
|
// This file originated from: http://opensource.conformal.com/
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// Package cairo implements Go bindings for Cairo. Supports version 1.10 and
|
||||||
|
// later.
|
||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tm := []glib.TypeMarshaler{
|
||||||
|
// Enums
|
||||||
|
{glib.Type(C.cairo_gobject_antialias_get_type()), marshalAntialias},
|
||||||
|
{glib.Type(C.cairo_gobject_content_get_type()), marshalContent},
|
||||||
|
{glib.Type(C.cairo_gobject_fill_rule_get_type()), marshalFillRule},
|
||||||
|
{glib.Type(C.cairo_gobject_line_cap_get_type()), marshalLineCap},
|
||||||
|
{glib.Type(C.cairo_gobject_line_join_get_type()), marshalLineJoin},
|
||||||
|
{glib.Type(C.cairo_gobject_operator_get_type()), marshalOperator},
|
||||||
|
{glib.Type(C.cairo_gobject_status_get_type()), marshalStatus},
|
||||||
|
{glib.Type(C.cairo_gobject_surface_type_get_type()), marshalSurfaceType},
|
||||||
|
|
||||||
|
// Boxed
|
||||||
|
{glib.Type(C.cairo_gobject_context_get_type()), marshalContext},
|
||||||
|
{glib.Type(C.cairo_gobject_surface_get_type()), marshalSurface},
|
||||||
|
}
|
||||||
|
glib.RegisterGValueMarshalers(tm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
|
||||||
|
// Content is a representation of Cairo's cairo_content_t.
|
||||||
|
type Content int
|
||||||
|
|
||||||
|
const (
|
||||||
|
CONTENT_COLOR Content = C.CAIRO_CONTENT_COLOR
|
||||||
|
CONTENT_ALPHA Content = C.CAIRO_CONTENT_ALPHA
|
||||||
|
CONTENT_COLOR_ALPHA Content = C.CAIRO_CONTENT_COLOR_ALPHA
|
||||||
|
)
|
||||||
|
|
||||||
|
func marshalContent(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return Content(c), nil
|
||||||
|
}
|
@ -0,0 +1,401 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Context is a representation of Cairo's cairo_t.
|
||||||
|
type Context struct {
|
||||||
|
context *C.cairo_t
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying cairo_t.
|
||||||
|
func (v *Context) native() *C.cairo_t {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Context) GetCContext() *C.cairo_t {
|
||||||
|
return v.native()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native returns a pointer to the underlying cairo_t.
|
||||||
|
func (v *Context) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalContext(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_boxed((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
context := (*C.cairo_t)(unsafe.Pointer(c))
|
||||||
|
return wrapContext(context), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapContext(context *C.cairo_t) *Context {
|
||||||
|
return &Context{context}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create is a wrapper around cairo_create().
|
||||||
|
func Create(target *Surface) *Context {
|
||||||
|
c := C.cairo_create(target.native())
|
||||||
|
ctx := wrapContext(c)
|
||||||
|
runtime.SetFinalizer(ctx, (*Context).destroy)
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// reference is a wrapper around cairo_reference().
|
||||||
|
func (v *Context) reference() {
|
||||||
|
v.context = C.cairo_reference(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy is a wrapper around cairo_destroy().
|
||||||
|
func (v *Context) destroy() {
|
||||||
|
C.cairo_destroy(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status is a wrapper around cairo_status().
|
||||||
|
func (v *Context) Status() Status {
|
||||||
|
c := C.cairo_status(v.native())
|
||||||
|
return Status(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save is a wrapper around cairo_save().
|
||||||
|
func (v *Context) Save() {
|
||||||
|
C.cairo_save(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore is a wrapper around cairo_restore().
|
||||||
|
func (v *Context) Restore() {
|
||||||
|
C.cairo_restore(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTarget is a wrapper around cairo_get_target().
|
||||||
|
func (v *Context) GetTarget() *Surface {
|
||||||
|
c := C.cairo_get_target(v.native())
|
||||||
|
s := wrapSurface(c)
|
||||||
|
s.reference()
|
||||||
|
runtime.SetFinalizer(s, (*Surface).destroy)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushGroup is a wrapper around cairo_push_group().
|
||||||
|
func (v *Context) PushGroup() {
|
||||||
|
C.cairo_push_group(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushGroupWithContent is a wrapper around cairo_push_group_with_content().
|
||||||
|
func (v *Context) PushGroupWithContent(content Content) {
|
||||||
|
C.cairo_push_group_with_content(v.native(), C.cairo_content_t(content))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jrick) PopGroup (depends on Pattern)
|
||||||
|
|
||||||
|
// PopGroupToSource is a wrapper around cairo_pop_group_to_source().
|
||||||
|
func (v *Context) PopGroupToSource() {
|
||||||
|
C.cairo_pop_group_to_source(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGroupTarget is a wrapper around cairo_get_group_target().
|
||||||
|
func (v *Context) GetGroupTarget() *Surface {
|
||||||
|
c := C.cairo_get_group_target(v.native())
|
||||||
|
s := wrapSurface(c)
|
||||||
|
s.reference()
|
||||||
|
runtime.SetFinalizer(s, (*Surface).destroy)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSourceRGB is a wrapper around cairo_set_source_rgb().
|
||||||
|
func (v *Context) SetSourceRGB(red, green, blue float64) {
|
||||||
|
C.cairo_set_source_rgb(v.native(), C.double(red), C.double(green),
|
||||||
|
C.double(blue))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSourceRGBA is a wrapper around cairo_set_source_rgba().
|
||||||
|
func (v *Context) SetSourceRGBA(red, green, blue, alpha float64) {
|
||||||
|
C.cairo_set_source_rgba(v.native(), C.double(red), C.double(green),
|
||||||
|
C.double(blue), C.double(alpha))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jrick) SetSource (depends on Pattern)
|
||||||
|
|
||||||
|
// SetSourceSurface is a wrapper around cairo_set_source_surface().
|
||||||
|
func (v *Context) SetSourceSurface(surface *Surface, x, y float64) {
|
||||||
|
C.cairo_set_source_surface(v.native(), surface.native(), C.double(x),
|
||||||
|
C.double(y))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jrick) GetSource (depends on Pattern)
|
||||||
|
|
||||||
|
// SetAntialias is a wrapper around cairo_set_antialias().
|
||||||
|
func (v *Context) SetAntialias(antialias Antialias) {
|
||||||
|
C.cairo_set_antialias(v.native(), C.cairo_antialias_t(antialias))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAntialias is a wrapper around cairo_get_antialias().
|
||||||
|
func (v *Context) GetAntialias() Antialias {
|
||||||
|
c := C.cairo_get_antialias(v.native())
|
||||||
|
return Antialias(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDash is a wrapper around cairo_set_dash().
|
||||||
|
func (v *Context) SetDash(dashes []float64, offset float64) {
|
||||||
|
header := (*reflect.SliceHeader)(unsafe.Pointer(&dashes))
|
||||||
|
cdashes := (*C.double)(unsafe.Pointer(header.Data))
|
||||||
|
C.cairo_set_dash(v.native(), cdashes, C.int(header.Len),
|
||||||
|
C.double(offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDashCount is a wrapper around cairo_get_dash_count().
|
||||||
|
func (v *Context) GetDashCount() int {
|
||||||
|
c := C.cairo_get_dash_count(v.native())
|
||||||
|
return int(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDash is a wrapper around cairo_get_dash().
|
||||||
|
func (v *Context) GetDash() (dashes []float64, offset float64) {
|
||||||
|
dashCount := v.GetDashCount()
|
||||||
|
cdashes := (*C.double)(C.calloc(8, C.size_t(dashCount)))
|
||||||
|
var coffset C.double
|
||||||
|
C.cairo_get_dash(v.native(), cdashes, &coffset)
|
||||||
|
header := (*reflect.SliceHeader)((unsafe.Pointer(&dashes)))
|
||||||
|
header.Data = uintptr(unsafe.Pointer(cdashes))
|
||||||
|
header.Len = dashCount
|
||||||
|
header.Cap = dashCount
|
||||||
|
return dashes, float64(coffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFillRule is a wrapper around cairo_set_fill_rule().
|
||||||
|
func (v *Context) SetFillRule(fillRule FillRule) {
|
||||||
|
C.cairo_set_fill_rule(v.native(), C.cairo_fill_rule_t(fillRule))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFillRule is a wrapper around cairo_get_fill_rule().
|
||||||
|
func (v *Context) GetFillRule() FillRule {
|
||||||
|
c := C.cairo_get_fill_rule(v.native())
|
||||||
|
return FillRule(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLineCap is a wrapper around cairo_set_line_cap().
|
||||||
|
func (v *Context) SetLineCap(lineCap LineCap) {
|
||||||
|
C.cairo_set_line_cap(v.native(), C.cairo_line_cap_t(lineCap))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLineCap is a wrapper around cairo_get_line_cap().
|
||||||
|
func (v *Context) GetLineCap() LineCap {
|
||||||
|
c := C.cairo_get_line_cap(v.native())
|
||||||
|
return LineCap(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLineJoin is a wrapper around cairo_set_line_join().
|
||||||
|
func (v *Context) SetLineJoin(lineJoin LineJoin) {
|
||||||
|
C.cairo_set_line_join(v.native(), C.cairo_line_join_t(lineJoin))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLineJoin is a wrapper around cairo_get_line_join().
|
||||||
|
func (v *Context) GetLineJoin() LineJoin {
|
||||||
|
c := C.cairo_get_line_join(v.native())
|
||||||
|
return LineJoin(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLineWidth is a wrapper around cairo_set_line_width().
|
||||||
|
func (v *Context) SetLineWidth(width float64) {
|
||||||
|
C.cairo_set_line_width(v.native(), C.double(width))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLineWidth is a wrapper cairo_get_line_width().
|
||||||
|
func (v *Context) GetLineWidth() float64 {
|
||||||
|
c := C.cairo_get_line_width(v.native())
|
||||||
|
return float64(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMiterLimit is a wrapper around cairo_set_miter_limit().
|
||||||
|
func (v *Context) SetMiterLimit(limit float64) {
|
||||||
|
C.cairo_set_miter_limit(v.native(), C.double(limit))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMiterLimit is a wrapper around cairo_get_miter_limit().
|
||||||
|
func (v *Context) GetMiterLimit() float64 {
|
||||||
|
c := C.cairo_get_miter_limit(v.native())
|
||||||
|
return float64(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOperator is a wrapper around cairo_set_operator().
|
||||||
|
func (v *Context) SetOperator(op Operator) {
|
||||||
|
C.cairo_set_operator(v.native(), C.cairo_operator_t(op))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOperator is a wrapper around cairo_get_operator().
|
||||||
|
func (v *Context) GetOperator() Operator {
|
||||||
|
c := C.cairo_get_operator(v.native())
|
||||||
|
return Operator(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTolerance is a wrapper around cairo_set_tolerance().
|
||||||
|
func (v *Context) SetTolerance(tolerance float64) {
|
||||||
|
C.cairo_set_tolerance(v.native(), C.double(tolerance))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTolerance is a wrapper around cairo_get_tolerance().
|
||||||
|
func (v *Context) GetTolerance() float64 {
|
||||||
|
c := C.cairo_get_tolerance(v.native())
|
||||||
|
return float64(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clip is a wrapper around cairo_clip().
|
||||||
|
func (v *Context) Clip() {
|
||||||
|
C.cairo_clip(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClipPreserve is a wrapper around cairo_clip_preserve().
|
||||||
|
func (v *Context) ClipPreserve() {
|
||||||
|
C.cairo_clip_preserve(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClipExtents is a wrapper around cairo_clip_extents().
|
||||||
|
func (v *Context) ClipExtents() (x1, y1, x2, y2 float64) {
|
||||||
|
var cx1, cy1, cx2, cy2 C.double
|
||||||
|
C.cairo_clip_extents(v.native(), &cx1, &cy1, &cx2, &cy2)
|
||||||
|
return float64(cx1), float64(cy1), float64(cx2), float64(cy2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InClip is a wrapper around cairo_in_clip().
|
||||||
|
func (v *Context) InClip(x, y float64) bool {
|
||||||
|
c := C.cairo_in_clip(v.native(), C.double(x), C.double(y))
|
||||||
|
return gobool(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetClip is a wrapper around cairo_reset_clip().
|
||||||
|
func (v *Context) ResetClip() {
|
||||||
|
C.cairo_reset_clip(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rectangle is a wrapper around cairo_rectangle().
|
||||||
|
func (v *Context) Rectangle(x, y, w, h float64) {
|
||||||
|
C.cairo_rectangle(v.native(), C.double(x), C.double(y), C.double(w), C.double(h))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arc is a wrapper around cairo_arc().
|
||||||
|
func (v *Context) Arc(xc, yc, radius, angle1, angle2 float64) {
|
||||||
|
C.cairo_arc(v.native(), C.double(xc), C.double(yc), C.double(radius), C.double(angle1), C.double(angle2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArcNegative is a wrapper around cairo_arc_negative().
|
||||||
|
func (v *Context) ArcNegative(xc, yc, radius, angle1, angle2 float64) {
|
||||||
|
C.cairo_arc_negative(v.native(), C.double(xc), C.double(yc), C.double(radius), C.double(angle1), C.double(angle2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineTo is a wrapper around cairo_line_to().
|
||||||
|
func (v *Context) LineTo(x, y float64) {
|
||||||
|
C.cairo_line_to(v.native(), C.double(x), C.double(y))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurveTo is a wrapper around cairo_curve_to().
|
||||||
|
func (v *Context) CurveTo(x1, y1, x2, y2, x3, y3 float64) {
|
||||||
|
C.cairo_curve_to(v.native(), C.double(x1), C.double(y1), C.double(x2), C.double(y2), C.double(x3), C.double(y3))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveTo is a wrapper around cairo_move_to().
|
||||||
|
func (v *Context) MoveTo(x, y float64) {
|
||||||
|
C.cairo_move_to(v.native(), C.double(x), C.double(y))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jrick) CopyRectangleList (depends on RectangleList)
|
||||||
|
|
||||||
|
// Fill is a wrapper around cairo_fill().
|
||||||
|
func (v *Context) Fill() {
|
||||||
|
C.cairo_fill(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClosePath is a wrapper around cairo_close_path().
|
||||||
|
func (v *Context) ClosePath() {
|
||||||
|
C.cairo_close_path(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPath is a wrapper around cairo_new_path().
|
||||||
|
func (v *Context) NewPath() {
|
||||||
|
C.cairo_new_path(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentPoint is a wrapper around cairo_get_current_point().
|
||||||
|
func (v *Context) GetCurrentPoint() (x, y float64) {
|
||||||
|
C.cairo_get_current_point(v.native(), (*C.double)(&x), (*C.double)(&y))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// FillPreserve is a wrapper around cairo_fill_preserve().
|
||||||
|
func (v *Context) FillPreserve() {
|
||||||
|
C.cairo_fill_preserve(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// FillExtents is a wrapper around cairo_fill_extents().
|
||||||
|
func (v *Context) FillExtents() (x1, y1, x2, y2 float64) {
|
||||||
|
var cx1, cy1, cx2, cy2 C.double
|
||||||
|
C.cairo_fill_extents(v.native(), &cx1, &cy1, &cx2, &cy2)
|
||||||
|
return float64(cx1), float64(cy1), float64(cx2), float64(cy2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InFill is a wrapper around cairo_in_fill().
|
||||||
|
func (v *Context) InFill(x, y float64) bool {
|
||||||
|
c := C.cairo_in_fill(v.native(), C.double(x), C.double(y))
|
||||||
|
return gobool(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jrick) Mask (depends on Pattern)
|
||||||
|
|
||||||
|
// MaskSurface is a wrapper around cairo_mask_surface().
|
||||||
|
func (v *Context) MaskSurface(surface *Surface, surfaceX, surfaceY float64) {
|
||||||
|
C.cairo_mask_surface(v.native(), surface.native(), C.double(surfaceX),
|
||||||
|
C.double(surfaceY))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paint is a wrapper around cairo_paint().
|
||||||
|
func (v *Context) Paint() {
|
||||||
|
C.cairo_paint(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaintWithAlpha is a wrapper around cairo_paint_with_alpha().
|
||||||
|
func (v *Context) PaintWithAlpha(alpha float64) {
|
||||||
|
C.cairo_paint_with_alpha(v.native(), C.double(alpha))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stroke is a wrapper around cairo_stroke().
|
||||||
|
func (v *Context) Stroke() {
|
||||||
|
C.cairo_stroke(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrokePreserve is a wrapper around cairo_stroke_preserve().
|
||||||
|
func (v *Context) StrokePreserve() {
|
||||||
|
C.cairo_stroke_preserve(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrokeExtents is a wrapper around cairo_stroke_extents().
|
||||||
|
func (v *Context) StrokeExtents() (x1, y1, x2, y2 float64) {
|
||||||
|
var cx1, cy1, cx2, cy2 C.double
|
||||||
|
C.cairo_stroke_extents(v.native(), &cx1, &cy1, &cx2, &cy2)
|
||||||
|
return float64(cx1), float64(cy1), float64(cx2), float64(cy2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InStroke is a wrapper around cairo_in_stroke().
|
||||||
|
func (v *Context) InStroke(x, y float64) bool {
|
||||||
|
c := C.cairo_in_stroke(v.native(), C.double(x), C.double(y))
|
||||||
|
return gobool(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyPage is a wrapper around cairo_copy_page().
|
||||||
|
func (v *Context) CopyPage() {
|
||||||
|
C.cairo_copy_page(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShowPage is a wrapper around cairo_show_page().
|
||||||
|
func (v *Context) ShowPage() {
|
||||||
|
C.cairo_show_page(v.native())
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
type ErrorStatus Status
|
||||||
|
|
||||||
|
func (e ErrorStatus) Error() string {
|
||||||
|
return StatusToString(Status(e))
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FillRule is a representation of Cairo's cairo_fill_rule_t.
|
||||||
|
type FillRule int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FILL_RULE_WINDING FillRule = C.CAIRO_FILL_RULE_WINDING
|
||||||
|
FILL_RULE_EVEN_ODD FillRule = C.CAIRO_FILL_RULE_EVEN_ODD
|
||||||
|
)
|
||||||
|
|
||||||
|
func marshalFillRule(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return FillRule(c), nil
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Format is a representation of Cairo's cairo_format_t.
|
||||||
|
type Format int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FORMAT_INVALID Format = C.CAIRO_FORMAT_INVALID
|
||||||
|
FORMAT_ARGB32 Format = C.CAIRO_FORMAT_ARGB32
|
||||||
|
FORMAT_RGB24 Format = C.CAIRO_FORMAT_RGB24
|
||||||
|
FORMAT_A8 Format = C.CAIRO_FORMAT_A8
|
||||||
|
FORMAT_A1 Format = C.CAIRO_FORMAT_A1
|
||||||
|
FORMAT_RGB16_565 Format = C.CAIRO_FORMAT_RGB16_565
|
||||||
|
FORMAT_RGB30 Format = C.CAIRO_FORMAT_RGB30
|
||||||
|
)
|
||||||
|
|
||||||
|
func marshalFormat(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return Format(c), nil
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LineCap is a representation of Cairo's cairo_line_cap_t.
|
||||||
|
type LineCap int
|
||||||
|
|
||||||
|
const (
|
||||||
|
LINE_CAP_BUTT LineCap = C.CAIRO_LINE_CAP_BUTT
|
||||||
|
LINE_CAP_ROUND LineCap = C.CAIRO_LINE_CAP_ROUND
|
||||||
|
LINE_CAP_SQUARE LineCap = C.CAIRO_LINE_CAP_SQUARE
|
||||||
|
)
|
||||||
|
|
||||||
|
func marshalLineCap(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return LineCap(c), nil
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LineJoin is a representation of Cairo's cairo_line_join_t.
|
||||||
|
type LineJoin int
|
||||||
|
|
||||||
|
const (
|
||||||
|
LINE_JOIN_MITER LineJoin = C.CAIRO_LINE_JOIN_MITER
|
||||||
|
LINE_JOIN_ROUND LineJoin = C.CAIRO_LINE_JOIN_ROUND
|
||||||
|
LINE_JOIN_BEVEL LineJoin = C.CAIRO_LINE_JOIN_BEVEL
|
||||||
|
)
|
||||||
|
|
||||||
|
func marshalLineJoin(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return LineJoin(c), nil
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// MimeType is a representation of Cairo's CAIRO_MIME_TYPE_*
|
||||||
|
// preprocessor constants.
|
||||||
|
type MimeType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MIME_TYPE_JP2 MimeType = "image/jp2"
|
||||||
|
MIME_TYPE_JPEG MimeType = "image/jpeg"
|
||||||
|
MIME_TYPE_PNG MimeType = "image/png"
|
||||||
|
MIME_TYPE_URI MimeType = "image/x-uri"
|
||||||
|
MIME_TYPE_UNIQUE_ID MimeType = "application/x-cairo.uuid"
|
||||||
|
)
|
@ -0,0 +1,50 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Operator is a representation of Cairo's cairo_operator_t.
|
||||||
|
type Operator int
|
||||||
|
|
||||||
|
const (
|
||||||
|
OPERATOR_CLEAR Operator = C.CAIRO_OPERATOR_CLEAR
|
||||||
|
OPERATOR_SOURCE Operator = C.CAIRO_OPERATOR_SOURCE
|
||||||
|
OPERATOR_OVER Operator = C.CAIRO_OPERATOR_OVER
|
||||||
|
OPERATOR_IN Operator = C.CAIRO_OPERATOR_IN
|
||||||
|
OPERATOR_OUT Operator = C.CAIRO_OPERATOR_OUT
|
||||||
|
OPERATOR_ATOP Operator = C.CAIRO_OPERATOR_ATOP
|
||||||
|
OPERATOR_DEST Operator = C.CAIRO_OPERATOR_DEST
|
||||||
|
OPERATOR_DEST_OVER Operator = C.CAIRO_OPERATOR_DEST_OVER
|
||||||
|
OPERATOR_DEST_IN Operator = C.CAIRO_OPERATOR_DEST_IN
|
||||||
|
OPERATOR_DEST_OUT Operator = C.CAIRO_OPERATOR_DEST_OUT
|
||||||
|
OPERATOR_DEST_ATOP Operator = C.CAIRO_OPERATOR_DEST_ATOP
|
||||||
|
OPERATOR_XOR Operator = C.CAIRO_OPERATOR_XOR
|
||||||
|
OPERATOR_ADD Operator = C.CAIRO_OPERATOR_ADD
|
||||||
|
OPERATOR_SATURATE Operator = C.CAIRO_OPERATOR_SATURATE
|
||||||
|
OPERATOR_MULTIPLY Operator = C.CAIRO_OPERATOR_MULTIPLY
|
||||||
|
OPERATOR_SCREEN Operator = C.CAIRO_OPERATOR_SCREEN
|
||||||
|
OPERATOR_OVERLAY Operator = C.CAIRO_OPERATOR_OVERLAY
|
||||||
|
OPERATOR_DARKEN Operator = C.CAIRO_OPERATOR_DARKEN
|
||||||
|
OPERATOR_LIGHTEN Operator = C.CAIRO_OPERATOR_LIGHTEN
|
||||||
|
OPERATOR_COLOR_DODGE Operator = C.CAIRO_OPERATOR_COLOR_DODGE
|
||||||
|
OPERATOR_COLOR_BURN Operator = C.CAIRO_OPERATOR_COLOR_BURN
|
||||||
|
OPERATOR_HARD_LIGHT Operator = C.CAIRO_OPERATOR_HARD_LIGHT
|
||||||
|
OPERATOR_SOFT_LIGHT Operator = C.CAIRO_OPERATOR_SOFT_LIGHT
|
||||||
|
OPERATOR_DIFFERENCE Operator = C.CAIRO_OPERATOR_DIFFERENCE
|
||||||
|
OPERATOR_EXCLUSION Operator = C.CAIRO_OPERATOR_EXCLUSION
|
||||||
|
OPERATOR_HSL_HUE Operator = C.CAIRO_OPERATOR_HSL_HUE
|
||||||
|
OPERATOR_HSL_SATURATION Operator = C.CAIRO_OPERATOR_HSL_SATURATION
|
||||||
|
OPERATOR_HSL_COLOR Operator = C.CAIRO_OPERATOR_HSL_COLOR
|
||||||
|
OPERATOR_HSL_LUMINOSITY Operator = C.CAIRO_OPERATOR_HSL_LUMINOSITY
|
||||||
|
)
|
||||||
|
|
||||||
|
func marshalOperator(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return Operator(c), nil
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Status is a representation of Cairo's cairo_status_t.
|
||||||
|
type Status int
|
||||||
|
|
||||||
|
const (
|
||||||
|
STATUS_SUCCESS Status = C.CAIRO_STATUS_SUCCESS
|
||||||
|
STATUS_NO_MEMORY Status = C.CAIRO_STATUS_NO_MEMORY
|
||||||
|
STATUS_INVALID_RESTORE Status = C.CAIRO_STATUS_INVALID_RESTORE
|
||||||
|
STATUS_INVALID_POP_GROUP Status = C.CAIRO_STATUS_INVALID_POP_GROUP
|
||||||
|
STATUS_NO_CURRENT_POINT Status = C.CAIRO_STATUS_NO_CURRENT_POINT
|
||||||
|
STATUS_INVALID_MATRIX Status = C.CAIRO_STATUS_INVALID_MATRIX
|
||||||
|
STATUS_INVALID_STATUS Status = C.CAIRO_STATUS_INVALID_STATUS
|
||||||
|
STATUS_NULL_POINTER Status = C.CAIRO_STATUS_NULL_POINTER
|
||||||
|
STATUS_INVALID_STRING Status = C.CAIRO_STATUS_INVALID_STRING
|
||||||
|
STATUS_INVALID_PATH_DATA Status = C.CAIRO_STATUS_INVALID_PATH_DATA
|
||||||
|
STATUS_READ_ERROR Status = C.CAIRO_STATUS_READ_ERROR
|
||||||
|
STATUS_WRITE_ERROR Status = C.CAIRO_STATUS_WRITE_ERROR
|
||||||
|
STATUS_SURFACE_FINISHED Status = C.CAIRO_STATUS_SURFACE_FINISHED
|
||||||
|
STATUS_SURFACE_TYPE_MISMATCH Status = C.CAIRO_STATUS_SURFACE_TYPE_MISMATCH
|
||||||
|
STATUS_PATTERN_TYPE_MISMATCH Status = C.CAIRO_STATUS_PATTERN_TYPE_MISMATCH
|
||||||
|
STATUS_INVALID_CONTENT Status = C.CAIRO_STATUS_INVALID_CONTENT
|
||||||
|
STATUS_INVALID_FORMAT Status = C.CAIRO_STATUS_INVALID_FORMAT
|
||||||
|
STATUS_INVALID_VISUAL Status = C.CAIRO_STATUS_INVALID_VISUAL
|
||||||
|
STATUS_FILE_NOT_FOUND Status = C.CAIRO_STATUS_FILE_NOT_FOUND
|
||||||
|
STATUS_INVALID_DASH Status = C.CAIRO_STATUS_INVALID_DASH
|
||||||
|
STATUS_INVALID_DSC_COMMENT Status = C.CAIRO_STATUS_INVALID_DSC_COMMENT
|
||||||
|
STATUS_INVALID_INDEX Status = C.CAIRO_STATUS_INVALID_INDEX
|
||||||
|
STATUS_CLIP_NOT_REPRESENTABLE Status = C.CAIRO_STATUS_CLIP_NOT_REPRESENTABLE
|
||||||
|
STATUS_TEMP_FILE_ERROR Status = C.CAIRO_STATUS_TEMP_FILE_ERROR
|
||||||
|
STATUS_INVALID_STRIDE Status = C.CAIRO_STATUS_INVALID_STRIDE
|
||||||
|
STATUS_FONT_TYPE_MISMATCH Status = C.CAIRO_STATUS_FONT_TYPE_MISMATCH
|
||||||
|
STATUS_USER_FONT_IMMUTABLE Status = C.CAIRO_STATUS_USER_FONT_IMMUTABLE
|
||||||
|
STATUS_USER_FONT_ERROR Status = C.CAIRO_STATUS_USER_FONT_ERROR
|
||||||
|
STATUS_NEGATIVE_COUNT Status = C.CAIRO_STATUS_NEGATIVE_COUNT
|
||||||
|
STATUS_INVALID_CLUSTERS Status = C.CAIRO_STATUS_INVALID_CLUSTERS
|
||||||
|
STATUS_INVALID_SLANT Status = C.CAIRO_STATUS_INVALID_SLANT
|
||||||
|
STATUS_INVALID_WEIGHT Status = C.CAIRO_STATUS_INVALID_WEIGHT
|
||||||
|
STATUS_INVALID_SIZE Status = C.CAIRO_STATUS_INVALID_SIZE
|
||||||
|
STATUS_USER_FONT_NOT_IMPLEMENTED Status = C.CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED
|
||||||
|
STATUS_DEVICE_TYPE_MISMATCH Status = C.CAIRO_STATUS_DEVICE_TYPE_MISMATCH
|
||||||
|
STATUS_DEVICE_ERROR Status = C.CAIRO_STATUS_DEVICE_ERROR
|
||||||
|
// STATUS_INVALID_MESH_CONSTRUCTION Status = C.CAIRO_STATUS_INVALID_MESH_CONSTRUCTION (since 1.12)
|
||||||
|
// STATUS_DEVICE_FINISHED Status = C.CAIRO_STATUS_DEVICE_FINISHED (since 1.12)
|
||||||
|
)
|
||||||
|
|
||||||
|
var key_Status = map[Status]string{
|
||||||
|
|
||||||
|
STATUS_SUCCESS: "CAIRO_STATUS_SUCCESS",
|
||||||
|
STATUS_NO_MEMORY: "CAIRO_STATUS_NO_MEMORY",
|
||||||
|
STATUS_INVALID_RESTORE: "CAIRO_STATUS_INVALID_RESTORE",
|
||||||
|
STATUS_INVALID_POP_GROUP: "CAIRO_STATUS_INVALID_POP_GROUP",
|
||||||
|
STATUS_NO_CURRENT_POINT: "CAIRO_STATUS_NO_CURRENT_POINT",
|
||||||
|
STATUS_INVALID_MATRIX: "CAIRO_STATUS_INVALID_MATRIX",
|
||||||
|
STATUS_INVALID_STATUS: "CAIRO_STATUS_INVALID_STATUS",
|
||||||
|
STATUS_NULL_POINTER: "CAIRO_STATUS_NULL_POINTER",
|
||||||
|
STATUS_INVALID_STRING: "CAIRO_STATUS_INVALID_STRING",
|
||||||
|
STATUS_INVALID_PATH_DATA: "CAIRO_STATUS_INVALID_PATH_DATA",
|
||||||
|
STATUS_READ_ERROR: "CAIRO_STATUS_READ_ERROR",
|
||||||
|
STATUS_WRITE_ERROR: "CAIRO_STATUS_WRITE_ERROR",
|
||||||
|
STATUS_SURFACE_FINISHED: "CAIRO_STATUS_SURFACE_FINISHED",
|
||||||
|
STATUS_SURFACE_TYPE_MISMATCH: "CAIRO_STATUS_SURFACE_TYPE_MISMATCH",
|
||||||
|
STATUS_PATTERN_TYPE_MISMATCH: "CAIRO_STATUS_PATTERN_TYPE_MISMATCH",
|
||||||
|
STATUS_INVALID_CONTENT: "CAIRO_STATUS_INVALID_CONTENT",
|
||||||
|
STATUS_INVALID_FORMAT: "CAIRO_STATUS_INVALID_FORMAT",
|
||||||
|
STATUS_INVALID_VISUAL: "CAIRO_STATUS_INVALID_VISUAL",
|
||||||
|
STATUS_FILE_NOT_FOUND: "CAIRO_STATUS_FILE_NOT_FOUND",
|
||||||
|
STATUS_INVALID_DASH: "CAIRO_STATUS_INVALID_DASH",
|
||||||
|
STATUS_INVALID_DSC_COMMENT: "CAIRO_STATUS_INVALID_DSC_COMMENT",
|
||||||
|
STATUS_INVALID_INDEX: "CAIRO_STATUS_INVALID_INDEX",
|
||||||
|
STATUS_CLIP_NOT_REPRESENTABLE: "CAIRO_STATUS_CLIP_NOT_REPRESENTABLE",
|
||||||
|
STATUS_TEMP_FILE_ERROR: "CAIRO_STATUS_TEMP_FILE_ERROR",
|
||||||
|
STATUS_INVALID_STRIDE: "CAIRO_STATUS_INVALID_STRIDE",
|
||||||
|
STATUS_FONT_TYPE_MISMATCH: "CAIRO_STATUS_FONT_TYPE_MISMATCH",
|
||||||
|
STATUS_USER_FONT_IMMUTABLE: "CAIRO_STATUS_USER_FONT_IMMUTABLE",
|
||||||
|
STATUS_USER_FONT_ERROR: "CAIRO_STATUS_USER_FONT_ERROR",
|
||||||
|
STATUS_NEGATIVE_COUNT: "CAIRO_STATUS_NEGATIVE_COUNT",
|
||||||
|
STATUS_INVALID_CLUSTERS: "CAIRO_STATUS_INVALID_CLUSTERS",
|
||||||
|
STATUS_INVALID_SLANT: "CAIRO_STATUS_INVALID_SLANT",
|
||||||
|
STATUS_INVALID_WEIGHT: "CAIRO_STATUS_INVALID_WEIGHT",
|
||||||
|
STATUS_INVALID_SIZE: "CAIRO_STATUS_INVALID_SIZE",
|
||||||
|
STATUS_USER_FONT_NOT_IMPLEMENTED: "CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED",
|
||||||
|
STATUS_DEVICE_TYPE_MISMATCH: "CAIRO_STATUS_DEVICE_TYPE_MISMATCH",
|
||||||
|
STATUS_DEVICE_ERROR: "CAIRO_STATUS_DEVICE_ERROR",
|
||||||
|
}
|
||||||
|
|
||||||
|
func StatusToString(status Status) string {
|
||||||
|
|
||||||
|
s, ok := key_Status[status]
|
||||||
|
if !ok {
|
||||||
|
s = "CAIRO_STATUS_UNDEFINED"
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalStatus(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return Status(c), nil
|
||||||
|
}
|
@ -0,0 +1,215 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(jrick) SetUserData (depends on UserDataKey and DestroyFunc)
|
||||||
|
|
||||||
|
// TODO(jrick) GetUserData (depends on UserDataKey)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cairo_surface_t
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Surface is a representation of Cairo's cairo_surface_t.
|
||||||
|
type Surface struct {
|
||||||
|
surface *C.cairo_surface_t
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSurfaceFromPNG(fileName string) (*Surface, error) {
|
||||||
|
|
||||||
|
cstr := C.CString(fileName)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
surfaceNative := C.cairo_image_surface_create_from_png(cstr)
|
||||||
|
|
||||||
|
status := Status(C.cairo_surface_status(surfaceNative))
|
||||||
|
if status != STATUS_SUCCESS {
|
||||||
|
return nil, ErrorStatus(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Surface{surfaceNative}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateImageSurface is a wrapper around cairo_image_surface_create().
|
||||||
|
func CreateImageSurface(format Format, width, height int) *Surface {
|
||||||
|
c := C.cairo_image_surface_create(C.cairo_format_t(format),
|
||||||
|
C.int(width), C.int(height))
|
||||||
|
s := wrapSurface(c)
|
||||||
|
runtime.SetFinalizer(s, (*Surface).destroy)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying cairo_surface_t.
|
||||||
|
func (v *Surface) native() *C.cairo_surface_t {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.surface
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native returns a pointer to the underlying cairo_surface_t.
|
||||||
|
func (v *Surface) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalSurface(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_boxed((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
surface := (*C.cairo_surface_t)(unsafe.Pointer(c))
|
||||||
|
return wrapSurface(surface), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapSurface(surface *C.cairo_surface_t) *Surface {
|
||||||
|
return &Surface{surface}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSurface creates a gotk3 cairo Surface from a pointer to a
|
||||||
|
// C cairo_surface_t. This is primarily designed for use with other
|
||||||
|
// gotk3 packages and should be avoided by applications.
|
||||||
|
func NewSurface(s uintptr, needsRef bool) *Surface {
|
||||||
|
ptr := (*C.cairo_surface_t)(unsafe.Pointer(s))
|
||||||
|
surface := wrapSurface(ptr)
|
||||||
|
if needsRef {
|
||||||
|
surface.reference()
|
||||||
|
}
|
||||||
|
runtime.SetFinalizer(surface, (*Surface).destroy)
|
||||||
|
return surface
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSimilar is a wrapper around cairo_surface_create_similar().
|
||||||
|
func (v *Surface) CreateSimilar(content Content, width, height int) *Surface {
|
||||||
|
c := C.cairo_surface_create_similar(v.native(),
|
||||||
|
C.cairo_content_t(content), C.int(width), C.int(height))
|
||||||
|
s := wrapSurface(c)
|
||||||
|
runtime.SetFinalizer(s, (*Surface).destroy)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO cairo_surface_create_similar_image (since 1.12)
|
||||||
|
|
||||||
|
// CreateForRectangle is a wrapper around cairo_surface_create_for_rectangle().
|
||||||
|
func (v *Surface) CreateForRectangle(x, y, width, height float64) *Surface {
|
||||||
|
c := C.cairo_surface_create_for_rectangle(v.native(), C.double(x),
|
||||||
|
C.double(y), C.double(width), C.double(height))
|
||||||
|
s := wrapSurface(c)
|
||||||
|
runtime.SetFinalizer(s, (*Surface).destroy)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// reference is a wrapper around cairo_surface_reference().
|
||||||
|
func (v *Surface) reference() {
|
||||||
|
v.surface = C.cairo_surface_reference(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy is a wrapper around cairo_surface_destroy().
|
||||||
|
func (v *Surface) destroy() {
|
||||||
|
C.cairo_surface_destroy(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status is a wrapper around cairo_surface_status().
|
||||||
|
func (v *Surface) Status() Status {
|
||||||
|
c := C.cairo_surface_status(v.native())
|
||||||
|
return Status(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush is a wrapper around cairo_surface_flush().
|
||||||
|
func (v *Surface) Flush() {
|
||||||
|
C.cairo_surface_flush(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jrick) GetDevice (requires Device bindings)
|
||||||
|
|
||||||
|
// TODO(jrick) GetFontOptions (require FontOptions bindings)
|
||||||
|
|
||||||
|
// TODO(jrick) GetContent (requires Content bindings)
|
||||||
|
|
||||||
|
// MarkDirty is a wrapper around cairo_surface_mark_dirty().
|
||||||
|
func (v *Surface) MarkDirty() {
|
||||||
|
C.cairo_surface_mark_dirty(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkDirtyRectangle is a wrapper around cairo_surface_mark_dirty_rectangle().
|
||||||
|
func (v *Surface) MarkDirtyRectangle(x, y, width, height int) {
|
||||||
|
C.cairo_surface_mark_dirty_rectangle(v.native(), C.int(x), C.int(y),
|
||||||
|
C.int(width), C.int(height))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDeviceOffset is a wrapper around cairo_surface_set_device_offset().
|
||||||
|
func (v *Surface) SetDeviceOffset(x, y float64) {
|
||||||
|
C.cairo_surface_set_device_offset(v.native(), C.double(x), C.double(y))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDeviceOffset is a wrapper around cairo_surface_get_device_offset().
|
||||||
|
func (v *Surface) GetDeviceOffset() (x, y float64) {
|
||||||
|
var xOffset, yOffset C.double
|
||||||
|
C.cairo_surface_get_device_offset(v.native(), &xOffset, &yOffset)
|
||||||
|
return float64(xOffset), float64(yOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFallbackResolution is a wrapper around
|
||||||
|
// cairo_surface_set_fallback_resolution().
|
||||||
|
func (v *Surface) SetFallbackResolution(xPPI, yPPI float64) {
|
||||||
|
C.cairo_surface_set_fallback_resolution(v.native(), C.double(xPPI),
|
||||||
|
C.double(yPPI))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFallbackResolution is a wrapper around
|
||||||
|
// cairo_surface_get_fallback_resolution().
|
||||||
|
func (v *Surface) GetFallbackResolution() (xPPI, yPPI float64) {
|
||||||
|
var x, y C.double
|
||||||
|
C.cairo_surface_get_fallback_resolution(v.native(), &x, &y)
|
||||||
|
return float64(x), float64(y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetType is a wrapper around cairo_surface_get_type().
|
||||||
|
func (v *Surface) GetType() SurfaceType {
|
||||||
|
c := C.cairo_surface_get_type(v.native())
|
||||||
|
return SurfaceType(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jrick) SetUserData (depends on UserDataKey and DestroyFunc)
|
||||||
|
|
||||||
|
// TODO(jrick) GetUserData (depends on UserDataKey)
|
||||||
|
|
||||||
|
// CopyPage is a wrapper around cairo_surface_copy_page().
|
||||||
|
func (v *Surface) CopyPage() {
|
||||||
|
C.cairo_surface_copy_page(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShowPage is a wrapper around cairo_surface_show_page().
|
||||||
|
func (v *Surface) ShowPage() {
|
||||||
|
C.cairo_surface_show_page(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasShowTextGlyphs is a wrapper around cairo_surface_has_show_text_glyphs().
|
||||||
|
func (v *Surface) HasShowTextGlyphs() bool {
|
||||||
|
c := C.cairo_surface_has_show_text_glyphs(v.native())
|
||||||
|
return gobool(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jrick) SetMimeData (depends on DestroyFunc)
|
||||||
|
|
||||||
|
// GetMimeData is a wrapper around cairo_surface_get_mime_data(). The
|
||||||
|
// returned mimetype data is returned as a Go byte slice.
|
||||||
|
func (v *Surface) GetMimeData(mimeType MimeType) []byte {
|
||||||
|
cstr := C.CString(string(mimeType))
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
var data *C.uchar
|
||||||
|
var length C.ulong
|
||||||
|
C.cairo_surface_get_mime_data(v.native(), cstr, &data, &length)
|
||||||
|
return C.GoBytes(unsafe.Pointer(data), C.int(length))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jrick) SupportsMimeType (since 1.12)
|
||||||
|
|
||||||
|
// TODO(jrick) MapToImage (since 1.12)
|
||||||
|
|
||||||
|
// TODO(jrick) UnmapImage (since 1.12)
|
@ -0,0 +1,46 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SurfaceType is a representation of Cairo's cairo_surface_type_t.
|
||||||
|
type SurfaceType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
SURFACE_TYPE_IMAGE SurfaceType = C.CAIRO_SURFACE_TYPE_IMAGE
|
||||||
|
SURFACE_TYPE_PDF SurfaceType = C.CAIRO_SURFACE_TYPE_PDF
|
||||||
|
SURFACE_TYPE_PS SurfaceType = C.CAIRO_SURFACE_TYPE_PS
|
||||||
|
SURFACE_TYPE_XLIB SurfaceType = C.CAIRO_SURFACE_TYPE_XLIB
|
||||||
|
SURFACE_TYPE_XCB SurfaceType = C.CAIRO_SURFACE_TYPE_XCB
|
||||||
|
SURFACE_TYPE_GLITZ SurfaceType = C.CAIRO_SURFACE_TYPE_GLITZ
|
||||||
|
SURFACE_TYPE_QUARTZ SurfaceType = C.CAIRO_SURFACE_TYPE_QUARTZ
|
||||||
|
SURFACE_TYPE_WIN32 SurfaceType = C.CAIRO_SURFACE_TYPE_WIN32
|
||||||
|
SURFACE_TYPE_BEOS SurfaceType = C.CAIRO_SURFACE_TYPE_BEOS
|
||||||
|
SURFACE_TYPE_DIRECTFB SurfaceType = C.CAIRO_SURFACE_TYPE_DIRECTFB
|
||||||
|
SURFACE_TYPE_SVG SurfaceType = C.CAIRO_SURFACE_TYPE_SVG
|
||||||
|
SURFACE_TYPE_OS2 SurfaceType = C.CAIRO_SURFACE_TYPE_OS2
|
||||||
|
SURFACE_TYPE_WIN32_PRINTING SurfaceType = C.CAIRO_SURFACE_TYPE_WIN32_PRINTING
|
||||||
|
SURFACE_TYPE_QUARTZ_IMAGE SurfaceType = C.CAIRO_SURFACE_TYPE_QUARTZ_IMAGE
|
||||||
|
SURFACE_TYPE_SCRIPT SurfaceType = C.CAIRO_SURFACE_TYPE_SCRIPT
|
||||||
|
SURFACE_TYPE_QT SurfaceType = C.CAIRO_SURFACE_TYPE_QT
|
||||||
|
SURFACE_TYPE_RECORDING SurfaceType = C.CAIRO_SURFACE_TYPE_RECORDING
|
||||||
|
SURFACE_TYPE_VG SurfaceType = C.CAIRO_SURFACE_TYPE_VG
|
||||||
|
SURFACE_TYPE_GL SurfaceType = C.CAIRO_SURFACE_TYPE_GL
|
||||||
|
SURFACE_TYPE_DRM SurfaceType = C.CAIRO_SURFACE_TYPE_DRM
|
||||||
|
SURFACE_TYPE_TEE SurfaceType = C.CAIRO_SURFACE_TYPE_TEE
|
||||||
|
SURFACE_TYPE_XML SurfaceType = C.CAIRO_SURFACE_TYPE_XML
|
||||||
|
SURFACE_TYPE_SKIA SurfaceType = C.CAIRO_SURFACE_TYPE_SKIA
|
||||||
|
SURFACE_TYPE_SUBSURFACE SurfaceType = C.CAIRO_SURFACE_TYPE_SUBSURFACE
|
||||||
|
// SURFACE_TYPE_COGL SurfaceType = C.CAIRO_SURFACE_TYPE_COGL (since 1.12)
|
||||||
|
)
|
||||||
|
|
||||||
|
func marshalSurfaceType(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return SurfaceType(c), nil
|
||||||
|
}
|
@ -0,0 +1,127 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FontSlant is a representation of Cairo's cairo_font_slant_t
|
||||||
|
type FontSlant int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FONT_SLANT_NORMAL FontSlant = C.CAIRO_FONT_SLANT_NORMAL
|
||||||
|
FONT_SLANT_ITALIC FontSlant = C.CAIRO_FONT_SLANT_ITALIC
|
||||||
|
FONT_SLANT_OBLIQUE FontSlant = C.CAIRO_FONT_SLANT_OBLIQUE
|
||||||
|
)
|
||||||
|
|
||||||
|
// FontWeight is a representation of Cairo's cairo_font_weight_t
|
||||||
|
type FontWeight int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FONT_WEIGHT_NORMAL FontWeight = C.CAIRO_FONT_WEIGHT_NORMAL
|
||||||
|
FONT_WEIGHT_BOLD FontWeight = C.CAIRO_FONT_WEIGHT_BOLD
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *Context) SelectFontFace(family string, slant FontSlant, weight FontWeight) {
|
||||||
|
cstr := C.CString(family)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.cairo_select_font_face(v.native(), (*C.char)(cstr), C.cairo_font_slant_t(slant), C.cairo_font_weight_t(weight))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Context) SetFontSize(size float64) {
|
||||||
|
C.cairo_set_font_size(v.native(), C.double(size))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: cairo_set_font_matrix
|
||||||
|
|
||||||
|
// TODO: cairo_get_font_matrix
|
||||||
|
|
||||||
|
// TODO: cairo_set_font_options
|
||||||
|
|
||||||
|
// TODO: cairo_get_font_options
|
||||||
|
|
||||||
|
// TODO: cairo_set_font_face
|
||||||
|
|
||||||
|
// TODO: cairo_get_font_face
|
||||||
|
|
||||||
|
// TODO: cairo_set_scaled_font
|
||||||
|
|
||||||
|
// TODO: cairo_get_scaled_font
|
||||||
|
|
||||||
|
func (v *Context) ShowText(utf8 string) {
|
||||||
|
cstr := C.CString(utf8)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.cairo_show_text(v.native(), (*C.char)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: cairo_show_glyphs
|
||||||
|
|
||||||
|
// TODO: cairo_show_text_glyphs
|
||||||
|
|
||||||
|
type FontExtents struct {
|
||||||
|
Ascent float64
|
||||||
|
Descent float64
|
||||||
|
Height float64
|
||||||
|
MaxXAdvance float64
|
||||||
|
MaxYAdvance float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Context) FontExtents() FontExtents {
|
||||||
|
var extents C.cairo_font_extents_t
|
||||||
|
C.cairo_font_extents(v.native(), &extents)
|
||||||
|
return FontExtents{
|
||||||
|
Ascent: float64(extents.ascent),
|
||||||
|
Descent: float64(extents.descent),
|
||||||
|
Height: float64(extents.height),
|
||||||
|
MaxXAdvance: float64(extents.max_x_advance),
|
||||||
|
MaxYAdvance: float64(extents.max_y_advance),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextExtents struct {
|
||||||
|
XBearing float64
|
||||||
|
YBearing float64
|
||||||
|
Width float64
|
||||||
|
Height float64
|
||||||
|
XAdvance float64
|
||||||
|
YAdvance float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Context) TextExtents(utf8 string) TextExtents {
|
||||||
|
cstr := C.CString(utf8)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
var extents C.cairo_text_extents_t
|
||||||
|
C.cairo_text_extents(v.native(), (*C.char)(cstr), &extents)
|
||||||
|
return TextExtents{
|
||||||
|
XBearing: float64(extents.x_bearing),
|
||||||
|
YBearing: float64(extents.y_bearing),
|
||||||
|
Width: float64(extents.width),
|
||||||
|
Height: float64(extents.height),
|
||||||
|
XAdvance: float64(extents.x_advance),
|
||||||
|
YAdvance: float64(extents.y_advance),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: cairo_glyph_extents
|
||||||
|
|
||||||
|
// TODO: cairo_toy_font_face_create
|
||||||
|
|
||||||
|
// TODO: cairo_toy_font_face_get_family
|
||||||
|
|
||||||
|
// TODO: cairo_toy_font_face_get_slant
|
||||||
|
|
||||||
|
// TODO: cairo_toy_font_face_get_weight
|
||||||
|
|
||||||
|
// TODO: cairo_glyph_allocate
|
||||||
|
|
||||||
|
// TODO: cairo_glyph_free
|
||||||
|
|
||||||
|
// TODO: cairo_text_cluster_allocate
|
||||||
|
|
||||||
|
// TODO: cairo_text_cluster_free
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// Translate is a wrapper around cairo_translate.
|
||||||
|
func (v *Context) Translate(tx, ty float64) {
|
||||||
|
C.cairo_translate(v.native(), C.double(tx), C.double(ty))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale is a wrapper around cairo_scale.
|
||||||
|
func (v *Context) Scale(sx, sy float64) {
|
||||||
|
C.cairo_scale(v.native(), C.double(sx), C.double(sy))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate is a wrapper around cairo_rotate.
|
||||||
|
func (v *Context) Rotate(angle float64) {
|
||||||
|
C.cairo_rotate(v.native(), C.double(angle))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: The following depend on cairo_matrix_t:
|
||||||
|
//void cairo_transform ()
|
||||||
|
//void cairo_set_matrix ()
|
||||||
|
//void cairo_get_matrix ()
|
||||||
|
//void cairo_identity_matrix ()
|
||||||
|
//void cairo_user_to_device ()
|
||||||
|
//void cairo_user_to_device_distance ()
|
||||||
|
//void cairo_device_to_user ()
|
||||||
|
//void cairo_device_to_user_distance ()
|
@ -0,0 +1,21 @@
|
|||||||
|
package cairo
|
||||||
|
|
||||||
|
// #cgo pkg-config: cairo cairo-gobject
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <cairo.h>
|
||||||
|
// #include <cairo-gobject.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func cairobool(b bool) C.cairo_bool_t {
|
||||||
|
if b {
|
||||||
|
return C.cairo_bool_t(1)
|
||||||
|
}
|
||||||
|
return C.cairo_bool_t(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gobool(b C.cairo_bool_t) bool {
|
||||||
|
if b != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2014 Conformal Systems <info@conformal.com>
|
||||||
|
*
|
||||||
|
* This file originated from: http://opensource.conformal.com/
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Type Casting
|
||||||
|
static GdkAtom
|
||||||
|
toGdkAtom(void *p)
|
||||||
|
{
|
||||||
|
return ((GdkAtom)p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkDevice *
|
||||||
|
toGdkDevice(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_DEVICE(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkCursor *
|
||||||
|
toGdkCursor(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_CURSOR(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkDeviceManager *
|
||||||
|
toGdkDeviceManager(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_DEVICE_MANAGER(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkDisplay *
|
||||||
|
toGdkDisplay(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_DISPLAY(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkDragContext *
|
||||||
|
toGdkDragContext(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_DRAG_CONTEXT(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkPixbuf *
|
||||||
|
toGdkPixbuf(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_PIXBUF(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_gdk_pixbuf_save_png(GdkPixbuf *pixbuf,
|
||||||
|
const char *filename, GError ** err, const char *compression)
|
||||||
|
{
|
||||||
|
return gdk_pixbuf_save(pixbuf, filename, "png", err, "compression", compression, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_gdk_pixbuf_save_jpeg(GdkPixbuf *pixbuf,
|
||||||
|
const char *filename, GError ** err, const char *quality)
|
||||||
|
{
|
||||||
|
return gdk_pixbuf_save(pixbuf, filename, "jpeg", err, "quality", quality, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkPixbufLoader *
|
||||||
|
toGdkPixbufLoader(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_PIXBUF_LOADER(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkScreen *
|
||||||
|
toGdkScreen(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_SCREEN(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkVisual *
|
||||||
|
toGdkVisual(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_VISUAL(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkWindow *
|
||||||
|
toGdkWindow(void *p)
|
||||||
|
{
|
||||||
|
return (GDK_WINDOW(p));
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2013-2014 Conformal Systems <info@conformal.com>
|
||||||
|
//
|
||||||
|
// This file originated from: http://opensource.conformal.com/
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// This file includes wrapers for symbols deprecated beginning with GTK 3.10,
|
||||||
|
// and should only be included in a build targeted intended to target GTK
|
||||||
|
// 3.8 or earlier. To target an earlier build build, use the build tag
|
||||||
|
// gtk_MAJOR_MINOR. For example, to target GTK 3.8, run
|
||||||
|
// 'go build -tags gtk_3_8'.
|
||||||
|
// +build gtk_3_6 gtk_3_8
|
||||||
|
|
||||||
|
package gdk
|
||||||
|
|
||||||
|
// #cgo pkg-config: gdk-3.0
|
||||||
|
// #include <gdk/gdk.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// GetNScreens is a wrapper around gdk_display_get_n_screens().
|
||||||
|
func (v *Display) GetNScreens() int {
|
||||||
|
c := C.gdk_display_get_n_screens(v.native())
|
||||||
|
return int(c)
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
//+build gtk_3_6 gtk_3_8 gtk_3_10 gtk_3_12 gtk_3_14
|
||||||
|
|
||||||
|
package gdk
|
||||||
|
|
||||||
|
// #cgo pkg-config: gdk-3.0
|
||||||
|
// #include <gdk/gdk.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// SupportsComposite() is a wrapper around gdk_display_supports_composite().
|
||||||
|
func (v *Display) SupportsComposite() bool {
|
||||||
|
c := C.gdk_display_supports_composite(v.native())
|
||||||
|
return gobool(c)
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,198 @@
|
|||||||
|
package gdk
|
||||||
|
|
||||||
|
// #cgo pkg-config: gdk-3.0
|
||||||
|
// #include <gdk/gdk.h>
|
||||||
|
// #include "gdk.go.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GdkScreen
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Screen is a representation of GDK's GdkScreen.
|
||||||
|
type Screen struct {
|
||||||
|
*glib.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GdkScreen.
|
||||||
|
func (v *Screen) native() *C.GdkScreen {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(v.GObject)
|
||||||
|
return C.toGdkScreen(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native returns a pointer to the underlying GdkScreen.
|
||||||
|
func (v *Screen) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalScreen(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))}
|
||||||
|
return &Screen{obj}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toScreen(s *C.GdkScreen) (*Screen, error) {
|
||||||
|
if s == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
obj := &glib.Object{glib.ToGObject(unsafe.Pointer(s))}
|
||||||
|
return &Screen{obj}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRGBAVisual is a wrapper around gdk_screen_get_rgba_visual().
|
||||||
|
func (v *Screen) GetRGBAVisual() (*Visual, error) {
|
||||||
|
c := C.gdk_screen_get_rgba_visual(v.native())
|
||||||
|
if c == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))}
|
||||||
|
visual := &Visual{obj}
|
||||||
|
obj.Ref()
|
||||||
|
runtime.SetFinalizer(obj, (*glib.Object).Unref)
|
||||||
|
return visual, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSystemVisual is a wrapper around gdk_screen_get_system_visual().
|
||||||
|
func (v *Screen) GetSystemVisual() (*Visual, error) {
|
||||||
|
c := C.gdk_screen_get_system_visual(v.native())
|
||||||
|
if c == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
obj := &glib.Object{glib.ToGObject(unsafe.Pointer(c))}
|
||||||
|
visual := &Visual{obj}
|
||||||
|
obj.Ref()
|
||||||
|
runtime.SetFinalizer(obj, (*glib.Object).Unref)
|
||||||
|
return visual, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWidth is a wrapper around gdk_screen_get_width().
|
||||||
|
func (v *Screen) GetWidth() int {
|
||||||
|
c := C.gdk_screen_get_width(v.native())
|
||||||
|
return int(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeight is a wrapper around gdk_screen_get_height().
|
||||||
|
func (v *Screen) GetHeight() int {
|
||||||
|
c := C.gdk_screen_get_height(v.native())
|
||||||
|
return int(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScreenGetDefault is a wrapper aroud gdk_screen_get_default().
|
||||||
|
func ScreenGetDefault() (*Screen, error) {
|
||||||
|
return toScreen(C.gdk_screen_get_default())
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsComposited is a wrapper around gdk_screen_is_composited().
|
||||||
|
func (v *Screen) IsComposited() bool {
|
||||||
|
return gobool(C.gdk_screen_is_composited(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRootWindow is a wrapper around gdk_screen_get_root_window().
|
||||||
|
func (v *Screen) GetRootWindow() (*Window, error) {
|
||||||
|
return toWindow(C.gdk_screen_get_root_window(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDisplay is a wrapper around gdk_screen_get_display().
|
||||||
|
func (v *Screen) GetDisplay() (*Display, error) {
|
||||||
|
return toDisplay(C.gdk_screen_get_display(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNumber is a wrapper around gdk_screen_get_number().
|
||||||
|
func (v *Screen) GetNumber() int {
|
||||||
|
return int(C.gdk_screen_get_number(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWidthMM is a wrapper around gdk_screen_get_width_mm().
|
||||||
|
func (v *Screen) GetWidthMM() int {
|
||||||
|
return int(C.gdk_screen_get_width_mm(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeightMM is a wrapper around gdk_screen_get_height_mm().
|
||||||
|
func (v *Screen) GetHeightMM() int {
|
||||||
|
return int(C.gdk_screen_get_height_mm(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func toString(c *C.gchar) (string, error) {
|
||||||
|
if c == nil {
|
||||||
|
return "", nilPtrErr
|
||||||
|
}
|
||||||
|
return C.GoString((*C.char)(c)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeDisplayName is a wrapper around gdk_screen_make_display_name().
|
||||||
|
func (v *Screen) MakeDisplayName() (string, error) {
|
||||||
|
return toString(C.gdk_screen_make_display_name(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNMonitors is a wrapper around gdk_screen_get_n_monitors().
|
||||||
|
func (v *Screen) GetNMonitors() int {
|
||||||
|
return int(C.gdk_screen_get_n_monitors(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrimaryMonitor is a wrapper around gdk_screen_get_primary_monitor().
|
||||||
|
func (v *Screen) GetPrimaryMonitor() int {
|
||||||
|
return int(C.gdk_screen_get_primary_monitor(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMonitorAtPoint is a wrapper around gdk_screen_get_monitor_at_point().
|
||||||
|
func (v *Screen) GetMonitorAtPoint(x, y int) int {
|
||||||
|
return int(C.gdk_screen_get_monitor_at_point(v.native(), C.gint(x), C.gint(y)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMonitorAtWindow is a wrapper around gdk_screen_get_monitor_at_window().
|
||||||
|
func (v *Screen) GetMonitorAtWindow(w *Window) int {
|
||||||
|
return int(C.gdk_screen_get_monitor_at_window(v.native(), w.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMonitorHeightMM is a wrapper around gdk_screen_get_monitor_height_mm().
|
||||||
|
func (v *Screen) GetMonitorHeightMM(m int) int {
|
||||||
|
return int(C.gdk_screen_get_monitor_height_mm(v.native(), C.gint(m)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMonitorWidthMM is a wrapper around gdk_screen_get_monitor_width_mm().
|
||||||
|
func (v *Screen) GetMonitorWidthMM(m int) int {
|
||||||
|
return int(C.gdk_screen_get_monitor_width_mm(v.native(), C.gint(m)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMonitorPlugName is a wrapper around gdk_screen_get_monitor_plug_name().
|
||||||
|
func (v *Screen) GetMonitorPlugName(m int) (string, error) {
|
||||||
|
return toString(C.gdk_screen_get_monitor_plug_name(v.native(), C.gint(m)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMonitorScaleFactor is a wrapper around gdk_screen_get_monitor_scale_factor().
|
||||||
|
func (v *Screen) GetMonitorScaleFactor(m int) int {
|
||||||
|
return int(C.gdk_screen_get_monitor_scale_factor(v.native(), C.gint(m)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResolution is a wrapper around gdk_screen_get_resolution().
|
||||||
|
func (v *Screen) GetResolution() float64 {
|
||||||
|
return float64(C.gdk_screen_get_resolution(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetResolution is a wrapper around gdk_screen_set_resolution().
|
||||||
|
func (v *Screen) SetResolution(r float64) {
|
||||||
|
C.gdk_screen_set_resolution(v.native(), C.gdouble(r))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetActiveWindow is a wrapper around gdk_screen_get_active_window().
|
||||||
|
func (v *Screen) GetActiveWindow() (*Window, error) {
|
||||||
|
return toWindow(C.gdk_screen_get_active_window(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// void gdk_screen_set_font_options ()
|
||||||
|
// gboolean gdk_screen_get_setting ()
|
||||||
|
// const cairo_font_options_t * gdk_screen_get_font_options ()
|
||||||
|
// GList * gdk_screen_get_window_stack ()
|
||||||
|
// GList * gdk_screen_list_visuals ()
|
||||||
|
// GList * gdk_screen_get_toplevel_windows ()
|
||||||
|
// void gdk_screen_get_monitor_geometry ()
|
||||||
|
// void gdk_screen_get_monitor_workarea ()
|
@ -0,0 +1,25 @@
|
|||||||
|
// +build !linux no_x11
|
||||||
|
|
||||||
|
package gdk
|
||||||
|
|
||||||
|
func WorkspaceControlSupported() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetScreenNumber is a wrapper around gdk_x11_screen_get_screen_number().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Screen) GetScreenNumber() int {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNumberOfDesktops is a wrapper around gdk_x11_screen_get_number_of_desktops().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Screen) GetNumberOfDesktops() uint32 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentDesktop is a wrapper around gdk_x11_screen_get_current_desktop().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Screen) GetCurrentDesktop() uint32 {
|
||||||
|
return 0
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
// +build linux
|
||||||
|
// +build !no_x11
|
||||||
|
|
||||||
|
package gdk
|
||||||
|
|
||||||
|
// #cgo pkg-config: gdk-x11-3.0
|
||||||
|
// #include <gdk/gdk.h>
|
||||||
|
// #include <gdk/gdkx.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func WorkspaceControlSupported() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetScreenNumber is a wrapper around gdk_x11_screen_get_screen_number().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Screen) GetScreenNumber() int {
|
||||||
|
return int(C.gdk_x11_screen_get_screen_number(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNumberOfDesktops is a wrapper around gdk_x11_screen_get_number_of_desktops().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Screen) GetNumberOfDesktops() uint32 {
|
||||||
|
return uint32(C.gdk_x11_screen_get_number_of_desktops(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentDesktop is a wrapper around gdk_x11_screen_get_current_desktop().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Screen) GetCurrentDesktop() uint32 {
|
||||||
|
return uint32(C.gdk_x11_screen_get_current_desktop(v.native()))
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
// +build !linux no_x11
|
||||||
|
|
||||||
|
package gdk
|
||||||
|
|
||||||
|
func (v *Window) MoveToCurrentDesktop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDesktop is a wrapper around gdk_x11_window_get_desktop().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Window) GetDesktop() uint32 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveToDesktop is a wrapper around gdk_x11_window_move_to_desktop().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Window) MoveToDesktop(d uint32) {
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
// +build linux
|
||||||
|
// +build !no_x11
|
||||||
|
|
||||||
|
package gdk
|
||||||
|
|
||||||
|
// #cgo pkg-config: gdk-x11-3.0
|
||||||
|
// #include <gdk/gdk.h>
|
||||||
|
// #include <gdk/gdkx.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// MoveToCurrentDesktop is a wrapper around gdk_x11_window_move_to_current_desktop().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Window) MoveToCurrentDesktop() {
|
||||||
|
C.gdk_x11_window_move_to_current_desktop(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDesktop is a wrapper around gdk_x11_window_get_desktop().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Window) GetDesktop() uint32 {
|
||||||
|
return uint32(C.gdk_x11_window_get_desktop(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MoveToDesktop is a wrapper around gdk_x11_window_move_to_desktop().
|
||||||
|
// It only works on GDK versions compiled with X11 support - its return value can't be used if WorkspaceControlSupported returns false
|
||||||
|
func (v *Window) MoveToDesktop(d uint32) {
|
||||||
|
C.gdk_x11_window_move_to_desktop(v.native(), C.guint32(d))
|
||||||
|
}
|
@ -0,0 +1,216 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <gio/gio.h>
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// Application is a representation of GApplication.
|
||||||
|
type Application struct {
|
||||||
|
*Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// native() returns a pointer to the underlying GApplication.
|
||||||
|
func (v *Application) native() *C.GApplication {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return C.toGApplication(unsafe.Pointer(v.GObject))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Application) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalApplication(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapApplication(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapApplication(obj *Object) *Application {
|
||||||
|
return &Application{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicationIDIsValid is a wrapper around g_application_id_is_valid().
|
||||||
|
func ApplicationIDIsValid(id string) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(id))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return gobool(C.g_application_id_is_valid(cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicationNew is a wrapper around g_application_new().
|
||||||
|
func ApplicationNew(appID string, flags ApplicationFlags) *Application {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(appID))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
c := C.g_application_new(cstr1, C.GApplicationFlags(flags))
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapApplication(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetApplicationID is a wrapper around g_application_get_application_id().
|
||||||
|
func (v *Application) GetApplicationID() string {
|
||||||
|
c := C.g_application_get_application_id(v.native())
|
||||||
|
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetApplicationID is a wrapper around g_application_set_application_id().
|
||||||
|
func (v *Application) SetApplicationID(id string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(id))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_application_set_application_id(v.native(), cstr1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInactivityTimeout is a wrapper around g_application_get_inactivity_timeout().
|
||||||
|
func (v *Application) GetInactivityTimeout() uint {
|
||||||
|
return uint(C.g_application_get_inactivity_timeout(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetInactivityTimeout is a wrapper around g_application_set_inactivity_timeout().
|
||||||
|
func (v *Application) SetInactivityTimeout(timeout uint) {
|
||||||
|
C.g_application_set_inactivity_timeout(v.native(), C.guint(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFlags is a wrapper around g_application_get_flags().
|
||||||
|
func (v *Application) GetFlags() ApplicationFlags {
|
||||||
|
return ApplicationFlags(C.g_application_get_flags(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFlags is a wrapper around g_application_set_flags().
|
||||||
|
func (v *Application) SetFlags(flags ApplicationFlags) {
|
||||||
|
C.g_application_set_flags(v.native(), C.GApplicationFlags(flags))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only available in GLib 2.42+
|
||||||
|
// // GetResourceBasePath is a wrapper around g_application_get_resource_base_path().
|
||||||
|
// func (v *Application) GetResourceBasePath() string {
|
||||||
|
// c := C.g_application_get_resource_base_path(v.native())
|
||||||
|
|
||||||
|
// return C.GoString((*C.char)(c))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Only available in GLib 2.42+
|
||||||
|
// // SetResourceBasePath is a wrapper around g_application_set_resource_base_path().
|
||||||
|
// func (v *Application) SetResourceBasePath(bp string) {
|
||||||
|
// cstr1 := (*C.gchar)(C.CString(bp))
|
||||||
|
// defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
// C.g_application_set_resource_base_path(v.native(), cstr1)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// GetDbusObjectPath is a wrapper around g_application_get_dbus_object_path().
|
||||||
|
func (v *Application) GetDbusObjectPath() string {
|
||||||
|
c := C.g_application_get_dbus_object_path(v.native())
|
||||||
|
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIsRegistered is a wrapper around g_application_get_is_registered().
|
||||||
|
func (v *Application) GetIsRegistered() bool {
|
||||||
|
return gobool(C.g_application_get_is_registered(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIsRemote is a wrapper around g_application_get_is_remote().
|
||||||
|
func (v *Application) GetIsRemote() bool {
|
||||||
|
return gobool(C.g_application_get_is_remote(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hold is a wrapper around g_application_hold().
|
||||||
|
func (v *Application) Hold() {
|
||||||
|
C.g_application_hold(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release is a wrapper around g_application_release().
|
||||||
|
func (v *Application) Release() {
|
||||||
|
C.g_application_release(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quit is a wrapper around g_application_quit().
|
||||||
|
func (v *Application) Quit() {
|
||||||
|
C.g_application_quit(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate is a wrapper around g_application_activate().
|
||||||
|
func (v *Application) Activate() {
|
||||||
|
C.g_application_activate(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendNotification is a wrapper around g_application_send_notification().
|
||||||
|
func (v *Application) SendNotification(id string, notification *Notification) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(id))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_application_send_notification(v.native(), cstr1, notification.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithdrawNotification is a wrapper around g_application_withdraw_notification().
|
||||||
|
func (v *Application) WithdrawNotification(id string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(id))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_application_withdraw_notification(v.native(), cstr1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefault is a wrapper around g_application_set_default().
|
||||||
|
func (v *Application) SetDefault() {
|
||||||
|
C.g_application_set_default(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicationGetDefault is a wrapper around g_application_get_default().
|
||||||
|
func ApplicationGetDefault() *Application {
|
||||||
|
c := C.g_application_get_default()
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapApplication(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkBusy is a wrapper around g_application_mark_busy().
|
||||||
|
func (v *Application) MarkBusy() {
|
||||||
|
C.g_application_mark_busy(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarkBusy is a wrapper around g_application_unmark_busy().
|
||||||
|
func (v *Application) UnmarkBusy() {
|
||||||
|
C.g_application_unmark_busy(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run is a wrapper around g_application_run().
|
||||||
|
func (v *Application) Run(args []string) int {
|
||||||
|
cargs := C.make_strings(C.int(len(args)))
|
||||||
|
defer C.destroy_strings(cargs)
|
||||||
|
|
||||||
|
for i, arg := range args {
|
||||||
|
cstr := C.CString(arg)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.set_string(cargs, C.int(i), (*C.char)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
C.set_string(cargs, C.int(len(args)), nil)
|
||||||
|
|
||||||
|
return int(C.g_application_run(v.native(), C.int(len(args)), cargs))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only available in GLib 2.44+
|
||||||
|
// // GetIsBusy is a wrapper around g_application_get_is_busy().
|
||||||
|
// func (v *Application) GetIsBusy() bool {
|
||||||
|
// return gobool(C.g_application_get_is_busy(v.native()))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// void g_application_bind_busy_property ()
|
||||||
|
// void g_application_unbind_busy_property ()
|
||||||
|
// gboolean g_application_register () // requires GCancellable
|
||||||
|
// void g_application_set_action_group () // Deprecated since 2.32
|
||||||
|
// GDBusConnection * g_application_get_dbus_connection () // No support for GDBusConnection
|
||||||
|
// void g_application_open () // Needs GFile
|
||||||
|
// void g_application_add_main_option_entries () //Needs GOptionEntry
|
||||||
|
// void g_application_add_main_option () //Needs GOptionFlags and GOptionArg
|
||||||
|
// void g_application_add_option_group () // Needs GOptionGroup
|
@ -0,0 +1,117 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Events
|
||||||
|
*/
|
||||||
|
|
||||||
|
type SignalHandle uint
|
||||||
|
|
||||||
|
func (v *Object) connectClosure(after bool, detailedSignal string, f interface{}, userData ...interface{}) (SignalHandle, error) {
|
||||||
|
if len(userData) > 1 {
|
||||||
|
return 0, errors.New("userData len must be 0 or 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
cstr := C.CString(detailedSignal)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
closure, err := ClosureNew(f, userData...)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
C._g_closure_add_finalize_notifier(closure)
|
||||||
|
|
||||||
|
c := C.g_signal_connect_closure(C.gpointer(v.native()),
|
||||||
|
(*C.gchar)(cstr), closure, gbool(after))
|
||||||
|
handle := SignalHandle(c)
|
||||||
|
|
||||||
|
// Map the signal handle to the closure.
|
||||||
|
signals[handle] = closure
|
||||||
|
|
||||||
|
return handle, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect is a wrapper around g_signal_connect_closure(). f must be
|
||||||
|
// a function with a signaure matching the callback signature for
|
||||||
|
// detailedSignal. userData must either 0 or 1 elements which can
|
||||||
|
// be optionally passed to f. If f takes less arguments than it is
|
||||||
|
// passed from the GLib runtime, the extra arguments are ignored.
|
||||||
|
//
|
||||||
|
// Arguments for f must be a matching Go equivalent type for the
|
||||||
|
// C callback, or an interface type which the value may be packed in.
|
||||||
|
// If the type is not suitable, a runtime panic will occur when the
|
||||||
|
// signal is emitted.
|
||||||
|
func (v *Object) Connect(detailedSignal string, f interface{}, userData ...interface{}) (SignalHandle, error) {
|
||||||
|
return v.connectClosure(false, detailedSignal, f, userData...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectAfter is a wrapper around g_signal_connect_closure(). f must be
|
||||||
|
// a function with a signaure matching the callback signature for
|
||||||
|
// detailedSignal. userData must either 0 or 1 elements which can
|
||||||
|
// be optionally passed to f. If f takes less arguments than it is
|
||||||
|
// passed from the GLib runtime, the extra arguments are ignored.
|
||||||
|
//
|
||||||
|
// Arguments for f must be a matching Go equivalent type for the
|
||||||
|
// C callback, or an interface type which the value may be packed in.
|
||||||
|
// If the type is not suitable, a runtime panic will occur when the
|
||||||
|
// signal is emitted.
|
||||||
|
//
|
||||||
|
// The difference between Connect and ConnectAfter is that the latter
|
||||||
|
// will be invoked after the default handler, not before.
|
||||||
|
func (v *Object) ConnectAfter(detailedSignal string, f interface{}, userData ...interface{}) (SignalHandle, error) {
|
||||||
|
return v.connectClosure(true, detailedSignal, f, userData...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClosureNew creates a new GClosure and adds its callback function
|
||||||
|
// to the internally-maintained map. It's exported for visibility to other
|
||||||
|
// gotk3 packages and shouldn't be used in application code.
|
||||||
|
func ClosureNew(f interface{}, marshalData ...interface{}) (*C.GClosure, error) {
|
||||||
|
// Create a reflect.Value from f. This is called when the
|
||||||
|
// returned GClosure runs.
|
||||||
|
rf := reflect.ValueOf(f)
|
||||||
|
|
||||||
|
// Create closure context which points to the reflected func.
|
||||||
|
cc := closureContext{rf: rf}
|
||||||
|
|
||||||
|
// Closures can only be created from funcs.
|
||||||
|
if rf.Type().Kind() != reflect.Func {
|
||||||
|
return nil, errors.New("value is not a func")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(marshalData) > 0 {
|
||||||
|
cc.userData = reflect.ValueOf(marshalData[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
c := C._g_closure_new()
|
||||||
|
|
||||||
|
// Associate the GClosure with rf. rf will be looked up in this
|
||||||
|
// map by the closure when the closure runs.
|
||||||
|
closures.Lock()
|
||||||
|
closures.m[c] = cc
|
||||||
|
closures.Unlock()
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeClosure removes a closure from the internal closures map. This is
|
||||||
|
// needed to prevent a leak where Go code can access the closure context
|
||||||
|
// (along with rf and userdata) even after an object has been destroyed and
|
||||||
|
// the GClosure is invalidated and will never run.
|
||||||
|
//
|
||||||
|
//export removeClosure
|
||||||
|
func removeClosure(_ C.gpointer, closure *C.GClosure) {
|
||||||
|
closures.Lock()
|
||||||
|
delete(closures.m, closure)
|
||||||
|
closures.Unlock()
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2014 Conformal Systems <info@conformal.com>
|
||||||
|
*
|
||||||
|
* This file originated from: http://opensource.conformal.com/
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GLIB_GO_H__
|
||||||
|
#define __GLIB_GO_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#define G_SETTINGS_ENABLE_BACKEND
|
||||||
|
#include <gio/gsettingsbackend.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
#include <locale.h>
|
||||||
|
|
||||||
|
/* GObject Type Casting */
|
||||||
|
static GObject *
|
||||||
|
toGObject(void *p)
|
||||||
|
{
|
||||||
|
return (G_OBJECT(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GMenuModel *
|
||||||
|
toGMenuModel(void *p)
|
||||||
|
{
|
||||||
|
return (G_MENU_MODEL(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GMenu *
|
||||||
|
toGMenu(void *p)
|
||||||
|
{
|
||||||
|
return (G_MENU(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GMenuItem *
|
||||||
|
toGMenuItem(void *p)
|
||||||
|
{
|
||||||
|
return (G_MENU_ITEM(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GNotification *
|
||||||
|
toGNotification(void *p)
|
||||||
|
{
|
||||||
|
return (G_NOTIFICATION(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GApplication *
|
||||||
|
toGApplication(void *p)
|
||||||
|
{
|
||||||
|
return (G_APPLICATION(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSettings *
|
||||||
|
toGSettings(void *p)
|
||||||
|
{
|
||||||
|
return (G_SETTINGS(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSettingsBackend *
|
||||||
|
toGSettingsBackend(void *p)
|
||||||
|
{
|
||||||
|
return (G_SETTINGS_BACKEND(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GType
|
||||||
|
_g_type_from_instance(gpointer instance)
|
||||||
|
{
|
||||||
|
return (G_TYPE_FROM_INSTANCE(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper to avoid variable arg list */
|
||||||
|
static void
|
||||||
|
_g_object_set_one(gpointer object, const gchar *property_name, void *val)
|
||||||
|
{
|
||||||
|
g_object_set(object, property_name, *(gpointer **)val, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GValue *
|
||||||
|
alloc_gvalue_list(int n)
|
||||||
|
{
|
||||||
|
GValue *valv;
|
||||||
|
|
||||||
|
valv = g_new0(GValue, n);
|
||||||
|
return (valv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
val_list_insert(GValue *valv, int i, GValue *val)
|
||||||
|
{
|
||||||
|
valv[i] = *val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GValue
|
||||||
|
*/
|
||||||
|
|
||||||
|
static GValue *
|
||||||
|
_g_value_alloc()
|
||||||
|
{
|
||||||
|
return (g_new0(GValue, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GValue *
|
||||||
|
_g_value_init(GType g_type)
|
||||||
|
{
|
||||||
|
GValue *value;
|
||||||
|
|
||||||
|
value = g_new0(GValue, 1);
|
||||||
|
return (g_value_init(value, g_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_g_is_value(GValue *val)
|
||||||
|
{
|
||||||
|
return (G_IS_VALUE(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GType
|
||||||
|
_g_value_type(GValue *val)
|
||||||
|
{
|
||||||
|
return (G_VALUE_TYPE(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GType
|
||||||
|
_g_value_fundamental(GType type)
|
||||||
|
{
|
||||||
|
return (G_TYPE_FUNDAMENTAL(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GObjectClass *
|
||||||
|
_g_object_get_class (GObject *object)
|
||||||
|
{
|
||||||
|
return (G_OBJECT_GET_CLASS(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Closure support
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern void goMarshal(GClosure *, GValue *, guint, GValue *, gpointer, GValue *);
|
||||||
|
|
||||||
|
static GClosure *
|
||||||
|
_g_closure_new()
|
||||||
|
{
|
||||||
|
GClosure *closure;
|
||||||
|
|
||||||
|
closure = g_closure_new_simple(sizeof(GClosure), NULL);
|
||||||
|
g_closure_set_marshal(closure, (GClosureMarshal)(goMarshal));
|
||||||
|
return (closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void removeClosure(gpointer, GClosure *);
|
||||||
|
|
||||||
|
static void
|
||||||
|
_g_closure_add_finalize_notifier(GClosure *closure)
|
||||||
|
{
|
||||||
|
g_closure_add_finalize_notifier(closure, NULL, removeClosure);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline guint _g_signal_new(const gchar *name) {
|
||||||
|
return g_signal_new(name,
|
||||||
|
G_TYPE_OBJECT,
|
||||||
|
G_SIGNAL_RUN_FIRST,
|
||||||
|
0, NULL, NULL,
|
||||||
|
g_cclosure_marshal_VOID__POINTER,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
1,
|
||||||
|
G_TYPE_POINTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_i18n(const char *domain, const char *dir) {
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
bindtextdomain(domain, dir);
|
||||||
|
bind_textdomain_codeset(domain, "UTF-8");
|
||||||
|
textdomain(domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* localize(const char *string) {
|
||||||
|
return _(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char** make_strings(int count) {
|
||||||
|
return (char**)malloc(sizeof(char*) * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void destroy_strings(char** strings) {
|
||||||
|
free(strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline char* get_string(char** strings, int n) {
|
||||||
|
return strings[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_string(char** strings, int n, char* str) {
|
||||||
|
strings[n] = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline gchar** next_gcharptr(gchar** s) { return (s+1); }
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,18 @@
|
|||||||
|
//glib_extension contains definitions and functions to interface between glib/gtk/gio and go universe
|
||||||
|
|
||||||
|
package glib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Should be implemented by any class which need special conversion like
|
||||||
|
// gtk.Application -> gio.Application
|
||||||
|
type IGlibConvert interface {
|
||||||
|
// If convertion can't be done, function have to panic with a message that it can't convert to type
|
||||||
|
Convert(reflect.Type) reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
IGlibConvertType reflect.Type
|
||||||
|
)
|
@ -0,0 +1,32 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0 gio-2.0
|
||||||
|
// #include <gio/gio.h>
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type MainContext C.GMainContext
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GMainContext.
|
||||||
|
func (v *MainContext) native() *C.GMainContext {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*C.GMainContext)(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MainContextDefault is a wrapper around g_main_context_default().
|
||||||
|
func MainContextDefault() *MainContext {
|
||||||
|
c := C.g_main_context_default()
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*MainContext)(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MainDepth is a wrapper around g_main_depth().
|
||||||
|
func MainDepth() int {
|
||||||
|
return int(C.g_main_depth())
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0 gio-2.0
|
||||||
|
// #include <gio/gio.h>
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
type Source C.GSource
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GSource.
|
||||||
|
func (v *Source) native() *C.GSource {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*C.GSource)(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MainCurrentSource is a wrapper around g_main_current_source().
|
||||||
|
func MainCurrentSource() *Source {
|
||||||
|
c := C.g_main_current_source()
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*Source)(c)
|
||||||
|
}
|
@ -0,0 +1,186 @@
|
|||||||
|
//GVariant : GVariant — strongly typed value datatype
|
||||||
|
// https://developer.gnome.org/glib/2.26/glib-GVariant.html
|
||||||
|
|
||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
// #include "gvariant.go.h"
|
||||||
|
//import "C"
|
||||||
|
//import "unsafe"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GVariant
|
||||||
|
*/
|
||||||
|
|
||||||
|
// IVariant is an interface type implemented by Variant and all types which embed
|
||||||
|
// an Variant. It is meant to be used as a type for function arguments which
|
||||||
|
// require GVariants or any subclasses thereof.
|
||||||
|
/* todo fix bugs
|
||||||
|
type IVariant interface {
|
||||||
|
ToGVariant() *C.GVariant
|
||||||
|
ToVariant() *Variant
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variant is a representation of GLib's GVariant.
|
||||||
|
type Variant struct {
|
||||||
|
GVariant *C.GVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Variant) ToGVariant() *C.GVariant {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.native()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Variant) ToVariant() *Variant {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// newVariant creates a new Variant from a GVariant pointer.
|
||||||
|
func newVariant(p *C.GVariant) *Variant {
|
||||||
|
return &Variant{GVariant: p}
|
||||||
|
}
|
||||||
|
|
||||||
|
func VariantFromUnsafePointer(p unsafe.Pointer) *Variant {
|
||||||
|
return &Variant{C.toGVariant(p)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GVariant.
|
||||||
|
func (v *Variant) native() *C.GVariant {
|
||||||
|
if v == nil || v.GVariant == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(v.GVariant)
|
||||||
|
return C.toGVariant(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native returns a pointer to the underlying GVariant.
|
||||||
|
func (v *Variant) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//void g_variant_unref ()
|
||||||
|
//GVariant * g_variant_ref ()
|
||||||
|
//GVariant * g_variant_ref_sink ()
|
||||||
|
//gboolean g_variant_is_floating ()
|
||||||
|
//GVariant * g_variant_take_ref ()
|
||||||
|
//const GVariantType * g_variant_get_type ()
|
||||||
|
//const gchar * g_variant_get_type_string ()
|
||||||
|
//gboolean g_variant_is_of_type ()
|
||||||
|
//gboolean g_variant_is_container ()
|
||||||
|
//gint g_variant_compare ()
|
||||||
|
//GVariantClass g_variant_classify ()
|
||||||
|
//gboolean g_variant_check_format_string ()
|
||||||
|
//void g_variant_get ()
|
||||||
|
//void g_variant_get_va ()
|
||||||
|
//GVariant * g_variant_new ()
|
||||||
|
//GVariant * g_variant_new_va ()
|
||||||
|
//GVariant * g_variant_new_boolean ()
|
||||||
|
//GVariant * g_variant_new_byte ()
|
||||||
|
//GVariant * g_variant_new_int16 ()
|
||||||
|
//GVariant * g_variant_new_uint16 ()
|
||||||
|
//GVariant * g_variant_new_int32 ()
|
||||||
|
//GVariant * g_variant_new_uint32 ()
|
||||||
|
//GVariant * g_variant_new_int64 ()
|
||||||
|
//GVariant * g_variant_new_uint64 ()
|
||||||
|
//GVariant * g_variant_new_handle ()
|
||||||
|
//GVariant * g_variant_new_double ()
|
||||||
|
//GVariant * g_variant_new_string ()
|
||||||
|
//GVariant * g_variant_new_take_string ()
|
||||||
|
//GVariant * g_variant_new_printf ()
|
||||||
|
//GVariant * g_variant_new_object_path ()
|
||||||
|
//gboolean g_variant_is_object_path ()
|
||||||
|
//GVariant * g_variant_new_signature ()
|
||||||
|
//gboolean g_variant_is_signature ()
|
||||||
|
//GVariant * g_variant_new_variant ()
|
||||||
|
//GVariant * g_variant_new_strv ()
|
||||||
|
//GVariant * g_variant_new_objv ()
|
||||||
|
//GVariant * g_variant_new_bytestring ()
|
||||||
|
//GVariant * g_variant_new_bytestring_array ()
|
||||||
|
//gboolean g_variant_get_boolean ()
|
||||||
|
//guchar g_variant_get_byte ()
|
||||||
|
//gint16 g_variant_get_int16 ()
|
||||||
|
//guint16 g_variant_get_uint16 ()
|
||||||
|
//gint32 g_variant_get_int32 ()
|
||||||
|
//guint32 g_variant_get_uint32 ()
|
||||||
|
//gint64 g_variant_get_int64 ()
|
||||||
|
//guint64 g_variant_get_uint64 ()
|
||||||
|
//gint32 g_variant_get_handle ()
|
||||||
|
//gdouble g_variant_get_double ()
|
||||||
|
//const gchar * g_variant_get_string ()
|
||||||
|
//gchar * g_variant_dup_string ()
|
||||||
|
//GVariant * g_variant_get_variant ()
|
||||||
|
//const gchar ** g_variant_get_strv ()
|
||||||
|
//gchar ** g_variant_dup_strv ()
|
||||||
|
//const gchar ** g_variant_get_objv ()
|
||||||
|
//gchar ** g_variant_dup_objv ()
|
||||||
|
//const gchar * g_variant_get_bytestring ()
|
||||||
|
//gchar * g_variant_dup_bytestring ()
|
||||||
|
//const gchar ** g_variant_get_bytestring_array ()
|
||||||
|
//gchar ** g_variant_dup_bytestring_array ()
|
||||||
|
//GVariant * g_variant_new_maybe ()
|
||||||
|
//GVariant * g_variant_new_array ()
|
||||||
|
//GVariant * g_variant_new_tuple ()
|
||||||
|
//GVariant * g_variant_new_dict_entry ()
|
||||||
|
//GVariant * g_variant_new_fixed_array ()
|
||||||
|
//GVariant * g_variant_get_maybe ()
|
||||||
|
//gsize g_variant_n_children ()
|
||||||
|
//GVariant * g_variant_get_child_value ()
|
||||||
|
//void g_variant_get_child ()
|
||||||
|
//GVariant * g_variant_lookup_value ()
|
||||||
|
//gboolean g_variant_lookup ()
|
||||||
|
//gconstpointer g_variant_get_fixed_array ()
|
||||||
|
//gsize g_variant_get_size ()
|
||||||
|
//gconstpointer g_variant_get_data ()
|
||||||
|
//GBytes * g_variant_get_data_as_bytes ()
|
||||||
|
//void g_variant_store ()
|
||||||
|
//GVariant * g_variant_new_from_data ()
|
||||||
|
//GVariant * g_variant_new_from_bytes ()
|
||||||
|
//GVariant * g_variant_byteswap ()
|
||||||
|
//GVariant * g_variant_get_normal_form ()
|
||||||
|
//gboolean g_variant_is_normal_form ()
|
||||||
|
//guint g_variant_hash ()
|
||||||
|
//gboolean g_variant_equal ()
|
||||||
|
//gchar * g_variant_print ()
|
||||||
|
//GString * g_variant_print_string ()
|
||||||
|
//GVariantIter * g_variant_iter_copy ()
|
||||||
|
//void g_variant_iter_free ()
|
||||||
|
//gsize g_variant_iter_init ()
|
||||||
|
//gsize g_variant_iter_n_children ()
|
||||||
|
//GVariantIter * g_variant_iter_new ()
|
||||||
|
//GVariant * g_variant_iter_next_value ()
|
||||||
|
//gboolean g_variant_iter_next ()
|
||||||
|
//gboolean g_variant_iter_loop ()
|
||||||
|
//void g_variant_builder_unref ()
|
||||||
|
//GVariantBuilder * g_variant_builder_ref ()
|
||||||
|
//GVariantBuilder * g_variant_builder_new ()
|
||||||
|
//void g_variant_builder_init ()
|
||||||
|
//void g_variant_builder_clear ()
|
||||||
|
//void g_variant_builder_add_value ()
|
||||||
|
//void g_variant_builder_add ()
|
||||||
|
//void g_variant_builder_add_parsed ()
|
||||||
|
//GVariant * g_variant_builder_end ()
|
||||||
|
//void g_variant_builder_open ()
|
||||||
|
//void g_variant_builder_close ()
|
||||||
|
//void g_variant_dict_unref ()
|
||||||
|
//GVariantDict * g_variant_dict_ref ()
|
||||||
|
//GVariantDict * g_variant_dict_new ()
|
||||||
|
//void g_variant_dict_init ()
|
||||||
|
//void g_variant_dict_clear ()
|
||||||
|
//gboolean g_variant_dict_contains ()
|
||||||
|
//gboolean g_variant_dict_lookup ()
|
||||||
|
//GVariant * g_variant_dict_lookup_value ()
|
||||||
|
//void g_variant_dict_insert ()
|
||||||
|
//void g_variant_dict_insert_value ()
|
||||||
|
//gboolean g_variant_dict_remove ()
|
||||||
|
//GVariant * g_variant_dict_end ()
|
||||||
|
//#define G_VARIANT_PARSE_ERROR
|
||||||
|
//GVariant * g_variant_parse ()
|
||||||
|
//GVariant * g_variant_new_parsed_va ()
|
||||||
|
//GVariant * g_variant_new_parsed ()
|
||||||
|
//gchar * g_variant_parse_error_print_context ()
|
@ -0,0 +1,41 @@
|
|||||||
|
// Same copyright and license as the rest of the files in this project
|
||||||
|
|
||||||
|
//GVariant : GVariant — strongly typed value datatype
|
||||||
|
// https://developer.gnome.org/glib/2.26/glib-GVariant.html
|
||||||
|
|
||||||
|
/* todo fix bugs
|
||||||
|
#ifndef __GVARIANT_GO_H__
|
||||||
|
#define __GVARIANT_GO_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <glib/gvariant.h>
|
||||||
|
|
||||||
|
// Type Casting
|
||||||
|
static GVariant *
|
||||||
|
toGVariant(void *p)
|
||||||
|
{
|
||||||
|
return (_GVariant(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariantBuilder *
|
||||||
|
toGVariantBuilder(void *p)
|
||||||
|
{
|
||||||
|
return (GVariantBuilder(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariantDict *
|
||||||
|
toGVariantDict(void *p)
|
||||||
|
{
|
||||||
|
return (_GVariantDict(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariantIter *
|
||||||
|
toGVariantIter(void *p)
|
||||||
|
{
|
||||||
|
return (_GVariantIter(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
*/
|
@ -0,0 +1,54 @@
|
|||||||
|
// Same copyright and license as the rest of the files in this project
|
||||||
|
|
||||||
|
// GVariant : GVariant — strongly typed value datatype
|
||||||
|
// https://developer.gnome.org/glib/2.26/glib-GVariant.html
|
||||||
|
|
||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
// #include "gvariant.go.h"
|
||||||
|
//import "C"
|
||||||
|
//import "unsafe"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GVariantBuilder
|
||||||
|
*/
|
||||||
|
/* todo fix bugs
|
||||||
|
// VariantBuilder is a representation of GLib's VariantBuilder.
|
||||||
|
type VariantBuilder struct {
|
||||||
|
GVariantBuilder *C.GVariantBuilder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VariantBuilder) toGVariantBuilder() *C.GVariantBuilder {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.native()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VariantBuilder) toVariantBuilder() *VariantBuilder {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// newVariantBuilder creates a new VariantBuilder from a GVariantBuilder pointer.
|
||||||
|
func newVariantBuilder(p *C.GVariantBuilder) *VariantBuilder {
|
||||||
|
return &VariantBuilder{GVariantBuilder: p}
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GVariantBuilder.
|
||||||
|
func (v *VariantBuilder) native() *C.GVariantBuilder {
|
||||||
|
if v == nil || v.GVariantBuilder == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(v.GVariantBuilder)
|
||||||
|
return C.toGVariantBuilder(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native returns a pointer to the underlying GVariantBuilder.
|
||||||
|
func (v *VariantBuilder) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,39 @@
|
|||||||
|
// Same copyright and license as the rest of the files in this project
|
||||||
|
|
||||||
|
//GVariant : GVariant — strongly typed value datatype
|
||||||
|
// https://developer.gnome.org/glib/2.26/glib-GVariant.html
|
||||||
|
|
||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GVariantClass
|
||||||
|
*/
|
||||||
|
|
||||||
|
type VariantClass int
|
||||||
|
|
||||||
|
const (
|
||||||
|
VARIANT_CLASS_BOOLEAN VariantClass = C.G_VARIANT_CLASS_BOOLEAN //The GVariant is a boolean.
|
||||||
|
VARIANT_CLASS_BYTE VariantClass = C.G_VARIANT_CLASS_BYTE //The GVariant is a byte.
|
||||||
|
VARIANT_CLASS_INT16 VariantClass = C.G_VARIANT_CLASS_INT16 //The GVariant is a signed 16 bit integer.
|
||||||
|
VARIANT_CLASS_UINT16 VariantClass = C.G_VARIANT_CLASS_UINT16 //The GVariant is an unsigned 16 bit integer.
|
||||||
|
VARIANT_CLASS_INT32 VariantClass = C.G_VARIANT_CLASS_INT32 //The GVariant is a signed 32 bit integer.
|
||||||
|
VARIANT_CLASS_UINT32 VariantClass = C.G_VARIANT_CLASS_UINT32 //The GVariant is an unsigned 32 bit integer.
|
||||||
|
VARIANT_CLASS_INT64 VariantClass = C.G_VARIANT_CLASS_INT64 //The GVariant is a signed 64 bit integer.
|
||||||
|
VARIANT_CLASS_UINT64 VariantClass = C.G_VARIANT_CLASS_UINT64 //The GVariant is an unsigned 64 bit integer.
|
||||||
|
VARIANT_CLASS_HANDLE VariantClass = C.G_VARIANT_CLASS_HANDLE //The GVariant is a file handle index.
|
||||||
|
VARIANT_CLASS_DOUBLE VariantClass = C.G_VARIANT_CLASS_DOUBLE //The GVariant is a double precision floating point value.
|
||||||
|
VARIANT_CLASS_STRING VariantClass = C.G_VARIANT_CLASS_STRING //The GVariant is a normal string.
|
||||||
|
VARIANT_CLASS_OBJECT_PATH VariantClass = C.G_VARIANT_CLASS_OBJECT_PATH //The GVariant is a D-Bus object path string.
|
||||||
|
VARIANT_CLASS_SIGNATURE VariantClass = C.G_VARIANT_CLASS_SIGNATURE //The GVariant is a D-Bus signature string.
|
||||||
|
VARIANT_CLASS_VARIANT VariantClass = C.G_VARIANT_CLASS_VARIANT //The GVariant is a variant.
|
||||||
|
VARIANT_CLASS_MAYBE VariantClass = C.G_VARIANT_CLASS_MAYBE //The GVariant is a maybe-typed value.
|
||||||
|
VARIANT_CLASS_ARRAY VariantClass = C.G_VARIANT_CLASS_ARRAY //The GVariant is an array.
|
||||||
|
VARIANT_CLASS_TUPLE VariantClass = C.G_VARIANT_CLASS_TUPLE //The GVariant is a tuple.
|
||||||
|
VARIANT_CLASS_DICT_ENTRY VariantClass = C.G_VARIANT_CLASS_DICT_ENTRY //The GVariant is a dictionary entry.
|
||||||
|
)
|
@ -0,0 +1,54 @@
|
|||||||
|
// Same copyright and license as the rest of the files in this project
|
||||||
|
|
||||||
|
//GVariant : GVariant — strongly typed value datatype
|
||||||
|
// https://developer.gnome.org/glib/2.26/glib-GVariant.html
|
||||||
|
|
||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
// #include "gvariant.go.h"
|
||||||
|
//import "C"
|
||||||
|
//import "unsafe"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GVariantDict
|
||||||
|
*/
|
||||||
|
/* todo fix bugs
|
||||||
|
// VariantDict is a representation of GLib's VariantDict.
|
||||||
|
type VariantDict struct {
|
||||||
|
GVariantDict *C.GVariantDict
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VariantDict) toGVariantDict() *C.GVariantDict {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.native()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VariantDict) toVariantDict() *VariantDict {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// newVariantDict creates a new VariantDict from a GVariantDict pointer.
|
||||||
|
func newVariantDict(p *C.GVariantDict) *VariantDict {
|
||||||
|
return &VariantDict{GVariantDict: p}
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GVariantDict.
|
||||||
|
func (v *VariantDict) native() *C.GVariantDict {
|
||||||
|
if v == nil || v.GVariantDict == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(v.GVariantDict)
|
||||||
|
return C.toGVariantDict(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native returns a pointer to the underlying GVariantDict.
|
||||||
|
func (v *VariantDict) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,54 @@
|
|||||||
|
// Same copyright and license as the rest of the files in this project
|
||||||
|
|
||||||
|
//GVariant : GVariant — strongly typed value datatype
|
||||||
|
// https://developer.gnome.org/glib/2.26/glib-GVariant.html
|
||||||
|
|
||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
// #include "gvariant.go.h"
|
||||||
|
//import "C"
|
||||||
|
//import "unsafe"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GVariantIter
|
||||||
|
*/
|
||||||
|
/* todo fix bugs
|
||||||
|
// VariantIter is a representation of GLib's GVariantIter.
|
||||||
|
type VariantIter struct {
|
||||||
|
GVariantIter *C.GVariantIter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VariantIter) toGVariantIter() *C.GVariantIter {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.native()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VariantIter) toVariantIter() *VariantIter {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// newVariantIter creates a new VariantIter from a GVariantIter pointer.
|
||||||
|
func newVariantIter(p *C.GVariantIter) *VariantIter {
|
||||||
|
return &VariantIter{GVariantIter: p}
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GVariantIter.
|
||||||
|
func (v *VariantIter) native() *C.GVariantIter {
|
||||||
|
if v == nil || v.GVariantIter == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(v.GVariantIter)
|
||||||
|
return C.toGVariantIter(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native returns a pointer to the underlying GVariantIter.
|
||||||
|
func (v *VariantIter) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,156 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Linked Lists
|
||||||
|
*/
|
||||||
|
|
||||||
|
// List is a representation of Glib's GList.
|
||||||
|
type List struct {
|
||||||
|
list *C.struct__GList
|
||||||
|
// If set, dataWrap is called every time NthDataWrapped()
|
||||||
|
// or DataWrapped() is called to wrap raw underlying
|
||||||
|
// value into appropriate type.
|
||||||
|
dataWrap func(unsafe.Pointer) interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapList(obj uintptr) *List {
|
||||||
|
return wrapList((*C.struct__GList)(unsafe.Pointer(obj)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapList(obj *C.struct__GList) *List {
|
||||||
|
if obj == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &List{list: obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *List) wrapNewHead(obj *C.struct__GList) *List {
|
||||||
|
if obj == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &List{
|
||||||
|
list: obj,
|
||||||
|
dataWrap: v.dataWrap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *List) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.list))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *List) native() *C.struct__GList {
|
||||||
|
if v == nil || v.list == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.list
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataWapper sets wrap functions, which is called during NthDataWrapped()
|
||||||
|
// and DataWrapped(). It's used to cast raw C data into appropriate
|
||||||
|
// Go structures and types every time that data is retreived.
|
||||||
|
func (v *List) DataWrapper(fn func(unsafe.Pointer) interface{}) {
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v.dataWrap = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append is a wrapper around g_list_append().
|
||||||
|
func (v *List) Append(data uintptr) *List {
|
||||||
|
glist := C.g_list_append(v.native(), C.gpointer(data))
|
||||||
|
return v.wrapNewHead(glist)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepend is a wrapper around g_list_prepend().
|
||||||
|
func (v *List) Prepend(data uintptr) *List {
|
||||||
|
glist := C.g_list_prepend(v.native(), C.gpointer(data))
|
||||||
|
return v.wrapNewHead(glist)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert is a wrapper around g_list_insert().
|
||||||
|
func (v *List) Insert(data uintptr, position int) *List {
|
||||||
|
glist := C.g_list_insert(v.native(), C.gpointer(data), C.gint(position))
|
||||||
|
return v.wrapNewHead(glist)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Length is a wrapper around g_list_length().
|
||||||
|
func (v *List) Length() uint {
|
||||||
|
return uint(C.g_list_length(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// nthDataRaw is a wrapper around g_list_nth_data().
|
||||||
|
func (v *List) nthDataRaw(n uint) unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(C.g_list_nth_data(v.native(), C.guint(n)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nth() is a wrapper around g_list_nth().
|
||||||
|
func (v *List) Nth(n uint) *List {
|
||||||
|
list := wrapList(C.g_list_nth(v.native(), C.guint(n)))
|
||||||
|
list.DataWrapper(v.dataWrap)
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// NthDataWrapped acts the same as g_list_nth_data(), but passes
|
||||||
|
// retrieved value before returning through wrap function, set by DataWrapper().
|
||||||
|
// If no wrap function is set, it returns raw unsafe.Pointer.
|
||||||
|
func (v *List) NthData(n uint) interface{} {
|
||||||
|
ptr := v.nthDataRaw(n)
|
||||||
|
if v.dataWrap != nil {
|
||||||
|
return v.dataWrap(ptr)
|
||||||
|
}
|
||||||
|
return ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free is a wrapper around g_list_free().
|
||||||
|
func (v *List) Free() {
|
||||||
|
C.g_list_free(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next is a wrapper around the next struct field
|
||||||
|
func (v *List) Next() *List {
|
||||||
|
return v.wrapNewHead(v.native().next)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous is a wrapper around the prev struct field
|
||||||
|
func (v *List) Previous() *List {
|
||||||
|
return v.wrapNewHead(v.native().prev)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dataRaw is a wrapper around the data struct field
|
||||||
|
func (v *List) dataRaw() unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(v.native().data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataWrapped acts the same as data struct field, but passes
|
||||||
|
// retrieved value before returning through wrap function, set by DataWrapper().
|
||||||
|
// If no wrap function is set, it returns raw unsafe.Pointer.
|
||||||
|
func (v *List) Data() interface{} {
|
||||||
|
ptr := v.dataRaw()
|
||||||
|
if v.dataWrap != nil {
|
||||||
|
return v.dataWrap(ptr)
|
||||||
|
}
|
||||||
|
return ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Foreach acts the same as g_list_foreach().
|
||||||
|
// No user_data arguement is implemented because of Go clojure capabilities.
|
||||||
|
func (v *List) Foreach(fn func(item interface{})) {
|
||||||
|
for l := v; l != nil; l = l.Next() {
|
||||||
|
fn(l.Data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FreeFull acts the same as g_list_free_full().
|
||||||
|
// Calling list.FreeFull(fn) is equivalent to calling list.Foreach(fn) and
|
||||||
|
// list.Free() sequentially.
|
||||||
|
func (v *List) FreeFull(fn func(item interface{})) {
|
||||||
|
v.Foreach(fn)
|
||||||
|
v.Free()
|
||||||
|
}
|
@ -0,0 +1,333 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <gio/gio.h>
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// MenuModel is a representation of GMenuModel.
|
||||||
|
type MenuModel struct {
|
||||||
|
*Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// native() returns a pointer to the underlying GMenuModel.
|
||||||
|
func (v *MenuModel) native() *C.GMenuModel {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return C.toGMenuModel(unsafe.Pointer(v.GObject))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *MenuModel) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalMenuModel(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapMenuModel(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapMenuModel(obj *Object) *MenuModel {
|
||||||
|
return &MenuModel{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMutable is a wrapper around g_menu_model_is_mutable().
|
||||||
|
func (v *MenuModel) IsMutable() bool {
|
||||||
|
return gobool(C.g_menu_model_is_mutable(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNItems is a wrapper around g_menu_model_get_n_items().
|
||||||
|
func (v *MenuModel) GetNItems() int {
|
||||||
|
return int(C.g_menu_model_get_n_items(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetItemLink is a wrapper around g_menu_model_get_item_link().
|
||||||
|
func (v *MenuModel) GetItemLink(index int, link string) *MenuModel {
|
||||||
|
cstr := (*C.gchar)(C.CString(link))
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
c := C.g_menu_model_get_item_link(v.native(), C.gint(index), cstr)
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapMenuModel(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ItemsChanged is a wrapper around g_menu_model_items_changed().
|
||||||
|
func (v *MenuModel) ItemsChanged(position, removed, added int) {
|
||||||
|
C.g_menu_model_items_changed(v.native(), C.gint(position), C.gint(removed), C.gint(added))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GVariant * g_menu_model_get_item_attribute_value ()
|
||||||
|
// gboolean g_menu_model_get_item_attribute ()
|
||||||
|
// GMenuAttributeIter * g_menu_model_iterate_item_attributes ()
|
||||||
|
// GMenuLinkIter * g_menu_model_iterate_item_links ()
|
||||||
|
|
||||||
|
// Menu is a representation of GMenu.
|
||||||
|
type Menu struct {
|
||||||
|
MenuModel
|
||||||
|
}
|
||||||
|
|
||||||
|
// native() returns a pointer to the underlying GMenu.
|
||||||
|
func (m *Menu) native() *C.GMenu {
|
||||||
|
if m == nil || m.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(m.GObject)
|
||||||
|
return C.toGMenu(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalMenu(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapMenu(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapMenu(obj *Object) *Menu {
|
||||||
|
return &Menu{MenuModel{obj}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuNew is a wrapper around g_menu_new().
|
||||||
|
func MenuNew() *Menu {
|
||||||
|
c := C.g_menu_new()
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapMenu(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Freeze is a wrapper around g_menu_freeze().
|
||||||
|
func (v *Menu) Freeze() {
|
||||||
|
C.g_menu_freeze(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert is a wrapper around g_menu_insert().
|
||||||
|
func (v *Menu) Insert(position int, label, detailed_action string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
cstr2 := (*C.gchar)(C.CString(detailed_action))
|
||||||
|
defer C.free(unsafe.Pointer(cstr2))
|
||||||
|
|
||||||
|
C.g_menu_insert(v.native(), C.gint(position), cstr1, cstr2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepend is a wrapper around g_menu_prepend().
|
||||||
|
func (v *Menu) Prepend(label, detailed_action string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
cstr2 := (*C.gchar)(C.CString(detailed_action))
|
||||||
|
defer C.free(unsafe.Pointer(cstr2))
|
||||||
|
|
||||||
|
C.g_menu_prepend(v.native(), cstr1, cstr2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append is a wrapper around g_menu_append().
|
||||||
|
func (v *Menu) Append(label, detailed_action string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
cstr2 := (*C.gchar)(C.CString(detailed_action))
|
||||||
|
defer C.free(unsafe.Pointer(cstr2))
|
||||||
|
|
||||||
|
C.g_menu_append(v.native(), cstr1, cstr2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertItem is a wrapper around g_menu_insert_item().
|
||||||
|
func (v *Menu) InsertItem(position int, item *MenuItem) {
|
||||||
|
C.g_menu_insert_item(v.native(), C.gint(position), item.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendItem is a wrapper around g_menu_append_item().
|
||||||
|
func (v *Menu) AppendItem(item *MenuItem) {
|
||||||
|
C.g_menu_append_item(v.native(), item.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrependItem is a wrapper around g_menu_prepend_item().
|
||||||
|
func (v *Menu) PrependItem(item *MenuItem) {
|
||||||
|
C.g_menu_prepend_item(v.native(), item.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertSection is a wrapper around g_menu_insert_section().
|
||||||
|
func (v *Menu) InsertSection(position int, label string, section *MenuModel) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_menu_insert_section(v.native(), C.gint(position), cstr1, section.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrependSection is a wrapper around g_menu_prepend_section().
|
||||||
|
func (v *Menu) PrependSection(label string, section *MenuModel) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_menu_prepend_section(v.native(), cstr1, section.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendSection is a wrapper around g_menu_append_section().
|
||||||
|
func (v *Menu) AppendSection(label string, section *MenuModel) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_menu_append_section(v.native(), cstr1, section.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertSubmenu is a wrapper around g_menu_insert_submenu().
|
||||||
|
func (v *Menu) InsertSubmenu(position int, label string, submenu *MenuModel) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_menu_insert_submenu(v.native(), C.gint(position), cstr1, submenu.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrependSubmenu is a wrapper around g_menu_prepend_submenu().
|
||||||
|
func (v *Menu) PrependSubmenu(label string, submenu *MenuModel) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_menu_prepend_submenu(v.native(), cstr1, submenu.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendSubmenu is a wrapper around g_menu_append_submenu().
|
||||||
|
func (v *Menu) AppendSubmenu(label string, submenu *MenuModel) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_menu_append_submenu(v.native(), cstr1, submenu.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove is a wrapper around g_menu_remove().
|
||||||
|
func (v *Menu) Remove(position int) {
|
||||||
|
C.g_menu_remove(v.native(), C.gint(position))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAll is a wrapper around g_menu_remove_all().
|
||||||
|
func (v *Menu) RemoveAll() {
|
||||||
|
C.g_menu_remove_all(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuItem is a representation of GMenuItem.
|
||||||
|
type MenuItem struct {
|
||||||
|
*Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// native() returns a pointer to the underlying GMenuItem.
|
||||||
|
func (m *MenuItem) native() *C.GMenuItem {
|
||||||
|
if m == nil || m.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(m.GObject)
|
||||||
|
return C.toGMenuItem(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalMenuItem(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapMenuItem(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapMenuItem(obj *Object) *MenuItem {
|
||||||
|
return &MenuItem{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuItemNew is a wrapper around g_menu_item_new().
|
||||||
|
func MenuItemNew(label, detailed_action string) *MenuItem {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
cstr2 := (*C.gchar)(C.CString(detailed_action))
|
||||||
|
defer C.free(unsafe.Pointer(cstr2))
|
||||||
|
|
||||||
|
c := C.g_menu_item_new(cstr1, cstr2)
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapMenuItem(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuItemNewSection is a wrapper around g_menu_item_new_section().
|
||||||
|
func MenuItemNewSection(label string, section *MenuModel) *MenuItem {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
c := C.g_menu_item_new_section(cstr1, section.native())
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapMenuItem(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuItemNewSubmenu is a wrapper around g_menu_item_new_submenu().
|
||||||
|
func MenuItemNewSubmenu(label string, submenu *MenuModel) *MenuItem {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
c := C.g_menu_item_new_submenu(cstr1, submenu.native())
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapMenuItem(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuItemNewFromModel is a wrapper around g_menu_item_new_from_model().
|
||||||
|
func MenuItemNewFromModel(model *MenuModel, index int) *MenuItem {
|
||||||
|
c := C.g_menu_item_new_from_model(model.native(), C.gint(index))
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapMenuItem(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//SetLabel is a wrapper around g_menu_item_set_label().
|
||||||
|
func (v *MenuItem) SetLabel(label string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_menu_item_set_label(v.native(), cstr1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//SetDetailedAction is a wrapper around g_menu_item_set_detailed_action().
|
||||||
|
func (v *MenuItem) SetDetailedAction(act string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(act))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_menu_item_set_detailed_action(v.native(), cstr1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//SetSection is a wrapper around g_menu_item_set_section().
|
||||||
|
func (v *MenuItem) SetSection(section *MenuModel) {
|
||||||
|
C.g_menu_item_set_section(v.native(), section.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
//SetSubmenu is a wrapper around g_menu_item_set_submenu().
|
||||||
|
func (v *MenuItem) SetSubmenu(submenu *MenuModel) {
|
||||||
|
C.g_menu_item_set_submenu(v.native(), submenu.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
//GetLink is a wrapper around g_menu_item_get_link().
|
||||||
|
func (v *MenuItem) GetLink(link string) *MenuModel {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(link))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
c := C.g_menu_item_get_link(v.native(), cstr1)
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapMenuModel(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
//SetLink is a wrapper around g_menu_item_Set_link().
|
||||||
|
func (v *MenuItem) SetLink(link string, model *MenuModel) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(link))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_menu_item_set_link(v.native(), cstr1, model.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// void g_menu_item_set_action_and_target_value ()
|
||||||
|
// void g_menu_item_set_action_and_target ()
|
||||||
|
// GVariant * g_menu_item_get_attribute_value ()
|
||||||
|
// gboolean g_menu_item_get_attribute ()
|
||||||
|
// void g_menu_item_set_attribute_value ()
|
||||||
|
// void g_menu_item_set_attribute ()
|
@ -0,0 +1,106 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <gio/gio.h>
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// Only available from 2.42
|
||||||
|
// // NotificationPriority is a representation of GLib's GNotificationPriority.
|
||||||
|
// type NotificationPriority int
|
||||||
|
|
||||||
|
// const (
|
||||||
|
// NOTIFICATION_PRIORITY_NORMAL NotificationPriority = C.G_NOTIFICATION_PRIORITY_NORMAL
|
||||||
|
// NOTIFICATION_PRIORITY_LOW NotificationPriority = C.G_NOTIFICATION_PRIORITY_LOW
|
||||||
|
// NOTIFICATION_PRIORITY_HIGH NotificationPriority = C.G_NOTIFICATION_PRIORITY_HIGH
|
||||||
|
// NOTIFICATION_PRIORITY_URGENT NotificationPriority = C.G_NOTIFICATION_PRIORITY_URGENT
|
||||||
|
// )
|
||||||
|
|
||||||
|
// Notification is a representation of GNotification.
|
||||||
|
type Notification struct {
|
||||||
|
*Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// native() returns a pointer to the underlying GNotification.
|
||||||
|
func (v *Notification) native() *C.GNotification {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return C.toGNotification(unsafe.Pointer(v.GObject))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Notification) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalNotification(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapNotification(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapNotification(obj *Object) *Notification {
|
||||||
|
return &Notification{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationNew is a wrapper around g_notification_new().
|
||||||
|
func NotificationNew(title string) *Notification {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(title))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
c := C.g_notification_new(cstr1)
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapNotification(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTitle is a wrapper around g_notification_set_title().
|
||||||
|
func (v *Notification) SetTitle(title string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(title))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_notification_set_title(v.native(), cstr1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBody is a wrapper around g_notification_set_body().
|
||||||
|
func (v *Notification) SetBody(body string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(body))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_notification_set_body(v.native(), cstr1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only available from 2.42
|
||||||
|
// // SetPriority is a wrapper around g_notification_set_priority().
|
||||||
|
// func (v *Notification) SetPriority(prio NotificationPriority) {
|
||||||
|
// C.g_notification_set_priority(v.native(), C.GNotificationPriority(prio))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// SetDefaultAction is a wrapper around g_notification_set_default_action().
|
||||||
|
func (v *Notification) SetDefaultAction(detailedAction string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(detailedAction))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_notification_set_default_action(v.native(), cstr1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddButton is a wrapper around g_notification_add_button().
|
||||||
|
func (v *Notification) AddButton(label, detailedAction string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(label))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
cstr2 := (*C.gchar)(C.CString(detailedAction))
|
||||||
|
defer C.free(unsafe.Pointer(cstr2))
|
||||||
|
|
||||||
|
C.g_notification_add_button(v.native(), cstr1, cstr2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// void g_notification_set_default_action_and_target () // requires varargs
|
||||||
|
// void g_notification_set_default_action_and_target_value () // requires variant
|
||||||
|
// void g_notification_add_button_with_target () // requires varargs
|
||||||
|
// void g_notification_add_button_with_target_value () //requires variant
|
||||||
|
// void g_notification_set_urgent () // Deprecated, so not implemented
|
||||||
|
// void g_notification_set_icon () // Requires support for GIcon, which we don't have yet.
|
@ -0,0 +1,277 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <gio/gio.h>
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// Settings is a representation of GSettings.
|
||||||
|
type Settings struct {
|
||||||
|
*Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// native() returns a pointer to the underlying GSettings.
|
||||||
|
func (v *Settings) native() *C.GSettings {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return C.toGSettings(unsafe.Pointer(v.GObject))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Settings) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalSettings(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapSettings(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapSettings(obj *Object) *Settings {
|
||||||
|
return &Settings{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapFullSettings(obj *C.GSettings) *Settings {
|
||||||
|
if obj == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapSettings(wrapObject(unsafe.Pointer(obj)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsNew is a wrapper around g_settings_new().
|
||||||
|
func SettingsNew(schemaID string) *Settings {
|
||||||
|
cstr := (*C.gchar)(C.CString(schemaID))
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
return wrapFullSettings(C.g_settings_new(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsNewWithPath is a wrapper around g_settings_new_with_path().
|
||||||
|
func SettingsNewWithPath(schemaID, path string) *Settings {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(schemaID))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
cstr2 := (*C.gchar)(C.CString(path))
|
||||||
|
defer C.free(unsafe.Pointer(cstr2))
|
||||||
|
|
||||||
|
return wrapFullSettings(C.g_settings_new_with_path(cstr1, cstr2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsNewWithBackend is a wrapper around g_settings_new_with_backend().
|
||||||
|
func SettingsNewWithBackend(schemaID string, backend *SettingsBackend) *Settings {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(schemaID))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return wrapFullSettings(C.g_settings_new_with_backend(cstr1, backend.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsNewWithBackendAndPath is a wrapper around g_settings_new_with_backend_and_path().
|
||||||
|
func SettingsNewWithBackendAndPath(schemaID string, backend *SettingsBackend, path string) *Settings {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(schemaID))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
cstr2 := (*C.gchar)(C.CString(path))
|
||||||
|
defer C.free(unsafe.Pointer(cstr2))
|
||||||
|
|
||||||
|
return wrapFullSettings(C.g_settings_new_with_backend_and_path(cstr1, backend.native(), cstr2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsNewFull is a wrapper around g_settings_new_full().
|
||||||
|
func SettingsNewFull(schema *SettingsSchema, backend *SettingsBackend, path string) *Settings {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(path))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return wrapFullSettings(C.g_settings_new_full(schema.native(), backend.native(), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsSync is a wrapper around g_settings_sync().
|
||||||
|
func SettingsSync() {
|
||||||
|
C.g_settings_sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWritable is a wrapper around g_settings_is_writable().
|
||||||
|
func (v *Settings) IsWritable(name string) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_is_writable(v.native(), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay is a wrapper around g_settings_delay().
|
||||||
|
func (v *Settings) Delay() {
|
||||||
|
C.g_settings_delay(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply is a wrapper around g_settings_apply().
|
||||||
|
func (v *Settings) Apply() {
|
||||||
|
C.g_settings_apply(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revert is a wrapper around g_settings_revert().
|
||||||
|
func (v *Settings) Revert() {
|
||||||
|
C.g_settings_revert(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHasUnapplied is a wrapper around g_settings_get_has_unapplied().
|
||||||
|
func (v *Settings) GetHasUnapplied() bool {
|
||||||
|
return gobool(C.g_settings_get_has_unapplied(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChild is a wrapper around g_settings_get_child().
|
||||||
|
func (v *Settings) GetChild(name string) *Settings {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return wrapFullSettings(C.g_settings_get_child(v.native(), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset is a wrapper around g_settings_reset().
|
||||||
|
func (v *Settings) Reset(name string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
C.g_settings_reset(v.native(), cstr1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListChildren is a wrapper around g_settings_list_children().
|
||||||
|
func (v *Settings) ListChildren() []string {
|
||||||
|
return toGoStringArray(C.g_settings_list_children(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBoolean is a wrapper around g_settings_get_boolean().
|
||||||
|
func (v *Settings) GetBoolean(name string) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_get_boolean(v.native(), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBoolean is a wrapper around g_settings_set_boolean().
|
||||||
|
func (v *Settings) SetBoolean(name string, value bool) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_set_boolean(v.native(), cstr1, gbool(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInt is a wrapper around g_settings_get_int().
|
||||||
|
func (v *Settings) GetInt(name string) int {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return int(C.g_settings_get_int(v.native(), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetInt is a wrapper around g_settings_set_int().
|
||||||
|
func (v *Settings) SetInt(name string, value int) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_set_int(v.native(), cstr1, C.gint(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUInt is a wrapper around g_settings_get_uint().
|
||||||
|
func (v *Settings) GetUInt(name string) uint {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return uint(C.g_settings_get_uint(v.native(), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUInt is a wrapper around g_settings_set_uint().
|
||||||
|
func (v *Settings) SetUInt(name string, value uint) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_set_uint(v.native(), cstr1, C.guint(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDouble is a wrapper around g_settings_get_double().
|
||||||
|
func (v *Settings) GetDouble(name string) float64 {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return float64(C.g_settings_get_double(v.native(), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDouble is a wrapper around g_settings_set_double().
|
||||||
|
func (v *Settings) SetDouble(name string, value float64) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_set_double(v.native(), cstr1, C.gdouble(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetString is a wrapper around g_settings_get_string().
|
||||||
|
func (v *Settings) GetString(name string) string {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return C.GoString((*C.char)(C.g_settings_get_string(v.native(), cstr1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetString is a wrapper around g_settings_set_string().
|
||||||
|
func (v *Settings) SetString(name string, value string) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
cstr2 := (*C.gchar)(C.CString(value))
|
||||||
|
defer C.free(unsafe.Pointer(cstr2))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_set_string(v.native(), cstr1, cstr2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEnum is a wrapper around g_settings_get_enum().
|
||||||
|
func (v *Settings) GetEnum(name string) int {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return int(C.g_settings_get_enum(v.native(), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEnum is a wrapper around g_settings_set_enum().
|
||||||
|
func (v *Settings) SetEnum(name string, value int) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_set_enum(v.native(), cstr1, C.gint(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFlags is a wrapper around g_settings_get_flags().
|
||||||
|
func (v *Settings) GetFlags(name string) uint {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return uint(C.g_settings_get_flags(v.native(), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFlags is a wrapper around g_settings_set_flags().
|
||||||
|
func (v *Settings) SetFlags(name string, value uint) bool {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(name))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_set_flags(v.native(), cstr1, C.guint(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GVariant * g_settings_get_value ()
|
||||||
|
// gboolean g_settings_set_value ()
|
||||||
|
// GVariant * g_settings_get_user_value ()
|
||||||
|
// GVariant * g_settings_get_default_value ()
|
||||||
|
// const gchar * const * g_settings_list_schemas ()
|
||||||
|
// const gchar * const * g_settings_list_relocatable_schemas ()
|
||||||
|
// gchar ** g_settings_list_keys ()
|
||||||
|
// GVariant * g_settings_get_range ()
|
||||||
|
// gboolean g_settings_range_check ()
|
||||||
|
// void g_settings_get ()
|
||||||
|
// gboolean g_settings_set ()
|
||||||
|
// gpointer g_settings_get_mapped ()
|
||||||
|
// void g_settings_bind ()
|
||||||
|
// void g_settings_bind_with_mapping ()
|
||||||
|
// void g_settings_bind_writable ()
|
||||||
|
// void g_settings_unbind ()
|
||||||
|
// gaction * g_settings_create_action ()
|
||||||
|
// gchar ** g_settings_get_strv ()
|
||||||
|
// gboolean g_settings_set_strv ()
|
@ -0,0 +1,71 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// SettingsBackend is a representation of GSettingsBackend.
|
||||||
|
type SettingsBackend struct {
|
||||||
|
*Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// native() returns a pointer to the underlying GSettingsBackend.
|
||||||
|
func (v *SettingsBackend) native() *C.GSettingsBackend {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return C.toGSettingsBackend(unsafe.Pointer(v.GObject))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *SettingsBackend) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalSettingsBackend(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapSettingsBackend(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapSettingsBackend(obj *Object) *SettingsBackend {
|
||||||
|
return &SettingsBackend{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsBackendGetDefault is a wrapper around g_settings_backend_get_default().
|
||||||
|
func SettingsBackendGetDefault() *SettingsBackend {
|
||||||
|
return wrapSettingsBackend(wrapObject(unsafe.Pointer(C.g_settings_backend_get_default())))
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyfileSettingsBackendNew is a wrapper around g_keyfile_settings_backend_new().
|
||||||
|
func KeyfileSettingsBackendNew(filename, rootPath, rootGroup string) *SettingsBackend {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(filename))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
cstr2 := (*C.gchar)(C.CString(rootPath))
|
||||||
|
defer C.free(unsafe.Pointer(cstr2))
|
||||||
|
|
||||||
|
cstr3 := (*C.gchar)(C.CString(rootGroup))
|
||||||
|
defer C.free(unsafe.Pointer(cstr3))
|
||||||
|
|
||||||
|
return wrapSettingsBackend(wrapObject(unsafe.Pointer(C.g_keyfile_settings_backend_new(cstr1, cstr2, cstr3))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemorySettingsBackendNew is a wrapper around g_memory_settings_backend_new().
|
||||||
|
func MemorySettingsBackendNew() *SettingsBackend {
|
||||||
|
return wrapSettingsBackend(wrapObject(unsafe.Pointer(C.g_memory_settings_backend_new())))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NullSettingsBackendNew is a wrapper around g_null_settings_backend_new().
|
||||||
|
func NullSettingsBackendNew() *SettingsBackend {
|
||||||
|
return wrapSettingsBackend(wrapObject(unsafe.Pointer(C.g_null_settings_backend_new())))
|
||||||
|
}
|
||||||
|
|
||||||
|
// void g_settings_backend_changed ()
|
||||||
|
// void g_settings_backend_path_changed ()
|
||||||
|
// void g_settings_backend_keys_changed ()
|
||||||
|
// void g_settings_backend_path_writable_changed ()
|
||||||
|
// void g_settings_backend_writable_changed ()
|
||||||
|
// void g_settings_backend_changed_tree ()
|
||||||
|
// void g_settings_backend_flatten_tree ()
|
@ -0,0 +1,96 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <gio/gio.h>
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// SettingsSchema is a representation of GSettingsSchema.
|
||||||
|
type SettingsSchema struct {
|
||||||
|
schema *C.GSettingsSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapSettingsSchema(obj *C.GSettingsSchema) *SettingsSchema {
|
||||||
|
if obj == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &SettingsSchema{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *SettingsSchema) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.schema))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *SettingsSchema) native() *C.GSettingsSchema {
|
||||||
|
if v == nil || v.schema == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.schema
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref() is a wrapper around g_settings_schema_ref().
|
||||||
|
func (v *SettingsSchema) Ref() *SettingsSchema {
|
||||||
|
return wrapSettingsSchema(C.g_settings_schema_ref(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unref() is a wrapper around g_settings_schema_unref().
|
||||||
|
func (v *SettingsSchema) Unref() {
|
||||||
|
C.g_settings_schema_unref(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetID() is a wrapper around g_settings_schema_get_id().
|
||||||
|
func (v *SettingsSchema) GetID() string {
|
||||||
|
return C.GoString((*C.char)(C.g_settings_schema_get_id(v.native())))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPath() is a wrapper around g_settings_schema_get_path().
|
||||||
|
func (v *SettingsSchema) GetPath() string {
|
||||||
|
return C.GoString((*C.char)(C.g_settings_schema_get_path(v.native())))
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasKey() is a wrapper around g_settings_schema_has_key().
|
||||||
|
func (v *SettingsSchema) HasKey(v1 string) bool {
|
||||||
|
cstr := (*C.gchar)(C.CString(v1))
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
return gobool(C.g_settings_schema_has_key(v.native(), cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func toGoStringArray(c **C.gchar) []string {
|
||||||
|
var strs []string
|
||||||
|
originalc := c
|
||||||
|
defer C.g_strfreev(originalc)
|
||||||
|
|
||||||
|
for *c != nil {
|
||||||
|
strs = append(strs, C.GoString((*C.char)(*c)))
|
||||||
|
c = C.next_gcharptr(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strs
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// // ListChildren() is a wrapper around g_settings_schema_list_children().
|
||||||
|
// func (v *SettingsSchema) ListChildren() []string {
|
||||||
|
// return toGoStringArray(C.g_settings_schema_list_children(v.native()))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // ListKeys() is a wrapper around g_settings_schema_list_keys().
|
||||||
|
// func (v *SettingsSchema) ListKeys() []string {
|
||||||
|
// return toGoStringArray(C.g_settings_schema_list_keys(v.native()))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const GVariantType * g_settings_schema_key_get_value_type ()
|
||||||
|
// GVariant * g_settings_schema_key_get_default_value ()
|
||||||
|
// GVariant * g_settings_schema_key_get_range ()
|
||||||
|
// gboolean g_settings_schema_key_range_check ()
|
||||||
|
// const gchar * g_settings_schema_key_get_name ()
|
||||||
|
// const gchar * g_settings_schema_key_get_summary ()
|
||||||
|
// const gchar * g_settings_schema_key_get_description ()
|
||||||
|
|
||||||
|
// GSettingsSchemaKey * g_settings_schema_get_key ()
|
||||||
|
// GSettingsSchemaKey * g_settings_schema_key_ref ()
|
||||||
|
// void g_settings_schema_key_unref ()
|
@ -0,0 +1,70 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <gio/gio.h>
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// SettingsSchemaSource is a representation of GSettingsSchemaSource.
|
||||||
|
type SettingsSchemaSource struct {
|
||||||
|
source *C.GSettingsSchemaSource
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapSettingsSchemaSource(obj *C.GSettingsSchemaSource) *SettingsSchemaSource {
|
||||||
|
if obj == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &SettingsSchemaSource{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *SettingsSchemaSource) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.source))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *SettingsSchemaSource) native() *C.GSettingsSchemaSource {
|
||||||
|
if v == nil || v.source == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.source
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsSchemaSourceGetDefault is a wrapper around g_settings_schema_source_get_default().
|
||||||
|
func SettingsSchemaSourceGetDefault() *SettingsSchemaSource {
|
||||||
|
return wrapSettingsSchemaSource(C.g_settings_schema_source_get_default())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref() is a wrapper around g_settings_schema_source_ref().
|
||||||
|
func (v *SettingsSchemaSource) Ref() *SettingsSchemaSource {
|
||||||
|
return wrapSettingsSchemaSource(C.g_settings_schema_source_ref(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unref() is a wrapper around g_settings_schema_source_unref().
|
||||||
|
func (v *SettingsSchemaSource) Unref() {
|
||||||
|
C.g_settings_schema_source_unref(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettingsSchemaSourceNewFromDirectory() is a wrapper around g_settings_schema_source_new_from_directory().
|
||||||
|
func SettingsSchemaSourceNewFromDirectory(dir string, parent *SettingsSchemaSource, trusted bool) *SettingsSchemaSource {
|
||||||
|
cstr := (*C.gchar)(C.CString(dir))
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
return wrapSettingsSchemaSource(C.g_settings_schema_source_new_from_directory(cstr, parent.native(), gbool(trusted), nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup() is a wrapper around g_settings_schema_source_lookup().
|
||||||
|
func (v *SettingsSchemaSource) Lookup(schema string, recursive bool) *SettingsSchema {
|
||||||
|
cstr := (*C.gchar)(C.CString(schema))
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
return wrapSettingsSchema(C.g_settings_schema_source_lookup(v.native(), cstr, gbool(recursive)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSchemas is a wrapper around g_settings_schema_source_list_schemas().
|
||||||
|
func (v *SettingsSchemaSource) ListSchemas(recursive bool) (nonReolcatable, relocatable []string) {
|
||||||
|
var nonRel, rel **C.gchar
|
||||||
|
C.g_settings_schema_source_list_schemas(v.native(), gbool(recursive), &nonRel, &rel)
|
||||||
|
return toGoStringArray(nonRel), toGoStringArray(rel)
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package glib
|
||||||
|
|
||||||
|
// #cgo pkg-config: glib-2.0 gobject-2.0
|
||||||
|
// #include <glib.h>
|
||||||
|
// #include <glib-object.h>
|
||||||
|
// #include "glib.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// SList is a representation of Glib's GSList.
|
||||||
|
type SList struct {
|
||||||
|
list *C.struct__GSList
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapSList(obj uintptr) *SList {
|
||||||
|
return wrapSList((*C.struct__GSList)(unsafe.Pointer(obj)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapSList(obj *C.struct__GSList) *SList {
|
||||||
|
return &SList{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *SList) Native() uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(v.list))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *SList) native() *C.struct__GSList {
|
||||||
|
if v == nil || v.list == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.list
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *SList) Append(data uintptr) *SList {
|
||||||
|
ret := C.g_slist_append(v.native(), C.gpointer(data))
|
||||||
|
if ret == v.native() {
|
||||||
|
return v
|
||||||
|
} else {
|
||||||
|
return wrapSList(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GSList * g_slist_alloc ()
|
||||||
|
// GSList * g_slist_prepend ()
|
||||||
|
// GSList * g_slist_insert ()
|
||||||
|
// GSList * g_slist_insert_before ()
|
||||||
|
// GSList * g_slist_insert_sorted ()
|
||||||
|
// GSList * g_slist_remove ()
|
||||||
|
// GSList * g_slist_remove_link ()
|
||||||
|
// GSList * g_slist_delete_link ()
|
||||||
|
// GSList * g_slist_remove_all ()
|
||||||
|
// void g_slist_free ()
|
||||||
|
// void g_slist_free_full ()
|
||||||
|
// void g_slist_free_1 ()
|
||||||
|
// guint g_slist_length ()
|
||||||
|
// GSList * g_slist_copy ()
|
||||||
|
// GSList * g_slist_copy_deep ()
|
||||||
|
// GSList * g_slist_reverse ()
|
||||||
|
// GSList * g_slist_insert_sorted_with_data ()
|
||||||
|
// GSList * g_slist_sort ()
|
||||||
|
// GSList * g_slist_sort_with_data ()
|
||||||
|
// GSList * g_slist_concat ()
|
||||||
|
// void g_slist_foreach ()
|
||||||
|
// GSList * g_slist_last ()
|
||||||
|
// #define g_slist_next()
|
||||||
|
// GSList * g_slist_nth ()
|
||||||
|
// gpointer g_slist_nth_data ()
|
||||||
|
// GSList * g_slist_find ()
|
||||||
|
// GSList * g_slist_find_custom ()
|
||||||
|
// gint g_slist_position ()
|
||||||
|
// gint g_slist_index ()
|
@ -0,0 +1,313 @@
|
|||||||
|
package gtk
|
||||||
|
|
||||||
|
// #include <gtk/gtk.h>
|
||||||
|
// #include "gtk.go.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gdk"
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tm := []glib.TypeMarshaler{
|
||||||
|
{glib.Type(C.gtk_about_dialog_get_type()), marshalAboutDialog},
|
||||||
|
}
|
||||||
|
|
||||||
|
glib.RegisterGValueMarshalers(tm)
|
||||||
|
|
||||||
|
WrapMap["GtkAboutDialog"] = wrapAboutDialog
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GtkAboutDialog
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AboutDialog is a representation of GTK's GtkAboutDialog.
|
||||||
|
type AboutDialog struct {
|
||||||
|
Dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GtkAboutDialog.
|
||||||
|
func (v *AboutDialog) native() *C.GtkAboutDialog {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(v.GObject)
|
||||||
|
return C.toGtkAboutDialog(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalAboutDialog(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
obj := wrapObject(unsafe.Pointer(c))
|
||||||
|
return wrapAboutDialog(obj), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapAboutDialog(obj *glib.Object) *AboutDialog {
|
||||||
|
return &AboutDialog{Dialog{Window{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AboutDialogNew is a wrapper around gtk_about_dialog_new().
|
||||||
|
func AboutDialogNew() (*AboutDialog, error) {
|
||||||
|
c := C.gtk_about_dialog_new()
|
||||||
|
if c == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
obj := wrapObject(unsafe.Pointer(c))
|
||||||
|
return wrapAboutDialog(obj), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetComments is a wrapper around gtk_about_dialog_get_comments().
|
||||||
|
func (v *AboutDialog) GetComments() string {
|
||||||
|
c := C.gtk_about_dialog_get_comments(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetComments is a wrapper around gtk_about_dialog_set_comments().
|
||||||
|
func (v *AboutDialog) SetComments(comments string) {
|
||||||
|
cstr := C.CString(comments)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_about_dialog_set_comments(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCopyright is a wrapper around gtk_about_dialog_get_copyright().
|
||||||
|
func (v *AboutDialog) GetCopyright() string {
|
||||||
|
c := C.gtk_about_dialog_get_copyright(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCopyright is a wrapper around gtk_about_dialog_set_copyright().
|
||||||
|
func (v *AboutDialog) SetCopyright(copyright string) {
|
||||||
|
cstr := C.CString(copyright)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_about_dialog_set_copyright(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLicense is a wrapper around gtk_about_dialog_get_license().
|
||||||
|
func (v *AboutDialog) GetLicense() string {
|
||||||
|
c := C.gtk_about_dialog_get_license(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLicense is a wrapper around gtk_about_dialog_set_license().
|
||||||
|
func (v *AboutDialog) SetLicense(license string) {
|
||||||
|
cstr := C.CString(license)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_about_dialog_set_license(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLicenseType is a wrapper around gtk_about_dialog_get_license_type().
|
||||||
|
func (v *AboutDialog) GetLicenseType() License {
|
||||||
|
c := C.gtk_about_dialog_get_license_type(v.native())
|
||||||
|
return License(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLicenseType is a wrapper around gtk_about_dialog_set_license_type().
|
||||||
|
func (v *AboutDialog) SetLicenseType(license License) {
|
||||||
|
C.gtk_about_dialog_set_license_type(v.native(), C.GtkLicense(license))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogo is a wrapper around gtk_about_dialog_set_logo().
|
||||||
|
func (v *AboutDialog) SetLogo(logo *gdk.Pixbuf) {
|
||||||
|
logoPtr := (*C.GdkPixbuf)(unsafe.Pointer(logo.Native()))
|
||||||
|
C.gtk_about_dialog_set_logo(v.native(), logoPtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLogoIconName is a wrapper around gtk_about_dialog_get_logo_icon_name().
|
||||||
|
func (v *AboutDialog) GetLogoIconName() string {
|
||||||
|
c := C.gtk_about_dialog_get_logo_icon_name(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogoIconName is a wrapper around gtk_about_dialog_set_logo_icon_name().
|
||||||
|
func (v *AboutDialog) SetLogoIconName(name string) {
|
||||||
|
cstr := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_about_dialog_set_logo_icon_name(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProgramName is a wrapper around gtk_about_dialog_get_program_name().
|
||||||
|
func (v *AboutDialog) GetProgramName() string {
|
||||||
|
c := C.gtk_about_dialog_get_program_name(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProgramName is a wrapper around gtk_about_dialog_set_program_name().
|
||||||
|
func (v *AboutDialog) SetProgramName(name string) {
|
||||||
|
cstr := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_about_dialog_set_program_name(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAuthors is a wrapper around gtk_about_dialog_get_authors().
|
||||||
|
func (v *AboutDialog) GetAuthors() []string {
|
||||||
|
var authors []string
|
||||||
|
cauthors := C.gtk_about_dialog_get_authors(v.native())
|
||||||
|
if cauthors == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if *cauthors == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
authors = append(authors, C.GoString((*C.char)(*cauthors)))
|
||||||
|
cauthors = C.next_gcharptr(cauthors)
|
||||||
|
}
|
||||||
|
return authors
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthors is a wrapper around gtk_about_dialog_set_authors().
|
||||||
|
func (v *AboutDialog) SetAuthors(authors []string) {
|
||||||
|
cauthors := C.make_strings(C.int(len(authors) + 1))
|
||||||
|
for i, author := range authors {
|
||||||
|
cstr := C.CString(author)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.set_string(cauthors, C.int(i), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
C.set_string(cauthors, C.int(len(authors)), nil)
|
||||||
|
C.gtk_about_dialog_set_authors(v.native(), cauthors)
|
||||||
|
C.destroy_strings(cauthors)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetArtists is a wrapper around gtk_about_dialog_get_artists().
|
||||||
|
func (v *AboutDialog) GetArtists() []string {
|
||||||
|
var artists []string
|
||||||
|
cartists := C.gtk_about_dialog_get_artists(v.native())
|
||||||
|
if cartists == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if *cartists == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
artists = append(artists, C.GoString((*C.char)(*cartists)))
|
||||||
|
cartists = C.next_gcharptr(cartists)
|
||||||
|
}
|
||||||
|
return artists
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetArtists is a wrapper around gtk_about_dialog_set_artists().
|
||||||
|
func (v *AboutDialog) SetArtists(artists []string) {
|
||||||
|
cartists := C.make_strings(C.int(len(artists) + 1))
|
||||||
|
for i, artist := range artists {
|
||||||
|
cstr := C.CString(artist)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.set_string(cartists, C.int(i), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
C.set_string(cartists, C.int(len(artists)), nil)
|
||||||
|
C.gtk_about_dialog_set_artists(v.native(), cartists)
|
||||||
|
C.destroy_strings(cartists)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDocumenters is a wrapper around gtk_about_dialog_get_documenters().
|
||||||
|
func (v *AboutDialog) GetDocumenters() []string {
|
||||||
|
var documenters []string
|
||||||
|
cdocumenters := C.gtk_about_dialog_get_documenters(v.native())
|
||||||
|
if cdocumenters == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if *cdocumenters == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
documenters = append(documenters, C.GoString((*C.char)(*cdocumenters)))
|
||||||
|
cdocumenters = C.next_gcharptr(cdocumenters)
|
||||||
|
}
|
||||||
|
return documenters
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDocumenters is a wrapper around gtk_about_dialog_set_documenters().
|
||||||
|
func (v *AboutDialog) SetDocumenters(documenters []string) {
|
||||||
|
cdocumenters := C.make_strings(C.int(len(documenters) + 1))
|
||||||
|
for i, doc := range documenters {
|
||||||
|
cstr := C.CString(doc)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.set_string(cdocumenters, C.int(i), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
C.set_string(cdocumenters, C.int(len(documenters)), nil)
|
||||||
|
C.gtk_about_dialog_set_documenters(v.native(), cdocumenters)
|
||||||
|
C.destroy_strings(cdocumenters)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTranslatorCredits is a wrapper around gtk_about_dialog_get_translator_credits().
|
||||||
|
func (v *AboutDialog) GetTranslatorCredits() string {
|
||||||
|
c := C.gtk_about_dialog_get_translator_credits(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTranslatorCredits is a wrapper around gtk_about_dialog_set_translator_credits().
|
||||||
|
func (v *AboutDialog) SetTranslatorCredits(translatorCredits string) {
|
||||||
|
cstr := C.CString(translatorCredits)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_about_dialog_set_translator_credits(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVersion is a wrapper around gtk_about_dialog_get_version().
|
||||||
|
func (v *AboutDialog) GetVersion() string {
|
||||||
|
c := C.gtk_about_dialog_get_version(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVersion is a wrapper around gtk_about_dialog_set_version().
|
||||||
|
func (v *AboutDialog) SetVersion(version string) {
|
||||||
|
cstr := C.CString(version)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_about_dialog_set_version(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWebsite is a wrapper around gtk_about_dialog_get_website().
|
||||||
|
func (v *AboutDialog) GetWebsite() string {
|
||||||
|
c := C.gtk_about_dialog_get_website(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWebsite is a wrapper around gtk_about_dialog_set_website().
|
||||||
|
func (v *AboutDialog) SetWebsite(website string) {
|
||||||
|
cstr := C.CString(website)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_about_dialog_set_website(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWebsiteLabel is a wrapper around gtk_about_dialog_get_website_label().
|
||||||
|
func (v *AboutDialog) GetWebsiteLabel() string {
|
||||||
|
c := C.gtk_about_dialog_get_website_label(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWebsiteLabel is a wrapper around gtk_about_dialog_set_website_label().
|
||||||
|
func (v *AboutDialog) SetWebsiteLabel(websiteLabel string) {
|
||||||
|
cstr := C.CString(websiteLabel)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_about_dialog_set_website_label(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWrapLicense is a wrapper around gtk_about_dialog_get_wrap_license().
|
||||||
|
func (v *AboutDialog) GetWrapLicense() bool {
|
||||||
|
return gobool(C.gtk_about_dialog_get_wrap_license(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWrapLicense is a wrapper around gtk_about_dialog_set_wrap_license().
|
||||||
|
func (v *AboutDialog) SetWrapLicense(wrapLicense bool) {
|
||||||
|
C.gtk_about_dialog_set_wrap_license(v.native(), gbool(wrapLicense))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCreditSection is a wrapper around gtk_about_dialog_add_credit_section().
|
||||||
|
func (v *AboutDialog) AddCreditSection(sectionName string, people []string) {
|
||||||
|
cname := (*C.gchar)(C.CString(sectionName))
|
||||||
|
defer C.free(unsafe.Pointer(cname))
|
||||||
|
|
||||||
|
cpeople := C.make_strings(C.int(len(people)) + 1)
|
||||||
|
defer C.destroy_strings(cpeople)
|
||||||
|
for i, p := range people {
|
||||||
|
cp := (*C.gchar)(C.CString(p))
|
||||||
|
defer C.free(unsafe.Pointer(cp))
|
||||||
|
C.set_string(cpeople, C.int(i), cp)
|
||||||
|
}
|
||||||
|
C.set_string(cpeople, C.int(len(people)), nil)
|
||||||
|
|
||||||
|
C.gtk_about_dialog_add_credit_section(v.native(), cname, cpeople)
|
||||||
|
}
|
@ -0,0 +1,435 @@
|
|||||||
|
// Same copyright and license as the rest of the files in this project
|
||||||
|
// This file contains accelerator related functions and structures
|
||||||
|
|
||||||
|
package gtk
|
||||||
|
|
||||||
|
// #include <gtk/gtk.h>
|
||||||
|
// #include "gtk.go.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gdk"
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccelFlags is a representation of GTK's GtkAccelFlags
|
||||||
|
type AccelFlags int
|
||||||
|
|
||||||
|
const (
|
||||||
|
ACCEL_VISIBLE AccelFlags = C.GTK_ACCEL_VISIBLE
|
||||||
|
ACCEL_LOCKED AccelFlags = C.GTK_ACCEL_LOCKED
|
||||||
|
ACCEL_MASK AccelFlags = C.GTK_ACCEL_MASK
|
||||||
|
)
|
||||||
|
|
||||||
|
func marshalAccelFlags(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return AccelFlags(c), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceleratorName is a wrapper around gtk_accelerator_name().
|
||||||
|
func AcceleratorName(key uint, mods gdk.ModifierType) string {
|
||||||
|
c := C.gtk_accelerator_name(C.guint(key), C.GdkModifierType(mods))
|
||||||
|
defer C.free(unsafe.Pointer(c))
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceleratorValid is a wrapper around gtk_accelerator_valid().
|
||||||
|
func AcceleratorValid(key uint, mods gdk.ModifierType) bool {
|
||||||
|
return gobool(C.gtk_accelerator_valid(C.guint(key), C.GdkModifierType(mods)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceleratorGetDefaultModMask is a wrapper around gtk_accelerator_get_default_mod_mask().
|
||||||
|
func AcceleratorGetDefaultModMask() gdk.ModifierType {
|
||||||
|
return gdk.ModifierType(C.gtk_accelerator_get_default_mod_mask())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceleratorParse is a wrapper around gtk_accelerator_parse().
|
||||||
|
func AcceleratorParse(acc string) (key uint, mods gdk.ModifierType) {
|
||||||
|
cstr := C.CString(acc)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
k := C.guint(0)
|
||||||
|
m := C.GdkModifierType(0)
|
||||||
|
|
||||||
|
C.gtk_accelerator_parse((*C.gchar)(cstr), &k, &m)
|
||||||
|
return uint(k), gdk.ModifierType(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceleratorGetLabel is a wrapper around gtk_accelerator_get_label().
|
||||||
|
func AcceleratorGetLabel(key uint, mods gdk.ModifierType) string {
|
||||||
|
c := C.gtk_accelerator_get_label(C.guint(key), C.GdkModifierType(mods))
|
||||||
|
defer C.free(unsafe.Pointer(c))
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceleratorSetDefaultModMask is a wrapper around gtk_accelerator_set_default_mod_mask().
|
||||||
|
func AcceleratorSetDefaultModMask(mods gdk.ModifierType) {
|
||||||
|
C.gtk_accelerator_set_default_mod_mask(C.GdkModifierType(mods))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GtkAccelGroup
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AccelGroup is a representation of GTK's GtkAccelGroup.
|
||||||
|
type AccelGroup struct {
|
||||||
|
*glib.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GtkAccelGroup.
|
||||||
|
func (v *AccelGroup) native() *C.GtkAccelGroup {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(v.GObject)
|
||||||
|
return C.toGtkAccelGroup(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalAccelGroup(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
obj := wrapObject(unsafe.Pointer(c))
|
||||||
|
return wrapAccelGroup(obj), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapAccelGroup(obj *glib.Object) *AccelGroup {
|
||||||
|
return &AccelGroup{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelGroup is a wrapper around gtk_accel_group_new().
|
||||||
|
func AccelGroupNew() (*AccelGroup, error) {
|
||||||
|
c := C.gtk_accel_group_new()
|
||||||
|
if c == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
obj := wrapObject(unsafe.Pointer(c))
|
||||||
|
return wrapAccelGroup(obj), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect is a wrapper around gtk_accel_group_connect().
|
||||||
|
func (v *AccelGroup) Connect(key uint, mods gdk.ModifierType, flags AccelFlags, f interface{}) {
|
||||||
|
closure, _ := glib.ClosureNew(f)
|
||||||
|
cl := (*C.struct__GClosure)(unsafe.Pointer(closure))
|
||||||
|
C.gtk_accel_group_connect(
|
||||||
|
v.native(),
|
||||||
|
C.guint(key),
|
||||||
|
C.GdkModifierType(mods),
|
||||||
|
C.GtkAccelFlags(flags),
|
||||||
|
cl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectByPath is a wrapper around gtk_accel_group_connect_by_path().
|
||||||
|
func (v *AccelGroup) ConnectByPath(path string, f interface{}) {
|
||||||
|
closure, _ := glib.ClosureNew(f)
|
||||||
|
cl := (*C.struct__GClosure)(unsafe.Pointer(closure))
|
||||||
|
|
||||||
|
cstr := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_accel_group_connect_by_path(
|
||||||
|
v.native(),
|
||||||
|
(*C.gchar)(cstr),
|
||||||
|
cl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect is a wrapper around gtk_accel_group_disconnect().
|
||||||
|
func (v *AccelGroup) Disconnect(f interface{}) {
|
||||||
|
closure, _ := glib.ClosureNew(f)
|
||||||
|
cl := (*C.struct__GClosure)(unsafe.Pointer(closure))
|
||||||
|
C.gtk_accel_group_disconnect(v.native(), cl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisconnectKey is a wrapper around gtk_accel_group_disconnect_key().
|
||||||
|
func (v *AccelGroup) DisconnectKey(key uint, mods gdk.ModifierType) {
|
||||||
|
C.gtk_accel_group_disconnect_key(v.native(), C.guint(key), C.GdkModifierType(mods))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock is a wrapper around gtk_accel_group_lock().
|
||||||
|
func (v *AccelGroup) Lock() {
|
||||||
|
C.gtk_accel_group_lock(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock is a wrapper around gtk_accel_group_unlock().
|
||||||
|
func (v *AccelGroup) Unlock() {
|
||||||
|
C.gtk_accel_group_unlock(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsLocked is a wrapper around gtk_accel_group_get_is_locked().
|
||||||
|
func (v *AccelGroup) IsLocked() bool {
|
||||||
|
return gobool(C.gtk_accel_group_get_is_locked(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelGroupFromClosure is a wrapper around gtk_accel_group_from_accel_closure().
|
||||||
|
func AccelGroupFromClosure(f interface{}) *AccelGroup {
|
||||||
|
closure, _ := glib.ClosureNew(f)
|
||||||
|
cl := (*C.struct__GClosure)(unsafe.Pointer(closure))
|
||||||
|
c := C.gtk_accel_group_from_accel_closure(cl)
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapAccelGroup(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetModifierMask is a wrapper around gtk_accel_group_get_modifier_mask().
|
||||||
|
func (v *AccelGroup) GetModifierMask() gdk.ModifierType {
|
||||||
|
return gdk.ModifierType(C.gtk_accel_group_get_modifier_mask(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelGroupsActivate is a wrapper around gtk_accel_groups_activate().
|
||||||
|
func AccelGroupsActivate(obj *glib.Object, key uint, mods gdk.ModifierType) bool {
|
||||||
|
return gobool(C.gtk_accel_groups_activate((*C.GObject)(unsafe.Pointer(obj.Native())), C.guint(key), C.GdkModifierType(mods)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate is a wrapper around gtk_accel_group_activate().
|
||||||
|
func (v *AccelGroup) Activate(quark glib.Quark, acceleratable *glib.Object, key uint, mods gdk.ModifierType) bool {
|
||||||
|
return gobool(C.gtk_accel_group_activate(v.native(), C.GQuark(quark), (*C.GObject)(unsafe.Pointer(acceleratable.Native())), C.guint(key), C.GdkModifierType(mods)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelGroupsFromObject is a wrapper around gtk_accel_groups_from_object().
|
||||||
|
func AccelGroupsFromObject(obj *glib.Object) *glib.SList {
|
||||||
|
res := C.gtk_accel_groups_from_object((*C.GObject)(unsafe.Pointer(obj.Native())))
|
||||||
|
if res == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*glib.SList)(unsafe.Pointer(res))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GtkAccelMap
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AccelMap is a representation of GTK's GtkAccelMap.
|
||||||
|
type AccelMap struct {
|
||||||
|
*glib.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GtkAccelMap.
|
||||||
|
func (v *AccelMap) native() *C.GtkAccelMap {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(v.GObject)
|
||||||
|
return C.toGtkAccelMap(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalAccelMap(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
obj := wrapObject(unsafe.Pointer(c))
|
||||||
|
return wrapAccelMap(obj), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapAccelMap(obj *glib.Object) *AccelMap {
|
||||||
|
return &AccelMap{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapAddEntry is a wrapper around gtk_accel_map_add_entry().
|
||||||
|
func AccelMapAddEntry(path string, key uint, mods gdk.ModifierType) {
|
||||||
|
cstr := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_accel_map_add_entry((*C.gchar)(cstr), C.guint(key), C.GdkModifierType(mods))
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccelKey struct {
|
||||||
|
key uint
|
||||||
|
mods gdk.ModifierType
|
||||||
|
flags uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *AccelKey) native() *C.struct__GtkAccelKey {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var val C.struct__GtkAccelKey
|
||||||
|
val.accel_key = C.guint(v.key)
|
||||||
|
val.accel_mods = C.GdkModifierType(v.mods)
|
||||||
|
val.accel_flags = v.flags
|
||||||
|
return &val
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapAccelKey(obj *C.struct__GtkAccelKey) *AccelKey {
|
||||||
|
var v AccelKey
|
||||||
|
|
||||||
|
v.key = uint(obj.accel_key)
|
||||||
|
v.mods = gdk.ModifierType(obj.accel_mods)
|
||||||
|
v.flags = uint16(obj.accel_flags)
|
||||||
|
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapLookupEntry is a wrapper around gtk_accel_map_lookup_entry().
|
||||||
|
func AccelMapLookupEntry(path string) *AccelKey {
|
||||||
|
cstr := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
var v *C.struct__GtkAccelKey
|
||||||
|
|
||||||
|
C.gtk_accel_map_lookup_entry((*C.gchar)(cstr), v)
|
||||||
|
return wrapAccelKey(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapChangeEntry is a wrapper around gtk_accel_map_change_entry().
|
||||||
|
func AccelMapChangeEntry(path string, key uint, mods gdk.ModifierType, replace bool) bool {
|
||||||
|
cstr := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
return gobool(C.gtk_accel_map_change_entry((*C.gchar)(cstr), C.guint(key), C.GdkModifierType(mods), gbool(replace)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapLoad is a wrapper around gtk_accel_map_load().
|
||||||
|
func AccelMapLoad(fileName string) {
|
||||||
|
cstr := C.CString(fileName)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_accel_map_load((*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapSave is a wrapper around gtk_accel_map_save().
|
||||||
|
func AccelMapSave(fileName string) {
|
||||||
|
cstr := C.CString(fileName)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_accel_map_save((*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapLoadFD is a wrapper around gtk_accel_map_load_fd().
|
||||||
|
func AccelMapLoadFD(fd int) {
|
||||||
|
C.gtk_accel_map_load_fd(C.gint(fd))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapSaveFD is a wrapper around gtk_accel_map_save_fd().
|
||||||
|
func AccelMapSaveFD(fd int) {
|
||||||
|
C.gtk_accel_map_save_fd(C.gint(fd))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapAddFilter is a wrapper around gtk_accel_map_add_filter().
|
||||||
|
func AccelMapAddFilter(filter string) {
|
||||||
|
cstr := C.CString(filter)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_accel_map_add_filter((*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapGet is a wrapper around gtk_accel_map_get().
|
||||||
|
func AccelMapGet() *AccelMap {
|
||||||
|
c := C.gtk_accel_map_get()
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapAccelMap(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapLockPath is a wrapper around gtk_accel_map_lock_path().
|
||||||
|
func AccelMapLockPath(path string) {
|
||||||
|
cstr := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_accel_map_lock_path((*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccelMapUnlockPath is a wrapper around gtk_accel_map_unlock_path().
|
||||||
|
func AccelMapUnlockPath(path string) {
|
||||||
|
cstr := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_accel_map_unlock_path((*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAccelGroup is a wrapper around gtk_menu_set_accel_group().
|
||||||
|
func (v *Menu) SetAccelGroup(accelGroup *AccelGroup) {
|
||||||
|
C.gtk_menu_set_accel_group(v.native(), accelGroup.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccelGroup is a wrapper around gtk_menu_get_accel_group().
|
||||||
|
func (v *Menu) GetAccelGroup() *AccelGroup {
|
||||||
|
c := C.gtk_menu_get_accel_group(v.native())
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapAccelGroup(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAccelPath is a wrapper around gtk_menu_set_accel_path().
|
||||||
|
func (v *Menu) SetAccelPath(path string) {
|
||||||
|
cstr := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_menu_set_accel_path(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccelPath is a wrapper around gtk_menu_get_accel_path().
|
||||||
|
func (v *Menu) GetAccelPath() string {
|
||||||
|
c := C.gtk_menu_get_accel_path(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAccelPath is a wrapper around gtk_menu_item_set_accel_path().
|
||||||
|
func (v *MenuItem) SetAccelPath(path string) {
|
||||||
|
cstr := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_menu_item_set_accel_path(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccelPath is a wrapper around gtk_menu_item_get_accel_path().
|
||||||
|
func (v *MenuItem) GetAccelPath() string {
|
||||||
|
c := C.gtk_menu_item_get_accel_path(v.native())
|
||||||
|
return C.GoString((*C.char)(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAccelerator is a wrapper around gtk_widget_add_accelerator().
|
||||||
|
func (v *Widget) AddAccelerator(signal string, group *AccelGroup, key uint, mods gdk.ModifierType, flags AccelFlags) {
|
||||||
|
csignal := (*C.gchar)(C.CString(signal))
|
||||||
|
defer C.free(unsafe.Pointer(csignal))
|
||||||
|
|
||||||
|
C.gtk_widget_add_accelerator(v.native(),
|
||||||
|
csignal,
|
||||||
|
group.native(),
|
||||||
|
C.guint(key),
|
||||||
|
C.GdkModifierType(mods),
|
||||||
|
C.GtkAccelFlags(flags))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAccelerator is a wrapper around gtk_widget_remove_accelerator().
|
||||||
|
func (v *Widget) RemoveAccelerator(group *AccelGroup, key uint, mods gdk.ModifierType) bool {
|
||||||
|
return gobool(C.gtk_widget_remove_accelerator(v.native(),
|
||||||
|
group.native(),
|
||||||
|
C.guint(key),
|
||||||
|
C.GdkModifierType(mods)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAccelPath is a wrapper around gtk_widget_set_accel_path().
|
||||||
|
func (v *Widget) SetAccelPath(path string, group *AccelGroup) {
|
||||||
|
cstr := (*C.gchar)(C.CString(path))
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
C.gtk_widget_set_accel_path(v.native(), cstr, group.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanActivateAccel is a wrapper around gtk_widget_can_activate_accel().
|
||||||
|
func (v *Widget) CanActivateAccel(signalId uint) bool {
|
||||||
|
return gobool(C.gtk_widget_can_activate_accel(v.native(), C.guint(signalId)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAccelGroup() is a wrapper around gtk_window_add_accel_group().
|
||||||
|
func (v *Window) AddAccelGroup(accelGroup *AccelGroup) {
|
||||||
|
C.gtk_window_add_accel_group(v.native(), accelGroup.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAccelGroup() is a wrapper around gtk_window_add_accel_group().
|
||||||
|
func (v *Window) RemoveAccelGroup(accelGroup *AccelGroup) {
|
||||||
|
C.gtk_window_remove_accel_group(v.native(), accelGroup.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// These three functions are for system level access - thus not as high priority to implement
|
||||||
|
// TODO: void gtk_accelerator_parse_with_keycode ()
|
||||||
|
// TODO: gchar * gtk_accelerator_name_with_keycode ()
|
||||||
|
// TODO: gchar * gtk_accelerator_get_label_with_keycode ()
|
||||||
|
|
||||||
|
// TODO: GtkAccelKey * gtk_accel_group_find () - this function uses a function type - I don't know how to represent it in cgo
|
||||||
|
// TODO: gtk_accel_map_foreach_unfiltered - can't be done without a function type
|
||||||
|
// TODO: gtk_accel_map_foreach - can't be done without a function type
|
||||||
|
|
||||||
|
// TODO: gtk_accel_map_load_scanner
|
||||||
|
// TODO: gtk_widget_list_accel_closures
|
@ -0,0 +1,106 @@
|
|||||||
|
// +build !gtk_3_6,!gtk_3_8,!gtk_3_10
|
||||||
|
|
||||||
|
// Copyright (c) 2013-2014 Conformal Systems <info@conformal.com>
|
||||||
|
//
|
||||||
|
// This file originated from: http://opensource.conformal.com/
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
// This file includes wrapers for symbols included since GTK 3.12, and
|
||||||
|
// and should not be included in a build intended to target any older GTK
|
||||||
|
// versions. To target an older build, such as 3.10, use
|
||||||
|
// 'go build -tags gtk_3_10'. Otherwise, if no build tags are used, GTK 3.12
|
||||||
|
// is assumed and this file is built.
|
||||||
|
// +build !gtk_3_6,!gtk_3_8,!gtk_3_10
|
||||||
|
|
||||||
|
package gtk
|
||||||
|
|
||||||
|
// #cgo pkg-config: gtk+-3.0
|
||||||
|
// #include <gtk/gtk.h>
|
||||||
|
// #include "actionbar_since_3_12.go.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tm := []glib.TypeMarshaler{
|
||||||
|
{glib.Type(C.gtk_action_bar_get_type()), marshalActionBar},
|
||||||
|
}
|
||||||
|
|
||||||
|
glib.RegisterGValueMarshalers(tm)
|
||||||
|
|
||||||
|
WrapMap["GtkActionBar"] = wrapActionBar
|
||||||
|
}
|
||||||
|
|
||||||
|
//GtkActionBar
|
||||||
|
type ActionBar struct {
|
||||||
|
Bin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ActionBar) native() *C.GtkActionBar {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := unsafe.Pointer(v.GObject)
|
||||||
|
return C.toGtkActionBar(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalActionBar(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapActionBar(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapActionBar(obj *glib.Object) *ActionBar {
|
||||||
|
return &ActionBar{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
//gtk_action_bar_new()
|
||||||
|
func ActionBarNew() (*ActionBar, error) {
|
||||||
|
c := C.gtk_action_bar_new()
|
||||||
|
if c == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
return wrapActionBar(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//gtk_action_bar_pack_start(GtkActionBar *action_bar,GtkWidget *child)
|
||||||
|
func (a *ActionBar) PackStart(child IWidget) {
|
||||||
|
C.gtk_action_bar_pack_start(a.native(), child.toWidget())
|
||||||
|
}
|
||||||
|
|
||||||
|
//gtk_action_bar_pack_end(GtkActionBar *action_bar,GtkWidget *child)
|
||||||
|
func (a *ActionBar) PackEnd(child IWidget) {
|
||||||
|
C.gtk_action_bar_pack_end(a.native(), child.toWidget())
|
||||||
|
}
|
||||||
|
|
||||||
|
//gtk_action_bar_set_center_widget(GtkActionBar *action_bar,GtkWidget *center_widget)
|
||||||
|
func (a *ActionBar) SetCenterWidget(child IWidget) {
|
||||||
|
if child == nil {
|
||||||
|
C.gtk_action_bar_set_center_widget(a.native(), nil)
|
||||||
|
} else {
|
||||||
|
C.gtk_action_bar_set_center_widget(a.native(), child.toWidget())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//gtk_action_bar_get_center_widget(GtkActionBar *action_bar)
|
||||||
|
func (a *ActionBar) GetCenterWidget() *Widget {
|
||||||
|
w := C.gtk_action_bar_get_center_widget(a.native())
|
||||||
|
if w == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Widget{glib.InitiallyUnowned{wrapObject(unsafe.Pointer(w))}}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
// +build !gtk_3_6,!gtk_3_8,!gtk_3_10,!gtk_3_12
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013-2014 Conformal Systems <info@conformal.com>
|
||||||
|
*
|
||||||
|
* This file originated from: http://opensource.conformal.com/
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static GtkActionBar *
|
||||||
|
toGtkActionBar(void *p)
|
||||||
|
{
|
||||||
|
return (GTK_ACTION_BAR(p));
|
||||||
|
}
|
@ -0,0 +1,378 @@
|
|||||||
|
package gtk
|
||||||
|
|
||||||
|
// #include <gtk/gtk.h>
|
||||||
|
// #include "gtk.go.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tm := []glib.TypeMarshaler{
|
||||||
|
{glib.Type(C.gtk_app_chooser_get_type()), marshalAppChooser},
|
||||||
|
{glib.Type(C.gtk_app_chooser_button_get_type()), marshalAppChooserButton},
|
||||||
|
{glib.Type(C.gtk_app_chooser_widget_get_type()), marshalAppChooserWidget},
|
||||||
|
{glib.Type(C.gtk_app_chooser_dialog_get_type()), marshalAppChooserDialog},
|
||||||
|
}
|
||||||
|
|
||||||
|
glib.RegisterGValueMarshalers(tm)
|
||||||
|
|
||||||
|
WrapMap["GtkAppChooser"] = wrapAppChooser
|
||||||
|
WrapMap["GtkAppChooserButton"] = wrapAppChooserButton
|
||||||
|
WrapMap["GtkAppChooserWidget"] = wrapAppChooserWidget
|
||||||
|
WrapMap["GtkAppChooserDialog"] = wrapAppChooserDialog
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GtkAppChooser
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AppChooser is a representation of GTK's GtkAppChooser GInterface.
|
||||||
|
type AppChooser struct {
|
||||||
|
*glib.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
// IAppChooser is an interface type implemented by all structs
|
||||||
|
// embedding an AppChooser. It is meant to be used as an argument type
|
||||||
|
// for wrapper functions that wrap around a C GTK function taking a
|
||||||
|
// GtkAppChooser.
|
||||||
|
type IAppChooser interface {
|
||||||
|
toAppChooser() *C.GtkAppChooser
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GtkAppChooser.
|
||||||
|
func (v *AppChooser) native() *C.GtkAppChooser {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p := unsafe.Pointer(v.GObject)
|
||||||
|
return C.toGtkAppChooser(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalAppChooser(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
obj := wrapObject(unsafe.Pointer(c))
|
||||||
|
return wrapAppChooser(obj), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapAppChooser(obj *glib.Object) *AppChooser {
|
||||||
|
return &AppChooser{obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *AppChooser) toAppChooser() *C.GtkAppChooser {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.native()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Needs gio/GAppInfo implementation first
|
||||||
|
// gtk_app_chooser_get_app_info ()
|
||||||
|
|
||||||
|
// GetContentType is a wrapper around gtk_app_chooser_get_content_type().
|
||||||
|
func (v *AppChooser) GetContentType() string {
|
||||||
|
cstr := C.gtk_app_chooser_get_content_type(v.native())
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
return C.GoString((*C.char)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh is a wrapper around gtk_app_chooser_refresh().
|
||||||
|
func (v *AppChooser) Refresh() {
|
||||||
|
C.gtk_app_chooser_refresh(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GtkAppChooserButton
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AppChooserButton is a representation of GTK's GtkAppChooserButton.
|
||||||
|
type AppChooserButton struct {
|
||||||
|
ComboBox
|
||||||
|
|
||||||
|
// Interfaces
|
||||||
|
AppChooser
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GtkAppChooserButton.
|
||||||
|
func (v *AppChooserButton) native() *C.GtkAppChooserButton {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := unsafe.Pointer(v.GObject)
|
||||||
|
return C.toGtkAppChooserButton(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalAppChooserButton(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapAppChooserButton(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapAppChooserButton(obj *glib.Object) *AppChooserButton {
|
||||||
|
cl := wrapCellLayout(obj)
|
||||||
|
ac := wrapAppChooser(obj)
|
||||||
|
return &AppChooserButton{ComboBox{Bin{Container{Widget{glib.InitiallyUnowned{obj}}}}, *cl}, *ac}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppChooserButtonNew() is a wrapper around gtk_app_chooser_button_new().
|
||||||
|
func AppChooserButtonNew(content_type string) (*AppChooserButton, error) {
|
||||||
|
cstr := C.CString(content_type)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
c := C.gtk_app_chooser_button_new((*C.gchar)(cstr))
|
||||||
|
if c == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
return wrapAppChooserButton(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Needs gio/GIcon implemented first
|
||||||
|
// gtk_app_chooser_button_append_custom_item ()
|
||||||
|
|
||||||
|
// AppendSeparator() is a wrapper around gtk_app_chooser_button_append_separator().
|
||||||
|
func (v *AppChooserButton) AppendSeparator() {
|
||||||
|
C.gtk_app_chooser_button_append_separator(v.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetActiveCustomItem() is a wrapper around gtk_app_chooser_button_set_active_custom_item().
|
||||||
|
func (v *AppChooserButton) SetActiveCustomItem(name string) {
|
||||||
|
cstr := C.CString(name)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_app_chooser_button_set_active_custom_item(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetShowDefaultItem() is a wrapper around gtk_app_chooser_button_get_show_default_item().
|
||||||
|
func (v *AppChooserButton) GetShowDefaultItem() bool {
|
||||||
|
return gobool(C.gtk_app_chooser_button_get_show_default_item(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetShowDefaultItem() is a wrapper around gtk_app_chooser_button_set_show_default_item().
|
||||||
|
func (v *AppChooserButton) SetShowDefaultItem(setting bool) {
|
||||||
|
C.gtk_app_chooser_button_set_show_default_item(v.native(), gbool(setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetShowDialogItem() is a wrapper around gtk_app_chooser_button_get_show_dialog_item().
|
||||||
|
func (v *AppChooserButton) GetShowDialogItem() bool {
|
||||||
|
return gobool(C.gtk_app_chooser_button_get_show_dialog_item(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetShowDialogItem() is a wrapper around gtk_app_chooser_button_set_show_dialog_item().
|
||||||
|
func (v *AppChooserButton) SetShowDialogItem(setting bool) {
|
||||||
|
C.gtk_app_chooser_button_set_show_dialog_item(v.native(), gbool(setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeading() is a wrapper around gtk_app_chooser_button_get_heading().
|
||||||
|
// In case when gtk_app_chooser_button_get_heading() returns a nil string,
|
||||||
|
// GetHeading() returns a non-nil error.
|
||||||
|
func (v *AppChooserButton) GetHeading() (string, error) {
|
||||||
|
cstr := C.gtk_app_chooser_button_get_heading(v.native())
|
||||||
|
if cstr == nil {
|
||||||
|
return "", nilPtrErr
|
||||||
|
}
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
return C.GoString((*C.char)(cstr)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHeading() is a wrapper around gtk_app_chooser_button_set_heading().
|
||||||
|
func (v *AppChooserButton) SetHeading(heading string) {
|
||||||
|
cstr := C.CString(heading)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_app_chooser_button_set_heading(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GtkAppChooserWidget
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AppChooserWidget is a representation of GTK's GtkAppChooserWidget.
|
||||||
|
type AppChooserWidget struct {
|
||||||
|
Box
|
||||||
|
|
||||||
|
// Interfaces
|
||||||
|
AppChooser
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GtkAppChooserWidget.
|
||||||
|
func (v *AppChooserWidget) native() *C.GtkAppChooserWidget {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := unsafe.Pointer(v.GObject)
|
||||||
|
return C.toGtkAppChooserWidget(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalAppChooserWidget(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapAppChooserWidget(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapAppChooserWidget(obj *glib.Object) *AppChooserWidget {
|
||||||
|
box := wrapBox(obj)
|
||||||
|
ac := wrapAppChooser(obj)
|
||||||
|
return &AppChooserWidget{*box, *ac}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppChooserWidgetNew() is a wrapper around gtk_app_chooser_widget_new().
|
||||||
|
func AppChooserWidgetNew(content_type string) (*AppChooserWidget, error) {
|
||||||
|
cstr := C.CString(content_type)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
c := C.gtk_app_chooser_widget_new((*C.gchar)(cstr))
|
||||||
|
if c == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
return wrapAppChooserWidget(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetShowDefault() is a wrapper around gtk_app_chooser_widget_get_show_default().
|
||||||
|
func (v *AppChooserWidget) GetShowDefault() bool {
|
||||||
|
return gobool(C.gtk_app_chooser_widget_get_show_default(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetShowDefault() is a wrapper around gtk_app_chooser_widget_set_show_default().
|
||||||
|
func (v *AppChooserWidget) SetShowDefault(setting bool) {
|
||||||
|
C.gtk_app_chooser_widget_set_show_default(v.native(), gbool(setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetShowRecommended() is a wrapper around gtk_app_chooser_widget_get_show_recommended().
|
||||||
|
func (v *AppChooserWidget) GetShowRecommended() bool {
|
||||||
|
return gobool(C.gtk_app_chooser_widget_get_show_recommended(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetShowRecommended() is a wrapper around gtk_app_chooser_widget_set_show_recommended().
|
||||||
|
func (v *AppChooserWidget) SetShowRecommended(setting bool) {
|
||||||
|
C.gtk_app_chooser_widget_set_show_recommended(v.native(), gbool(setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetShowFallback() is a wrapper around gtk_app_chooser_widget_get_show_fallback().
|
||||||
|
func (v *AppChooserWidget) GetShowFallback() bool {
|
||||||
|
return gobool(C.gtk_app_chooser_widget_get_show_fallback(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetShowFallback() is a wrapper around gtk_app_chooser_widget_set_show_fallback().
|
||||||
|
func (v *AppChooserWidget) SetShowFallback(setting bool) {
|
||||||
|
C.gtk_app_chooser_widget_set_show_fallback(v.native(), gbool(setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetShowOther() is a wrapper around gtk_app_chooser_widget_get_show_other().
|
||||||
|
func (v *AppChooserWidget) GetShowOther() bool {
|
||||||
|
return gobool(C.gtk_app_chooser_widget_get_show_other(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetShowOther() is a wrapper around gtk_app_chooser_widget_set_show_other().
|
||||||
|
func (v *AppChooserWidget) SetShowOther(setting bool) {
|
||||||
|
C.gtk_app_chooser_widget_set_show_other(v.native(), gbool(setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetShowAll() is a wrapper around gtk_app_chooser_widget_get_show_all().
|
||||||
|
func (v *AppChooserWidget) GetShowAll() bool {
|
||||||
|
return gobool(C.gtk_app_chooser_widget_get_show_all(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetShowAll() is a wrapper around gtk_app_chooser_widget_set_show_all().
|
||||||
|
func (v *AppChooserWidget) SetShowAll(setting bool) {
|
||||||
|
C.gtk_app_chooser_widget_set_show_all(v.native(), gbool(setting))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultText() is a wrapper around gtk_app_chooser_widget_get_default_text().
|
||||||
|
// In case when gtk_app_chooser_widget_get_default_text() returns a nil string,
|
||||||
|
// GetDefaultText() returns a non-nil error.
|
||||||
|
func (v *AppChooserWidget) GetDefaultText() (string, error) {
|
||||||
|
cstr := C.gtk_app_chooser_widget_get_default_text(v.native())
|
||||||
|
if cstr == nil {
|
||||||
|
return "", nilPtrErr
|
||||||
|
}
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
return C.GoString((*C.char)(cstr)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaultText() is a wrapper around gtk_app_chooser_widget_set_default_text().
|
||||||
|
func (v *AppChooserWidget) SetDefaultText(text string) {
|
||||||
|
cstr := C.CString(text)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_app_chooser_widget_set_default_text(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GtkAppChooserDialog
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AppChooserDialog is a representation of GTK's GtkAppChooserDialog.
|
||||||
|
type AppChooserDialog struct {
|
||||||
|
Dialog
|
||||||
|
|
||||||
|
// Interfaces
|
||||||
|
AppChooser
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GtkAppChooserButton.
|
||||||
|
func (v *AppChooserDialog) native() *C.GtkAppChooserDialog {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p := unsafe.Pointer(v.GObject)
|
||||||
|
return C.toGtkAppChooserDialog(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalAppChooserDialog(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
return wrapAppChooserDialog(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapAppChooserDialog(obj *glib.Object) *AppChooserDialog {
|
||||||
|
dialog := wrapDialog(obj)
|
||||||
|
ac := wrapAppChooser(obj)
|
||||||
|
return &AppChooserDialog{*dialog, *ac}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Uncomment when gio builds successfully
|
||||||
|
// AppChooserDialogNew() is a wrapper around gtk_app_chooser_dialog_new().
|
||||||
|
// func AppChooserDialogNew(parent *Window, flags DialogFlags, file *gio.File) (*AppChooserDialog, error) {
|
||||||
|
// var gfile *C.GFile
|
||||||
|
// if file != nil {
|
||||||
|
// gfile = (*C.GFile)(unsafe.Pointer(file.Native()))
|
||||||
|
// }
|
||||||
|
// c := C.gtk_app_chooser_dialog_new(parent.native(), C.GtkDialogFlags(flags), gfile)
|
||||||
|
// if c == nil {
|
||||||
|
// return nil, nilPtrErr
|
||||||
|
// }
|
||||||
|
// return wrapAppChooserDialog(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// AppChooserDialogNewForContentType() is a wrapper around gtk_app_chooser_dialog_new_for_content_type().
|
||||||
|
func AppChooserDialogNewForContentType(parent *Window, flags DialogFlags, content_type string) (*AppChooserDialog, error) {
|
||||||
|
cstr := C.CString(content_type)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
c := C.gtk_app_chooser_dialog_new_for_content_type(parent.native(), C.GtkDialogFlags(flags), (*C.gchar)(cstr))
|
||||||
|
if c == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
return wrapAppChooserDialog(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWidget() is a wrapper around gtk_app_chooser_dialog_get_widget().
|
||||||
|
func (v *AppChooserDialog) GetWidget() *AppChooserWidget {
|
||||||
|
c := C.gtk_app_chooser_dialog_get_widget(v.native())
|
||||||
|
return wrapAppChooserWidget(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeading() is a wrapper around gtk_app_chooser_dialog_get_heading().
|
||||||
|
// In case when gtk_app_chooser_dialog_get_heading() returns a nil string,
|
||||||
|
// GetHeading() returns a non-nil error.
|
||||||
|
func (v *AppChooserDialog) GetHeading() (string, error) {
|
||||||
|
cstr := C.gtk_app_chooser_dialog_get_heading(v.native())
|
||||||
|
if cstr == nil {
|
||||||
|
return "", nilPtrErr
|
||||||
|
}
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
return C.GoString((*C.char)(cstr)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHeading() is a wrapper around gtk_app_chooser_dialog_set_heading().
|
||||||
|
func (v *AppChooserDialog) SetHeading(heading string) {
|
||||||
|
cstr := C.CString(heading)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.gtk_app_chooser_dialog_set_heading(v.native(), (*C.gchar)(cstr))
|
||||||
|
}
|
@ -0,0 +1,156 @@
|
|||||||
|
// Same copyright and license as the rest of the files in this project
|
||||||
|
// This file contains style related functions and structures
|
||||||
|
|
||||||
|
package gtk
|
||||||
|
|
||||||
|
// #include <gtk/gtk.h>
|
||||||
|
// #include "gtk.go.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApplicationInhibitFlags is a representation of GTK's GtkApplicationInhibitFlags.
|
||||||
|
type ApplicationInhibitFlags int
|
||||||
|
|
||||||
|
const (
|
||||||
|
APPLICATION_INHIBIT_LOGOUT ApplicationInhibitFlags = C.GTK_APPLICATION_INHIBIT_LOGOUT
|
||||||
|
APPLICATION_INHIBIT_SWITCH ApplicationInhibitFlags = C.GTK_APPLICATION_INHIBIT_SWITCH
|
||||||
|
APPLICATION_INHIBIT_SUSPEND ApplicationInhibitFlags = C.GTK_APPLICATION_INHIBIT_SUSPEND
|
||||||
|
APPLICATION_INHIBIT_IDLE ApplicationInhibitFlags = C.GTK_APPLICATION_INHIBIT_IDLE
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GtkApplication
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Application is a representation of GTK's GtkApplication.
|
||||||
|
type Application struct {
|
||||||
|
glib.Application
|
||||||
|
}
|
||||||
|
|
||||||
|
// native returns a pointer to the underlying GtkApplication.
|
||||||
|
func (v *Application) native() *C.GtkApplication {
|
||||||
|
if v == nil || v.GObject == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return C.toGtkApplication(unsafe.Pointer(v.GObject))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalApplication(p uintptr) (interface{}, error) {
|
||||||
|
c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p)))
|
||||||
|
obj := wrapObject(unsafe.Pointer(c))
|
||||||
|
return wrapApplication(obj), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapApplication(obj *glib.Object) *Application {
|
||||||
|
return &Application{glib.Application{obj}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicationNew is a wrapper around gtk_application_new().
|
||||||
|
func ApplicationNew(appId string, flags glib.ApplicationFlags) (*Application, error) {
|
||||||
|
cstr := (*C.gchar)(C.CString(appId))
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
|
||||||
|
c := C.gtk_application_new(cstr, C.GApplicationFlags(flags))
|
||||||
|
if c == nil {
|
||||||
|
return nil, nilPtrErr
|
||||||
|
}
|
||||||
|
return wrapApplication(wrapObject(unsafe.Pointer(c))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddWindow is a wrapper around gtk_application_add_window().
|
||||||
|
func (v *Application) AddWindow(w *Window) {
|
||||||
|
C.gtk_application_add_window(v.native(), w.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveWindow is a wrapper around gtk_application_remove_window().
|
||||||
|
func (v *Application) RemoveWindow(w *Window) {
|
||||||
|
C.gtk_application_remove_window(v.native(), w.native())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWindowByID is a wrapper around gtk_application_get_window_by_id().
|
||||||
|
func (v *Application) GetWindowByID(id uint) *Window {
|
||||||
|
c := C.gtk_application_get_window_by_id(v.native(), C.guint(id))
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapWindow(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetActiveWindow is a wrapper around gtk_application_get_active_window().
|
||||||
|
func (v *Application) GetActiveWindow() *Window {
|
||||||
|
c := C.gtk_application_get_active_window(v.native())
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return wrapWindow(wrapObject(unsafe.Pointer(c)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uninhibit is a wrapper around gtk_application_uninhibit().
|
||||||
|
func (v *Application) Uninhibit(cookie uint) {
|
||||||
|
C.gtk_application_uninhibit(v.native(), C.guint(cookie))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAppMenu is a wrapper around gtk_application_get_app_menu().
|
||||||
|
func (v *Application) GetAppMenu() *glib.MenuModel {
|
||||||
|
c := C.gtk_application_get_app_menu(v.native())
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &glib.MenuModel{wrapObject(unsafe.Pointer(c))}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAppMenu is a wrapper around gtk_application_set_app_menu().
|
||||||
|
func (v *Application) SetAppMenu(m *glib.MenuModel) {
|
||||||
|
mptr := (*C.GMenuModel)(unsafe.Pointer(m.Native()))
|
||||||
|
C.gtk_application_set_app_menu(v.native(), mptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMenubar is a wrapper around gtk_application_get_menubar().
|
||||||
|
func (v *Application) GetMenubar() *glib.MenuModel {
|
||||||
|
c := C.gtk_application_get_menubar(v.native())
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &glib.MenuModel{wrapObject(unsafe.Pointer(c))}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMenubar is a wrapper around gtk_application_set_menubar().
|
||||||
|
func (v *Application) SetMenubar(m *glib.MenuModel) {
|
||||||
|
mptr := (*C.GMenuModel)(unsafe.Pointer(m.Native()))
|
||||||
|
C.gtk_application_set_menubar(v.native(), mptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInhibited is a wrapper around gtk_application_is_inhibited().
|
||||||
|
func (v *Application) IsInhibited(flags ApplicationInhibitFlags) bool {
|
||||||
|
return gobool(C.gtk_application_is_inhibited(v.native(), C.GtkApplicationInhibitFlags(flags)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inhibited is a wrapper around gtk_application_inhibit().
|
||||||
|
func (v *Application) Inhibited(w *Window, flags ApplicationInhibitFlags, reason string) uint {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(reason))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
return uint(C.gtk_application_inhibit(v.native(), w.native(), C.GtkApplicationInhibitFlags(flags), cstr1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// void gtk_application_add_accelerator () // deprecated and uses a gvariant paramater
|
||||||
|
// void gtk_application_remove_accelerator () // deprecated and uses a gvariant paramater
|
||||||
|
|
||||||
|
// GetWindows is a wrapper around gtk_application_get_windows().
|
||||||
|
// Returned list is wrapped to return *gtk.Window elements.
|
||||||
|
func (v *Application) GetWindows() *glib.List {
|
||||||
|
glist := C.gtk_application_get_windows(v.native())
|
||||||
|
list := glib.WrapList(uintptr(unsafe.Pointer(glist)))
|
||||||
|
list.DataWrapper(func(ptr unsafe.Pointer) interface{} {
|
||||||
|
return wrapWindow(wrapObject(ptr))
|
||||||
|
})
|
||||||
|
runtime.SetFinalizer(list, func(l *glib.List) {
|
||||||
|
l.Free()
|
||||||
|
})
|
||||||
|
return list
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
// +build !gtk_3_6,!gtk_3_8,!gtk_3_10
|
||||||
|
|
||||||
|
// See: https://developer.gnome.org/gtk3/3.12/api-index-3-12.html
|
||||||
|
|
||||||
|
package gtk
|
||||||
|
|
||||||
|
// #include <gtk/gtk.h>
|
||||||
|
// #include "gtk.go.h"
|
||||||
|
import "C"
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
// GetAccelsForAction is a wrapper around gtk_application_get_accels_for_action().
|
||||||
|
func (v *Application) GetAccelsForAction(act string) []string {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(act))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
var descs []string
|
||||||
|
c := C.gtk_application_get_accels_for_action(v.native(), cstr1)
|
||||||
|
originalc := c
|
||||||
|
defer C.g_strfreev(originalc)
|
||||||
|
|
||||||
|
for *c != nil {
|
||||||
|
descs = append(descs, C.GoString((*C.char)(*c)))
|
||||||
|
c = C.next_gcharptr(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return descs
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAccelsForAction is a wrapper around gtk_application_set_accels_for_action().
|
||||||
|
func (v *Application) SetAccelsForAction(act string, accels []string) {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(act))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
caccels := C.make_strings(C.int(len(accels) + 1))
|
||||||
|
defer C.destroy_strings(caccels)
|
||||||
|
|
||||||
|
for i, accel := range accels {
|
||||||
|
cstr := C.CString(accel)
|
||||||
|
defer C.free(unsafe.Pointer(cstr))
|
||||||
|
C.set_string(caccels, C.int(i), (*C.gchar)(cstr))
|
||||||
|
}
|
||||||
|
|
||||||
|
C.set_string(caccels, C.int(len(accels)), nil)
|
||||||
|
|
||||||
|
C.gtk_application_set_accels_for_action(v.native(), cstr1, caccels)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListActionDescriptions is a wrapper around gtk_application_list_action_descriptions().
|
||||||
|
func (v *Application) ListActionDescriptions() []string {
|
||||||
|
var descs []string
|
||||||
|
c := C.gtk_application_list_action_descriptions(v.native())
|
||||||
|
originalc := c
|
||||||
|
defer C.g_strfreev(originalc)
|
||||||
|
|
||||||
|
for *c != nil {
|
||||||
|
descs = append(descs, C.GoString((*C.char)(*c)))
|
||||||
|
c = C.next_gcharptr(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return descs
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
// +build !gtk_3_6,!gtk_3_8,!gtk_3_10,!gtk_3_12
|
||||||
|
|
||||||
|
// See: https://developer.gnome.org/gtk3/3.14/api-index-3-14.html
|
||||||
|
|
||||||
|
package gtk
|
||||||
|
|
||||||
|
// #include <gtk/gtk.h>
|
||||||
|
// #include "gtk.go.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PrefersAppMenu is a wrapper around gtk_application_prefers_app_menu().
|
||||||
|
func (v *Application) PrefersAppMenu() bool {
|
||||||
|
return gobool(C.gtk_application_prefers_app_menu(v.native()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetActionsForAccel is a wrapper around gtk_application_get_actions_for_accel().
|
||||||
|
func (v *Application) GetActionsForAccel(acc string) []string {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(acc))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
var acts []string
|
||||||
|
c := C.gtk_application_get_actions_for_accel(v.native(), cstr1)
|
||||||
|
originalc := c
|
||||||
|
defer C.g_strfreev(originalc)
|
||||||
|
|
||||||
|
for *c != nil {
|
||||||
|
acts = append(acts, C.GoString((*C.char)(*c)))
|
||||||
|
c = C.next_gcharptr(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acts
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMenuByID is a wrapper around gtk_application_get_menu_by_id().
|
||||||
|
func (v *Application) GetMenuByID(id string) *glib.Menu {
|
||||||
|
cstr1 := (*C.gchar)(C.CString(id))
|
||||||
|
defer C.free(unsafe.Pointer(cstr1))
|
||||||
|
|
||||||
|
c := C.gtk_application_get_menu_by_id(v.native(), cstr1)
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &glib.Menu{glib.MenuModel{wrapObject(unsafe.Pointer(c))}}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue