Shallow Thoughts : tags : gtk3
Akkana's Musings on Open Source Computing and Technology, Science, and Nature.
Wed, 05 Jun 2019
Lately I've been running with my default python set to Python 3.
Debian still uses Python 2 as the default, which is reasonable, but
adding a ~/bin/python symlink to /usr/bin/python3
helps me preview scripts that might become a problem once Debian
does switch. I thought I had converted most of my Python scripts to
Python 3 already, but this link is catching some I didn't convert.
Python has a nice script called 2to3 that can convert the bulk
of most scripts with little fanfare.
The biggest hassles that 2to3 can't handle are network related
(urllib and urllib2) and, the big one, user interfaces.
PyGTK, based on GTK2 has no Python 3 equivalent; in Python 3,
the only option is to use GObject Introspection (gi) and
GTK3. Since there's almost no documentation on python-gi and gtk3,
converting a GTK script always involves a lot of fumbling and guesswork.
A few days ago I tried to play an MP3 in my little
musicplayer.py
script and discovered I'd never updated it. I have enough gi/GTK3 scripts
by now that I thought something with such a simple user interface
would be easy. Shows how much I know about GTK3!
I got the basic window ported pretty easily, but it looked terrible:
huge margins everywhere, and no styling on the text, like the bold,
large-sized text I had previously use to highlight the name of the
currently playing song. I tried various approaches, but a lot of the
old methods of styling have been deprecated in GTK3; you're supposed to
use CSS. Except, of course, there's no documentation on it, and it turns
out the CSS accepted by GTK3 is a tiny subset of the CSS you can use in
HTML pages, but what the subset is doesn't seem to be documented anywhere.
How to Apply a Stylesheet
The first task was to get any CSS at all working.
The
GNOME Journal: Styling GTK with CSS
was helpful in getting started, but had a lot of information that
doesn't work (perhaps it did once). At least it gave me this basic snippet:
css = '* { background-color: #f00; }'
css_provider = gtk.CssProvider()
css_provider.load_from_data(css)
context = gtk.StyleContext()
screen = Gdk.Screen.get_default()
context.add_provider_for_screen(screen, css_provider,
gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
Built-in Class Names
Great! if all you want to do is turn the whole app red.
But in reality, you'll want to style different widgets differently.
At least some classes have class names:
css = 'button { background-color: #f00; }'
I found other pages suggesting using
'GtkButton in CSS,
but that didn't work for me. How do you find the right class names?
No idea, I never found a reference for that. Just guess, I guess.
User-set Class Names
What about classes -- for instance, make all the buttons in a ButtonBox white?
You can add classes this way:
button_context = button.get_style_context()
button_context.add_class("whitebutton")
If you need to change a class (for instance, turn a red button green),
first remove the old class:
button_context = button.get_style_context()
entry_style_context.remove_class("red")
Widget Names, like CSS ID
For single widgets, you can give the widget a name and
use it like an ID in CSS. Like this:
label = gtk.Label()
label.set_use_markup(True)
label.set_line_wrap(True)
label.set_name("red_label")
mainbox.pack_start(label, False, False, 0)
css = '#red_label { background-color: #f00; }'
[ ... ]
Properties You Can Set
There is, amazingly, a page on
which
CSS properties GTK3 supports.
That page doesn't mention it, but some properties like :hover
are also supported. So you can write CSS tweaks like
.button { border-radius: 15; border-width: 2; border-style: outset; }
.button:hover { background: #dff; border-color: #8bb; }
And descendants work, so you can say somthing like
buttonbox = gtk.ButtonBox(spacing=4)
buttonbox.set_name("buttonbox")
mainbox.pack_end(buttonbox, False, False, 0)
btn = gtk.Button(label="A")
buttonbox.add(btn)
btn = gtk.Button(label="B")
buttonbox.add(btn)
and then use CSS that affects all the buttons inside the buttonbox:
#buttonbox button { color: red; }
No mixed CSS Inside Labels
My biggest disappointment was that I couldn't mix styles inside a label.
You can't do something like
label.set_label('Headline'
'Normal text')
and expect to style the different parts separately.
You can use very simple markup like
<b>bold</b> normal
,
but anything further gives errors like
"error parsing markup: Attribute 'class' is not allowed on the
<span> tag" (you'll get the same error if you try "id").
I had to make separate GtkLabels for each text size and style I wanted,
which is a lot more work. If you wanted to mix styles and have them
reflow as the content length changed, I don't know how (or if)
you could do it.
Fortunately, I don't strictly need that for this little app.
So for now, I'm happy to have gotten this much working.
Tags: programming, python, gtk, gtk3
[
14:49 Jun 05, 2019
More programming |
permalink to this entry |
]
Sun, 24 Dec 2017
Dave and I will be giving a planetarium talk in February
on the analemma and related matters.
Our planetarium, which runs a fiddly and rather limited program called
Nightshade, has no way of showing the analemma. Or at least, after
trying for nearly a week once, I couldn't find a way. But it can
show images, and since I once wrote a
Python
program to plot the analemma, I figured I could use my program
to generate the analemmas I wanted to show and then project them
as images onto the planetarium dome.
But naturally, I wanted to project just the analemma and
associated labels; I didn't want the blue background to
cover up the stars the planetarium shows. So I couldn't just use
a simple screenshot; I needed a way to get my GTK app to create a
transparent image such as a PNG.
That turns out to be hard. GTK can't do it (either GTK2 or GTK3),
and people wanting to do anything with transparency are nudged toward
the Cairo library. As a first step, I updated my analemma program to
use Cairo and GTK3 via gi.repository. Then I dove into Cairo.
I found one C solution for
converting
an existing Cairo surface to a PNG, but I didn't have much luck
with it. But I did find a
Python
program that draws to a PNG without bothering to create a GUI.
I could use that.
The important part of that program is where it creates a new Cairo
"surface", and then creates a "context" for that surface:
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, *imagesize)
cr = cairo.Context(surface)
A Cairo surface is like a canvas to draw on, and it knows how to
save itself to a PNG image.
A context is the equivalent of a GC in X11 programming:
it knows about the current color, font and so forth.
So the trick is to create a new surface, create a context,
then draw everything all over again with the new context and surface.
A Cairo widget will already have a function to draw everything
(in my case, the analemma and all its labels), with this signature:
def draw(self, widget, ctx):
It already allows passing the context in, so passing in a different
context is no problem. I added an argument specifying the background
color and transparency, so I could use a blue background in the user
interface but a transparent background for the PNG image:
def draw(self, widget, ctx, background=None):
I also had a minor hitch: in draw(), I was saving the context as
self.ctx rather than passing it around to every draw routine.
That means calling it with the saved image's context would overwrite
the one used for the GUI window. So I save it first.
Here's the final image saving code:
def save_image(self, outfile):
dst_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
self.width, self.height)
dst_ctx = cairo.Context(dst_surface)
# draw() will overwrite self.ctx, so save it first:
save_ctx = self.ctx
# Draw everything again to the new context,
# with a transparent instead of an opaque background:
self.draw(None, dst_ctx, (0, 0, 1, 0)) # transparent blue
# Restore the GUI context:
self.ctx = save_ctx
dst_surface.write_to_png("example.png")
print("Saved to", outfile)
Tags: programming, python, gtk, gtk3, graphics, analemma
[
19:39 Dec 24, 2017
More programming |
permalink to this entry |
]
Sat, 07 May 2016
I recently let Firefox upgrade itself to 46.0.1, and suddenly I
couldn't type anything any more. The emacs/readline editing bindings,
which I use probably thousands of times a day, no longer worked.
So every time I typed a Ctrl-H to delete the previous character,
or Ctrl-B to move back one character, a sidebar popped up.
When I typed Ctrl-W to delete the last word, it closed the tab.
Ctrl-U, to erase the contents of the urlbar, opened a new View Source
tab, while Ctrl-N, to go to the next line, opened a new window.
Argh!
(I know that people who don't use these bindings are rolling their
eyes and wondering "What's the big deal?" But if you're a touch typist,
once you've gotten used to being able to edit text without moving your
hands from the home position, it's hard to imagine why everyone else
seems content with key bindings that require you to move your
hands and eyes way over to keys like Backspace or Home/End that aren't
even in the same position on every keyboard. I map CapsLock to Ctrl
for the same reason, since my hands are too small to hit the
PC-positioned Ctrl key without moving my whole hand. Ctrl
was to the left of the "A" key on nearly all computer keyboards
until IBM's 1986 "101 Enhanced Keyboard", and it made a lot more
sense than IBM's redesign since few people use Caps Lock very often.)
I found a bug filed on the broken bindings, and lots of people
commenting online, but it wasn't until I found out that Firefox 46 had
switched to GTK3 that I understood had actually happened. And adding
gtk3 to my web searches finally put me on the track to finding the
solution, after trying several other supposed fixes that weren't.
Here's what actually worked: edit
~/.config/gtk-3.0/settings.ini
and add, inside the
[Settings]
section, this line:
gtk-key-theme-name = Emacs
I think that's all that was needed. But in case that doesn't do it,
here's something I had already tried, unsuccessfully,
and it's possible that you actually need it in addition to the
settings.ini change
(I don't know how to undo magic Gnome settings so I can't test it):
gsettings set org.gnome.desktop.interface gtk-key-theme "Emacs"
Tags: linux, gtk, gtk3, emacs, firefox
[
18:11 May 07, 2016
More linux |
permalink to this entry |
]