mirror of
https://github.com/diamondburned/cchat-gtk.git
synced 2024-10-31 19:44:23 +00:00
fixed hidpi for some images
This commit is contained in:
parent
cda40a58ee
commit
999432a481
2
go.mod
2
go.mod
|
@ -2,7 +2,7 @@ module github.com/diamondburned/cchat-gtk
|
||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
replace github.com/gotk3/gotk3 => github.com/diamondburned/gotk3 v0.0.0-20201209182406-e7291341a091
|
replace github.com/gotk3/gotk3 => github.com/diamondburned/gotk3 v0.0.0-20201225074909-7bf1378bcba4
|
||||||
|
|
||||||
//replace github.com/diamondburned/cchat-discord => ../cchat-discord
|
//replace github.com/diamondburned/cchat-discord => ../cchat-discord
|
||||||
|
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -64,6 +64,12 @@ github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db h1:VQI2Pd
|
||||||
github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db/go.mod h1:M87kjNzWVPlkZycFNzpGPKQXzkHNnZphuwMf3E9ckgc=
|
github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db/go.mod h1:M87kjNzWVPlkZycFNzpGPKQXzkHNnZphuwMf3E9ckgc=
|
||||||
github.com/diamondburned/gotk3 v0.0.0-20201209182406-e7291341a091 h1:lQpSWzbi3rQf66aMSip/rIypasIFwqCqF0Wfn5og6gw=
|
github.com/diamondburned/gotk3 v0.0.0-20201209182406-e7291341a091 h1:lQpSWzbi3rQf66aMSip/rIypasIFwqCqF0Wfn5og6gw=
|
||||||
github.com/diamondburned/gotk3 v0.0.0-20201209182406-e7291341a091/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
|
github.com/diamondburned/gotk3 v0.0.0-20201209182406-e7291341a091/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
|
||||||
|
github.com/diamondburned/gotk3 v0.0.0-20201221055621-194e73aef9d5 h1:3mjkpXdjWoPN9sIRJeoNfJ/d8TbAzu4pVArO/0vRVZQ=
|
||||||
|
github.com/diamondburned/gotk3 v0.0.0-20201221055621-194e73aef9d5/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
|
||||||
|
github.com/diamondburned/gotk3 v0.0.0-20201221091325-c5152a10909f h1:Lnrq+vXBgzbdiptxglDHhPf3kVLgLqcCGOJ7Ai3n/tc=
|
||||||
|
github.com/diamondburned/gotk3 v0.0.0-20201221091325-c5152a10909f/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
|
||||||
|
github.com/diamondburned/gotk3 v0.0.0-20201225074909-7bf1378bcba4 h1:KvlmpqxLoXKg+j5uiJWZXhacfgPg4fi/8wLecWX+XlE=
|
||||||
|
github.com/diamondburned/gotk3 v0.0.0-20201225074909-7bf1378bcba4/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
|
||||||
github.com/diamondburned/gspell v0.0.0-20200830182722-77e5d27d6894 h1:QgI21deaQbCUMnxKkQQUXzQolnAe1dMIXAWwqAyOp2g=
|
github.com/diamondburned/gspell v0.0.0-20200830182722-77e5d27d6894 h1:QgI21deaQbCUMnxKkQQUXzQolnAe1dMIXAWwqAyOp2g=
|
||||||
github.com/diamondburned/gspell v0.0.0-20200830182722-77e5d27d6894/go.mod h1:IoyMxPKSJOMoP0BiBuFwf2RDMeA4Uqx0HPKN5BzqTtA=
|
github.com/diamondburned/gspell v0.0.0-20200830182722-77e5d27d6894/go.mod h1:IoyMxPKSJOMoP0BiBuFwf2RDMeA4Uqx0HPKN5BzqTtA=
|
||||||
github.com/diamondburned/handy v0.0.0-20200829011954-4667e7a918f4 h1:qF5VHC35+GyCjUmKz+1O94xpFc0JQd4Ui3h+I955pJw=
|
github.com/diamondburned/handy v0.0.0-20200829011954-4667e7a918f4 h1:qF5VHC35+GyCjUmKz+1O94xpFc0JQd4Ui3h+I955pJw=
|
||||||
|
|
|
@ -9,7 +9,9 @@ import (
|
||||||
"github.com/diamondburned/cchat-gtk/internal/log"
|
"github.com/diamondburned/cchat-gtk/internal/log"
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives"
|
||||||
"github.com/diamondburned/imgutil"
|
"github.com/diamondburned/imgutil"
|
||||||
|
"github.com/gotk3/gotk3/cairo"
|
||||||
"github.com/gotk3/gotk3/gdk"
|
"github.com/gotk3/gotk3/gdk"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,7 +25,29 @@ type ImageContainer interface {
|
||||||
GetSizeRequest() (w, h int)
|
GetSizeRequest() (w, h int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsyncImage loads an image. This method uses the cache.
|
type SurfaceContainer interface {
|
||||||
|
ImageContainer
|
||||||
|
GetScaleFactor() int
|
||||||
|
SetFromSurface(*cairo.Surface)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ ImageContainer = (*gtk.Image)(nil)
|
||||||
|
_ SurfaceContainer = (*gtk.Image)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
type surfaceWrapper struct {
|
||||||
|
SurfaceContainer
|
||||||
|
scale int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wrapper surfaceWrapper) SetFromPixbuf(pb *gdk.Pixbuf) {
|
||||||
|
surface, _ := gdk.CairoSurfaceCreateFromPixbuf(pb, wrapper.scale, nil)
|
||||||
|
wrapper.SetFromSurface(surface)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsyncImage loads an image. This method uses the cache. It prefers loading
|
||||||
|
// SetFromSurface over SetFromPixbuf, but will fallback if needed be.
|
||||||
func AsyncImage(ctx context.Context,
|
func AsyncImage(ctx context.Context,
|
||||||
img ImageContainer, url string, procs ...imgutil.Processor) {
|
img ImageContainer, url string, procs ...imgutil.Processor) {
|
||||||
|
|
||||||
|
@ -31,9 +55,19 @@ func AsyncImage(ctx context.Context,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = primitives.HandleDestroyCtx(ctx, img)
|
|
||||||
|
|
||||||
gif := strings.Contains(url, ".gif")
|
gif := strings.Contains(url, ".gif")
|
||||||
|
scale := 1
|
||||||
|
|
||||||
|
surfaceContainer, canSurface := img.(SurfaceContainer)
|
||||||
|
|
||||||
|
if canSurface = canSurface && !gif; canSurface {
|
||||||
|
// Only bother with this API if we even have HiDPI.
|
||||||
|
if scale = surfaceContainer.GetScaleFactor(); scale > 1 {
|
||||||
|
img = surfaceWrapper{surfaceContainer, scale}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = primitives.HandleDestroyCtx(ctx, img)
|
||||||
|
|
||||||
l, err := gdk.PixbufLoaderNew()
|
l, err := gdk.PixbufLoaderNew()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -41,27 +75,19 @@ func AsyncImage(ctx context.Context,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if w, h := img.GetSizeRequest(); w > 0 && h > 0 {
|
w, h := img.GetSizeRequest()
|
||||||
l.Connect("size-prepared", func(l *gdk.PixbufLoader, imgW, imgH int) {
|
l.Connect("size-prepared", func(l *gdk.PixbufLoader, imgW, imgH int) {
|
||||||
w, h = imgutil.MaxSize(imgW, imgH, w, h)
|
w, h = imgutil.MaxSize(imgW, imgH, w, h)
|
||||||
if w != imgW || h != imgH {
|
if w != imgW || h != imgH || scale > 1 {
|
||||||
l.SetSize(w, h)
|
l.SetSize(w*scale, h*scale)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
l.Connect("area-prepared", areaPreparedFn(ctx, img, gif))
|
l.Connect("area-prepared", areaPreparedFn(ctx, img, gif))
|
||||||
|
|
||||||
go syncImage(ctx, l, url, procs, gif)
|
go downloadImage(ctx, l, url, procs, gif)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func connectDestroyer(img ImageContainer, cancel func()) {
|
|
||||||
// img.Connect("destroy", func() {
|
|
||||||
// cancel()
|
|
||||||
// img.SetFromPixbuf(nil)
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
func areaPreparedFn(ctx context.Context, img ImageContainer, gif bool) func(l *gdk.PixbufLoader) {
|
func areaPreparedFn(ctx context.Context, img ImageContainer, gif bool) func(l *gdk.PixbufLoader) {
|
||||||
return func(l *gdk.PixbufLoader) {
|
return func(l *gdk.PixbufLoader) {
|
||||||
if !gif {
|
if !gif {
|
||||||
|
@ -90,9 +116,9 @@ func execIfCtx(ctx context.Context, fn func()) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncImage(ctx context.Context, l io.WriteCloser, url string, p []imgutil.Processor, gif bool) {
|
func downloadImage(ctx context.Context, dst io.WriteCloser, url string, p []imgutil.Processor, gif bool) {
|
||||||
// Close at the end when done.
|
// Close at the end when done.
|
||||||
defer l.Close()
|
defer dst.Close()
|
||||||
|
|
||||||
r, err := get(ctx, url, true)
|
r, err := get(ctx, url, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -104,13 +130,13 @@ func syncImage(ctx context.Context, l io.WriteCloser, url string, p []imgutil.Pr
|
||||||
// If we have processors, then write directly in there.
|
// If we have processors, then write directly in there.
|
||||||
if len(p) > 0 {
|
if len(p) > 0 {
|
||||||
if !gif {
|
if !gif {
|
||||||
err = imgutil.ProcessStream(l, r.Body, p)
|
err = imgutil.ProcessStream(dst, r.Body, p)
|
||||||
} else {
|
} else {
|
||||||
err = imgutil.ProcessAnimationStream(l, r.Body, p)
|
err = imgutil.ProcessAnimationStream(dst, r.Body, p)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Else, directly copy the body over.
|
// Else, directly copy the body over.
|
||||||
_, err = io.Copy(l, r.Body)
|
_, err = io.Copy(dst, r.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
8
internal/gts/httputil/nopwriter.go
Normal file
8
internal/gts/httputil/nopwriter.go
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package httputil
|
||||||
|
|
||||||
|
type nopWriterImpl struct{}
|
||||||
|
|
||||||
|
var nopWriter = nopWriterImpl{}
|
||||||
|
|
||||||
|
func (nopWriterImpl) Write(b []byte) (int, error) { return len(b), nil }
|
||||||
|
func (nopWriterImpl) Close() error { return nil }
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu"
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu"
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage"
|
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage"
|
||||||
"github.com/diamondburned/cchat-gtk/internal/ui/rich/labeluri"
|
"github.com/diamondburned/cchat-gtk/internal/ui/rich/labeluri"
|
||||||
|
"github.com/gotk3/gotk3/cairo"
|
||||||
"github.com/gotk3/gotk3/gtk"
|
"github.com/gotk3/gotk3/gtk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ type FullMessage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AvatarPixbufCopier interface {
|
type AvatarPixbufCopier interface {
|
||||||
CopyAvatarPixbuf(img httputil.ImageContainer)
|
CopyAvatarPixbuf(img httputil.SurfaceContainer)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -148,12 +149,15 @@ func (m *FullMessage) UpdateAuthor(author cchat.Author) {
|
||||||
|
|
||||||
// CopyAvatarPixbuf sets the pixbuf into the given container. This shares the
|
// CopyAvatarPixbuf sets the pixbuf into the given container. This shares the
|
||||||
// same pixbuf, but gtk.Image should take its own reference from the pixbuf.
|
// same pixbuf, but gtk.Image should take its own reference from the pixbuf.
|
||||||
func (m *FullMessage) CopyAvatarPixbuf(dst httputil.ImageContainer) {
|
func (m *FullMessage) CopyAvatarPixbuf(dst httputil.SurfaceContainer) {
|
||||||
switch img := m.Avatar.Image; img.GetImage().GetStorageType() {
|
switch img := m.Avatar.Image.GetImage(); img.GetStorageType() {
|
||||||
case gtk.IMAGE_PIXBUF:
|
case gtk.IMAGE_PIXBUF:
|
||||||
dst.SetFromPixbuf(img.GetPixbuf())
|
dst.SetFromPixbuf(img.GetPixbuf())
|
||||||
case gtk.IMAGE_ANIMATION:
|
case gtk.IMAGE_ANIMATION:
|
||||||
dst.SetFromAnimation(img.GetAnimation())
|
dst.SetFromAnimation(img.GetAnimation())
|
||||||
|
case gtk.IMAGE_SURFACE:
|
||||||
|
v, _ := img.GetProperty("surface")
|
||||||
|
dst.SetFromSurface(v.(*cairo.Surface))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +191,7 @@ func NewFullSendingMessage(msg input.PresendMessage) *FullSendingMessage {
|
||||||
|
|
||||||
type Avatar struct {
|
type Avatar struct {
|
||||||
roundimage.Button
|
roundimage.Button
|
||||||
image *roundimage.StaticImage
|
Image *roundimage.StaticImage
|
||||||
url string
|
url string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +220,7 @@ func (a *Avatar) SetURL(url string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
a.url = url
|
a.url = url
|
||||||
a.image.SetImageURL(url)
|
a.Image.SetImageURL(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ManuallySetURL sets the URL without downloading the image. It assumes the
|
// ManuallySetURL sets the URL without downloading the image. It assumes the
|
||||||
|
|
|
@ -167,6 +167,7 @@ func MenuItem(label string, fn interface{}) *gtk.MenuItem {
|
||||||
|
|
||||||
type Connector interface {
|
type Connector interface {
|
||||||
Connect(string, interface{}, ...interface{}) (glib.SignalHandle, error)
|
Connect(string, interface{}, ...interface{}) (glib.SignalHandle, error)
|
||||||
|
ConnectAfter(string, interface{}, ...interface{}) (glib.SignalHandle, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleDestroyCtx(ctx context.Context, connector Connector) context.Context {
|
func HandleDestroyCtx(ctx context.Context, connector Connector) context.Context {
|
||||||
|
|
|
@ -60,6 +60,19 @@ func NewImage(radius float64) (*Image, error) {
|
||||||
// Connect to the draw callback and clip the context.
|
// Connect to the draw callback and clip the context.
|
||||||
i.Connect("draw", image.drawer)
|
i.Connect("draw", image.drawer)
|
||||||
|
|
||||||
|
// Backup plan if Cairo's Surface is weird.
|
||||||
|
|
||||||
|
// var width, height int
|
||||||
|
// i.Connect("size-allocate", func() {
|
||||||
|
// w := i.GetAllocatedWidth()
|
||||||
|
// h := i.GetAllocatedHeight()
|
||||||
|
|
||||||
|
// if width != w || height != h {
|
||||||
|
// log.Println("Image allocate", width, height, i.GetScaleFactor())
|
||||||
|
// width, height = w, h
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
return image, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue