/
lookup.go
164 lines (137 loc) · 4.17 KB
/
lookup.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package main
/*
#include <stdlib.h>
#include <gtk/gtk.h>
#cgo pkg-config: gtk+-2.0
gint iter_array(gint **array) {
return *((*array)++);
}
*/
import "C"
import (
"errors"
"strings"
"unsafe"
)
// GTKTheme is a simple wrapper around the C GTKIconTheme struct.
type GTKTheme struct {
name string
theme *C.GtkIconTheme
}
// GTKIconProperties represents the properties of an icon.
type GTKIconProperties struct {
// The sizes in which this icon is available.
Sizes []uint
// Whether or not the icon has a scalable form.
Scalable bool
// The name of the icon.
Name string
// The category of this icon (apps, emblems, etc.)
Category string
}
// GTKInit call gtk_init with the given program arguments.
func GTKInit(args []string) {
// Convert the args to C args.
argc := C.int(len(args))
argv := make([]*C.char, argc)
// Convert each argument.
for i := 0; i < len(args); i++ {
argv[i] = C.CString(args[i])
defer C.free(unsafe.Pointer(argv[i]))
}
// Init GTK.
argvPtr := (**C.char)(unsafe.Pointer(&argv[0]))
C.gtk_init(&argc, &argvPtr)
}
// CreateTheme creates a new GtkIconTheme and sets it to the given theme name.
func CreateTheme(name string) GTKTheme {
// Create a new blank theme.
var t GTKTheme
t.name = name
t.theme = C.gtk_icon_theme_new()
// Load the given theme name.
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
C.gtk_icon_theme_set_custom_theme(t.theme, (*C.gchar)(cName))
return t
}
// GetIcon takes the name of an icon and a size as arguments. It returns the closest
// matching icon file from the theme.
func (t GTKTheme) GetIcon(name string, size int) string {
// TODO: User-specified flags.
var flags C.GtkIconLookupFlags
// Lookup the icon.
cName := C.CString(name)
defer C.free(unsafe.Pointer(cName))
iconInfo := C.gtk_icon_theme_lookup_icon(t.theme, (*C.gchar)(cName), C.gint(size), flags)
// Check the lookup was successful.
if iconInfo == nil {
return ""
}
// gtk_icon_info_free is deprecated, but we seem to have issues using g_object_unref.
defer C.gtk_icon_info_free(iconInfo)
//defer C.g_object_unref(C.gpointer(iconInfo))
// Check the icon's filename.
cFilename := C.gtk_icon_info_get_filename(iconInfo)
if cFilename == nil {
return ""
}
filename := C.GoString((*C.char)(cFilename))
return filename
}
// Returns all the icons in the theme, including inherited and hicolor icons.
func (t GTKTheme) GetAllIcons() []string {
// Get the list of all icons in this theme.
out := make([]string, 0)
list := C.gtk_icon_theme_list_icons(t.theme, nil)
defer C.g_list_free(list)
// Convert the list into a slice, freeing used elements as we go.
for ptr := list; ptr != nil; ptr = ptr.next {
out = append(out, C.GoString((*C.char)(ptr.data)))
C.g_free(ptr.data)
}
return out
}
// GetIconSizes gets the sizes an icon is available in and whether or not the icon has
// a scalable version.
func (t GTKTheme) GetIconSizes(icon string) (sizes []uint, isScalable bool) {
// Get the array of sizes.
cIcon := C.CString(icon)
defer C.free(unsafe.Pointer(cIcon))
cSizes := C.gtk_icon_theme_get_icon_sizes(t.theme, (*C.gchar)(cIcon))
defer C.g_free(C.gpointer(cSizes))
// Convert the data into Go types.
for i := C.iter_array(&cSizes); i != 0; i = C.iter_array(&cSizes) {
size := int(i)
if size == -1 {
isScalable = true
} else {
sizes = append(sizes, uint(size))
}
}
return
}
func getCategoryFromPath(path string) string {
// TODO: Do this much better.
if strings.Contains(path, "/usr/share/pixmaps") {
return "pixmaps"
}
parts := strings.Split(path, "/")
return parts[len(parts)-2]
}
// GetIconProperties attempts to determine all the properties of the given icon name.
func (t GTKTheme) GetIconProperties(icon string) (GTKIconProperties, error) {
// Check the icon is valid.
if t.GetIcon(icon, 16) == "" {
return GTKIconProperties{}, errors.New("Invalid icon name: " + icon)
}
// Record the name of the icon.
var properties GTKIconProperties
properties.Name = icon
// Get the available sizes from GTK.
properties.Sizes, properties.Scalable = t.GetIconSizes(icon)
// Deduce the category of the icon from the path name.
path := t.GetIcon(icon, 64)
properties.Category = getCategoryFromPath(path)
return properties, nil
}