How to check gtk version in Vala? - gtk3

I am developing some Gtk based application using Vala. In my application I want to add some custom styles.
I want to retain my styles for both Gtk 3.20- and Gtk 3.20+ versions. As we are aware, Gtk3 has changed widget classes beginning from Gtk 3.20.
So, how can I check the gtk version and apply custom style accordingly? I know that, I can apply both styles together. But don't want to overload the app with unnecessary styles.
I'm looking for something like this
string style = null;
If (GTK_VERSION >= 3.20) {
style = "window {border : none}";
} else {
style = "GtkWindow {border : none}";
}

You can use Gtk.get_major_versoin() and Gtk.get_minor_version() for getting major and minor versions respectively.
string style = null;
if (((Gtk.get_major_version() * 100) + (Gtk.get_minor_version())) >= 320)
style = "window {border : none}";
} else {
style = "GtkWindow {border : none}";
}
Reference:
Gtk.get_major_version()
Gtk.get_minor_version()

Related

Sharing code between a GTK/GJS App and a Gnome Shell Extension

I am developing a GTK application in GJS and like to reuse parts of the GTK
code inside a Gnome Shell extension. However, I did not find a way to add a
Gtk.Widget to the menu of my Gnome Shell panel icon.
I tried to use GtkClutter.Actor from clutter-gtk, but the library seems to
be out-dated and does neither work in a Wayland or X11 Gnome Shell, since it
requires Clutter 1.0 but sees 7 already loaded. When importing
imports.gi.GtkClutter in an extension, Gnome Shell yields this error:
Requiring GtkClutter, version none: Requiring namespace 'Clutter' version '1.0', but '7' is already loaded.
Here is some code to demonstrate that clutter-gtk actually works, if directly
running it via gjs; probably because I can enforce GTK 3.0 here.
gtkclutter.js:
imports.gi.versions.Gtk = '3.0' // fails if set to 4.0
const { Gtk, GLib, Clutter, GtkClutter } = imports.gi
// gtkUI returns a Gtk.Widget tree. This should be the reusable code.
function gtkUI() {
return new Gtk.Label({
label: '<span size="100000">🎉</span>',
use_markup: true,
})
}
// embedClutterActor returns a Gtk.Widget with an embedded Clutter.Actor.
function embedClutterActor(clutter_actor) {
let embed = new GtkClutter.Embed()
embed.get_stage().add_child(clutter_actor)
return embed
}
// embedGtkWidget returns a Clutter.Actor with an embedded Gtk.Widget.
function embedGtkWidget(gtk_widget) {
return new GtkClutter.Actor({ contents: gtk_widget })
}
class App {
constructor() {
this.title = 'GtkClutter'
GLib.set_prgname(this.title)
}
onActivate() { this.window.show_all() }
onStartup() { this.buildUI() }
run(ARGV=[]) {
this.app = new Gtk.Application()
this.app.connect('activate', () => this.onActivate())
this.app.connect('startup', () => this.onStartup())
this.app.run(ARGV)
}
buildUI() {
let w = this.window = new Gtk.ApplicationWindow({
application: this.app, title: this.title, icon_name: 'face-smile',
default_height: 160, default_width: 160, window_position: Gtk.WindowPosition.CENTER,
})
// Just to demonstrate that GtkClutter embedding works, we use both embeds here to create
// a Gtk.Widget from a Clutter.Actor from the actual Gtk.Widget that we want to show.
GtkClutter.init(null)
Clutter.init(null)
w.add(embedClutterActor(embedGtkWidget(gtkUI())))
// In the actual GTK App, we would just have used `w.add(gtkUI())`
// and not imported Clutter and GtkClutter at all.
}
}
new App().run(ARGV)
Here is the companion extension to the GTK app, trying (and failing)
to reuse the GTK code as contents of a GtkClutter.Actor.
extension.js:
const { Clutter, Gtk, Gio, St } = imports.gi
let GtkClutter = null // lazy import for debugging
const Main = imports.ui.main
const PanelMenu = imports.ui.panelMenu
const PopupMenu = imports.ui.popupMenu
const Me = imports.misc.extensionUtils.getCurrentExtension()
const VERSION = 'dev-version' // filled during install
const NAME = 'GtkClutterExt'
// gtkUI returns a Gtk.Widget tree. This should be the reusable code.
function gtkUI() {
return new Gtk.Button({ child: Gtk.Label({
label: `<span size="100000">🎉</span>`,
use_markup: true,
})})
}
// stUI returns an Gnome Shell widget tree that works only in Gnome Shell.
function stUI(icon_name='face-sad') {
return new St.Icon({ icon_name })
}
function statusIcon(icon_name) {
let box = new St.BoxLayout()
let icon = new St.Icon({ icon_name, style_class: 'system-status-icon emotes-icon' })
box.add_child(icon)
box.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM))
return box
}
class Ext {
constructor() { this.panel_widget = null }
enable() {
log(`enabling extension ${Me.uuid}`)
try {
// Use St only for the status icon and the menu container (not the menu content).
let btn = this.panel_widget = new PanelMenu.Button(0.0, NAME, false)
let item = new PopupMenu.PopupBaseMenuItem({ reactive: false, can_focus: false })
btn.menu.addMenuItem(item)
Main.panel.addToStatusArea(NAME, btn)
try { GtkClutter = imports.gi.GtkClutter }
catch (e) { log(`failed to load clutter-gtk, err=${e.message}`) }
if (GtkClutter) {
// Using St for the status icon is OK, since it is only used by the extension.
btn.add_child(statusIcon('face-happy'))
// But for the menu, I like to reuse my GTK code from the GTK app.
// That is what GtkClutter was designed for, I believe.
item.actor.add_child(new GtkClutter.Actor({ contents: gtkUI() }))
} else {
// As fallback we show our mood regarding GtkClutter support in Gnome Shell ;)
btn.add_child(statusIcon('face-sad'))
item.actor.add_child(stUI('face-angry'))
}
} catch (e) {
log(`failed to enable ${Me.uuid}, err=${e.message}`)
}
}
disable() {
debug(`disabling extension ${Me.uuid}`)
if (this.panel_widget == null) return
this.panel_widget.destroy()
this.panel_widget = null
}
}
function init() { return new Ext() }
I know that clutter-gtk is quite dated (see https://gitlab.gnome.org/GNOME/clutter-gtk),
but I did not find a better way to lift GTK into my extension.
Questions
Does Gnome Shell provide something similar to GtkClutter.Actor that allows
extension programmers to reuse their GJS/GTK code?
Which alternative way to reuse GTK/GJS code do you see?
If GTK is such a universal and cross-platform library, why does Gnome Shell not
support it out-of-the box? (Bonus question 😉, more out of curiosity)
TL;DR You can not use GTK widgets in a GNOME Shell extension.
The toolkit used in GNOME Shell is Clutter, not GTK. Clutter is an internal library of Mutter, while GTK3 is only used in GNOME Shell for a handful of utilities.
Clutter used to be a standalone library, but is now developed specifically as a compositor toolkit for Mutter. GTK is an application toolkit, not suited for use in a compositor.
The standalone Clutter project is effectively unmaintained now, making GtkClutter pretty much the same.

Proper way to implement custom Css attribute with Itext and html2Pdf

I'm using Itext 7 and their html2Pdf lib.
Is there a way to implement for example cmyk colors.
.wootWorkingCMYK-color{
color: cmyk( 1 , 0.69 , 0.08 , 0.54);
}
I know the itext core part pretty good, looking for away to use the html2Pdf side. I'm aware of the CssApplierFactory but this seems to be to far up the chain.
Well, of course there is a way of processing custom CSS properties like cmyk colors, but unfortunately the code would be quite bulky and you will need to write quite some code for different cases. I will show how to apply custom color for font, but e.g. for backgrounds, borders or other cases you will need to write separate code in a similar way. Reason behind it is that iText layout structure, although designed with HTML/CSS in mind, is not 100% similar and has some differences you have to code around.
Having that said, if you can fork, build and use your custom version from sources, this is the way I would advice to go. Although it has drawbacks like having to rebase to get updates, the solution would be simpler and more generic. To do that, search for usages of CssUtils.parseRgbaColor in pdfHTML module, and you will find that it is used in BackgroundApplierUtil, BorderStyleApplierUtil, FontStyleApplierUtil, OutlineApplierUtil. There you will find code like
if (!CssConstants.TRANSPARENT.equals(cssColorPropValue)) {
float[] rgbaColor = CssUtils.parseRgbaColor(cssColorPropValue);
Color color = new DeviceRgb(rgbaColor[0], rgbaColor[1], rgbaColor[2]);
float opacity = rgbaColor[3];
transparentColor = new TransparentColor(color, opacity);
} else {
transparentColor = new TransparentColor(ColorConstants.BLACK, 0f);
}
Which I belive you can tweak to process cmyk as well, knowing that you know core part pretty well.
Now, the solution without custom pdfHTML version is to indeed start with implementing ICssApplierFactory, or subclassing default implementation DefaultCssApplierFactory. We are mostly interested in customizing implementation of SpanTagCssApplier and BlockCssApplier, but you can consult with DefaultTagCssApplierMapping to get the full list of appliers and cases they are used in, so that you can decide which of them you want to process in your code.
I will show you how to add support for custom color space for font color in the two main applier classes I mentioned and you can work from there.
private static class CustomCssApplierFactory implements ICssApplierFactory {
private static final ICssApplierFactory DEFAULT_FACTORY = new DefaultCssApplierFactory();
#Override
public ICssApplier getCssApplier(IElementNode tag) {
ICssApplier defaultApplier = DEFAULT_FACTORY.getCssApplier(tag);
if (defaultApplier instanceof SpanTagCssApplier) {
return new CustomSpanTagCssApplier();
} else if (defaultApplier instanceof BlockCssApplier) {
return new CustomBlockCssApplier();
} else {
return defaultApplier;
}
}
}
private static class CustomSpanTagCssApplier extends SpanTagCssApplier {
#Override
protected void applyChildElementStyles(IPropertyContainer element, Map<String, String> css, ProcessorContext context, IStylesContainer stylesContainer) {
super.applyChildElementStyles(element, css, context, stylesContainer);
String color = css.get("color2");
if (color != null) {
color = color.trim();
if (color.startsWith("cmyk")) {
element.setProperty(Property.FONT_COLOR, new TransparentColor(parseCmykColor(color)));
}
}
}
}
private static class CustomBlockCssApplier extends BlockCssApplier {
#Override
public void apply(ProcessorContext context, IStylesContainer stylesContainer, ITagWorker tagWorker) {
super.apply(context, stylesContainer, tagWorker);
IPropertyContainer container = tagWorker.getElementResult();
if (container != null) {
String color = stylesContainer.getStyles().get("color2");
if (color != null) {
color = color.trim();
if (color.startsWith("cmyk")) {
container.setProperty(Property.FONT_COLOR, new TransparentColor(parseCmykColor(color)));
}
}
}
}
}
// You might want a safer implementation with better handling of corner cases
private static DeviceCmyk parseCmykColor(String color) {
final String delim = "cmyk(), \t\r\n\f";
StringTokenizer tok = new StringTokenizer(color, delim);
float[] res = new float[]{0, 0, 0, 0};
for (int k = 0; k < 3; ++k) {
if (tok.hasMoreTokens()) {
res[k] = Float.parseFloat(tok.nextToken());
}
}
return new DeviceCmyk(res[0], res[1], res[2], res[3]);
}
Having that custom code, you should configure the ConverterProperties accordingly and pass it to HtmlConverter:
ConverterProperties properties = new ConverterProperties();
properties.setCssApplierFactory(new CustomCssApplierFactory());
HtmlConverter.convertToPdf(..., properties);
You might have noticed that I used color2 instead of color, and this is for a reason. pdfHTML has a mechanism of CSS property validation (as browsers do as well), to discard invalid CSS properties when calculating effective properties for an element. Unfortunately, there is no mechanism of customizing this validation logic currently and of course it treats cmyk colors as invalid declarations at the moment. Thus, if you really want to have custom color property, you will have to preprocess your HTML and replace declarations like color: cmyk... to color2: cmyk.. or whatever the property name you might want to use.
As I mentioned at the start of the answer, my recommendation is to build your own custom version :)

How to automatically color lines in IDA?

I want IDA to automatically color lines in both the graph and text view for important instructions, for example wherever there is a call or xor instruction change the background color of each of those references to a certain color.
Here is what I am looking to achieve:
fig.1 graph view
fig.2 text view
I noticed you can go to Edit > Other > color instruction... from the main menu and this will allow you to change the background color of the selected instruction, but this does not change all of them and seems to only affect the current database.
How can I make IDA automatically color certain instructions such as call and xoras shown from the example images?
I want it to automatically work for any database I open.
You need to write an IDA plug in using IDAPython (python for IDA) or IDC (IDA scripting language which is very similar to C), the following code is in IDC:
#include <idc.idc>
static main(void)
{
auto currentEA;
auto currentMnem;
auto prevMnem;
auto currentOp;
prevMnem = "";
currentOp;
currentEA = FirstSeg();
currentEA = NextHead(currentEA, 0xFFFFFFFF);
while (currentEA != BADADDR)
{
currentMnem = GetMnem(currentEA);
//Highlight call functions
if (currentMnem == "call")
{
SetColor(currentEA, CIC_ITEM, 0xc7c7ff);
}
}
}
You can also refer to the opcodes' operands:
//Non-zeroing XORs are often signs of data encoding
if (currentMnem == "xor")
{
if (GetOpnd(currentEA, 0) != GetOpnd(currentEA, 1))
{
SetColor(currentEA, CIC_ITEM, 0xFFFF00);
}
}
Here is a guide from Hex Blog for using IDC plug-ins.
And here is a sample for similar script in IDA Python instead of IDC.

How to get the background color of a widget in GTK and Python?

I want to get the normal background color of a widget (a GtkHeaderBar, in this case). I'm currently using
style = self.get_titlebar().get_style_context()
to get the style, and
color = style.get_property("background-color", Gtk.StateFlags.NORMAL)
to get the background color associated to that style.
However it returns a Gkd.RGBA object with the following properties:
Gdk.RGBA(red=0.000000, green=0.000000, blue=0.000000, alpha=0.000000)
But if I open GTK Inspector, select the HeaderBar, and goes to the style properties, it shows
background-color | rgb(57,63,63) | gtk-contained-dark.css:1568.29
What do I have to do to get these same values?
Edit:
I am experimenting with the GtkStyleContext.render_background(), but I'm having no success:
surfc = Cairo.ImageSurface (Cairo.FORMAT_ARGB32, 10, 10)
contx = Cairo.Context(surfc)
style = self.get_titlebar().get_style_context()
backg = Gtk.render_background(style, contx, 10, 10, 10, 10)
surfc.write_to_png("test.png")
The resulting file test.png is a rgba(0, 0, 0, 0) image.
You should have a look at modifying the background-color with css. There is a very good documentation of it. It can be used with python with
css_provider = Gtk.CssProvider()
css_provider.load_from_path('application.css')
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)
and a css file like:
GtkHeaderbar {
background-color:#theme_bg_color;
}
EDIT: As you commented you do not want to modify the background color but retrieve the value of it. You can do widget.get_style_context().get_background_color() and it will return something like Gdk.RGBA(red=0.913725, green=0.913725, blue=0.913725, alpha=1.000000).
However, you should note that get_background_color() is deprecated since there is not one background color. Some widget use a gradient as a background so it is not the best solution to use this method. See the documentation for reference.
If anyone's interested, I think the problem lies here:
backg = Gtk.render_background(style, contx, 10, 10, 10, 10)
while it should be:
backg = Gtk.render_background(style, contx, 0, 0, 10, 10)
You were on the right track, but there is an issue with new recommended way to get colors.
The recommended workaround
is to fall back to the deprecated get_background_color()
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
import sys
window = Gtk.Window()
context = window.get_style_context()
# this one is buggy
color1 = context.get_property("background-color", Gtk.StateFlags.NORMAL)
print(color1)
# this is the deprecated version, but it is the recommended workaround
color2 = context.get_background_color(Gtk.StateFlags.NORMAL)
print(color2)
From the python/Gtk documentation,
Note that passing a state other than the current state of self is not recommended unless the style context has been saved with Gtk.StyleContext.save()
So the current recommended way to get a widget background color is
context = widget.get_style_context()
color = context.get_background_color(widget.get_state())
Often self is a Gtk widget, and this becomes
context = self.get_style_context()
color = context.get_background_color(self.get_state())

GXT - How to set the grid cell background color

I want to change background color of a cell in GXT Grid, I am using GXT 3.0 .I have got one link which is related to my query( http://ui-programming.blogspot.in/2010/01/gxt-how-to-set-cell-grid-background.html) but setRenderer method is not present columnConfig in GXT 3.0 .How can i get desired output? pLz help.
Code i have done till now:-
ColumnConfig<Stock, Double> changeCol = new ColumnConfig<Stock, Double>(props.change(), 100, "Change");
changeCol.setCell(new AbstractCell<Double>() {
#Override
public void render(Context context, Double value, SafeHtmlBuilder sb) {
if (value == null) {
return;
}
store.get(context.getIndex());
GWT.log(DOM.getCaptureElement().getId());
String style = "style='background-color: " + (value < 0 ? "red" : "green") + "'";
String v = number.format(value);
sb.appendHtmlConstant("<span " + style + " qtitle='Change' qtip='" + v + "'>" + v + "</span>");
}
});
For those that need to change cell colour based on data in the grid, I've just had to do this (GXT 3.1) but unfortunately the solution isn't perfect.
In general, one can do custom cell rendering with ColumnConfig.setCell(MyCell) where 'MyCell' is a subclass of AbstractCell. Unfortunately there is the problem of 'padding' in the host 'div' which isn't coloured. There are a few ways around this...
The simplest way is to:
ColumnConfig.setCellPadding(false)
Render your own coloured divs that fill up the whole cell (with padding if desired)
Unfortunately this doesn't play well with single cell selection (CellSelectionModel). The css class for cell selection is obfuscated so it can't be referenced in other stylesheets. :(
My (ugly) alternative was to render a custom stylesheet that is linked in the module's html page (eg. Main.html). Then I can colour cells using css 'class' instead of 'style' attributes. IE:
Create a custom JSP that renders a stylesheet (content type 'text/css')
Link the stylesheet to the module html (after 'reset.css')
The stylesheet needs to have selector td.someClass (.someClass is not specific enough)
Use Grid.getView().setViewConfig() to supply a GridViewConfig that returns the appropriate class(es)
Unfortunately this requires a good knowledge of CSS rules and also the possible colours need to be known at user login time.
There may be a third way using the style attribute of the 'td' element. Have a look at this issue from Sencha:
http://www.sencha.com/forum/showthread.php?289347-Influencing-cell-td-style-in-a-grid&p=1057079 (work in progress)
Note that other styling options include:
Various ColumnConfig.setXxxClassName()
Various ColumnConfig.setXxxStyle()