Vala basics Goo & GTK+ - gtk3

I'm trying to write my first Vala application and I'm desperatly in need for a
jumpstart as I have some VAPI conflict.
The app is bare minimum (like you would expect):
public class RoxyApplication : Gtk.Application {
public RoxyApplication () {
Object (application_id: "roxytesting",
flags: ApplicationFlags.FLAGS_NONE);
}
protected override void activate () {
Gtk.ApplicationWindow window = new Gtk.ApplicationWindow (this);
window.set_default_size (800, 600);
window.title = "Roxy App 0.0.1";
Goo.Canvas canvas = new Goo.Canvas ();
window.add (canvas);
Gtk.Label label = new Gtk.Label ("Roxxy moxxy");
window.add (label);
window.show_all();
}
public static int main (string[] args) {
RoxyApplication roxapp = new RoxyApplication ();
return roxapp.run (args);
}
}
when I'm compiling with:
valac-0.40 -o main --pkg goocanvas --pkg GTK+-3.0 main.vala
or
valac-0.40 -o main --pkg goocanvas main.vala
respectively I get:
3115 errors all in sense of
"gtk+-2.0.vapi:8397.2-8397.42: error: `Gtk' already contains a definition for `tree_get_row_drag_data'
and 2 errors:
main.vala:1.32-1.46: error: The type name `Gtk.Application' could not be found
public class RoxyApplication : Gtk.Application {
Is it even possible to use these libraries together?
Als far as I can get a grasp Goo is extension of GTK+
and not a subset. (or is it still?)
Thanks in advance for your pointers.

Related

Gtk.Entry unable to set_text from another method

Pretty new to vala and Gtk.
I am unable to call Gtk.Entry's set_text method, to set text from another method. Here is the sample code which I tried. I am able to set_text while in the activate() method, but just not from the tryThis() method.
using Gtk;
public class MyApplication : Gtk.Application {
public MyApplication () {
Object(application_id: "testing.my.application",
flags: ApplicationFlags.FLAGS_NONE);
}
protected override void activate () {
Gtk.ApplicationWindow window = new Gtk.ApplicationWindow (this);
window.set_default_size (800, 600);
window.window_position = WindowPosition.CENTER;
window.set_border_width(10);
Gtk.HeaderBar headerbar = new Gtk.HeaderBar();
headerbar.show_close_button = true;
headerbar.title = "Window";
window.set_titlebar(headerbar);
//Entry is initialized here
Gtk.Entry entry = new Gtk.Entry();
entry.set_text ("Before button click");
//Button is initialized and connect to method
Gtk.Button but = new Gtk.Button.with_label("Click me");
but.clicked.connect(tryThis);
Gtk.Box vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
vbox.pack_start(entry, false, false, 10);
vbox.pack_start(but, false, false, 20);
window.add(vbox);
window.show_all ();
}
private void tryThis() {
Gtk.Entry entry = new Gtk.Entry();
//This is not working!!
entry.set_text ("After button click");
message("%s -", "I am here");
}
public static int main (string[] args) {
MyApplication app = new MyApplication ();
return app.run (args);
}
}
The problem is a problem of scope. So activate creates an entry within the scope of that method, not the whole class. tryThis creates a new instance of Gtk.Entry and assigns it to a variable entry in the scope of that method, not the whole class.
This example fixes your problem, but is not the best solution, as discussed after the example:
using Gtk;
public class MyApplication : Gtk.Application {
Gtk.Entry entry;
public MyApplication () {
Object(application_id: "testing.my.application",
flags: ApplicationFlags.FLAGS_NONE);
}
protected override void activate () {
Gtk.ApplicationWindow window = new Gtk.ApplicationWindow (this);
window.set_default_size (800, 600);
window.window_position = WindowPosition.CENTER;
window.set_border_width(10);
Gtk.HeaderBar headerbar = new Gtk.HeaderBar();
headerbar.show_close_button = true;
headerbar.title = "Window";
window.set_titlebar(headerbar);
//Entry is initialized here
entry = new Gtk.Entry();
entry.set_text ("Before button click");
//Button is initialized and connect to method
Gtk.Button but = new Gtk.Button.with_label("Click me");
but.clicked.connect(tryThis);
Gtk.Box vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
vbox.pack_start(entry, false, false, 10);
vbox.pack_start(but, false, false, 20);
window.add(vbox);
window.show_all ();
}
private void tryThis() {
entry.set_text ("After button click");
message("%s -", "I am here");
}
public static int main (string[] args) {
MyApplication app = new MyApplication ();
return app.run (args);
}
}
You should notice that:
entry is brought in to the scope of the whole class with Gtk.Entry entry; at the beginning of the class definition
entry = new Gtk.Entry (); has been removed from tryThis because the entry has already been instantiated when activate is called
This works, but for the longer term it is better to separate the window from the application. So use activate to instantiate a new MainApplicationWindow for example. Also Vala includes code generation routines for Gtk templates. This allows you to define the window and its child widgets using XML or the GUI tool Glade and then attach the Vala code with the Vala attributes [GtkTemplate], [GtkChild] and [GtkCallback].

Why gtk css widget styling does not work?

I'm trying to style widget from inside of it's constructor in Vala but I don't get the result I want. Here is the original code sample:
public class MyWidget : Gtk.FlowBox {
public MyWidget () {
var css_provider = new Gtk.CssProvider ();
try {
css_provider.load_from_data (
"""
label {
color: blue;
}
"""
);
get_style_context ().add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
} catch (Error e) {
message ("error");
}
}
public void add_entry (string s) {
var entry = new Gtk.Label (s);
add (entry);
}
}
I've tried all different variants of styling "flowbox", "flowboxchild", "label" etc. and only one that works is "*" for every element inside GtkFlowbox or assigning it to a class, thought I still can't style it's children. Priorities don't seem to change anything, adding global "flowbox" styles for screen context don't work too.
I've tried to do it using gtk inspector but no result here too.
So how do I style all children of widget? Or do I need to specify class for them?
Here is a working example:
public class MyWidget : Gtk.FlowBox {
public MyWidget () {
this.add_entry ("default text");
}
public void add_entry (string s) {
var entry = new Gtk.Label (s);
add (entry);
}
}
void main (string[] args) {
Gtk.init (ref args);
var window = new Gtk.Window ();
window.destroy.connect (Gtk.main_quit);
window.window_position = Gtk.WindowPosition.CENTER;
window.set_default_size (300, 80);
window.add (new MyWidget ());
var css_provider = new Gtk.CssProvider ();
try {
css_provider.load_from_data (
"""
GtkLabel {
color: blue;
}
"""
);
Gtk.StyleContext.add_provider_for_screen (
Gdk.Screen.get_default (),
css_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
);
} catch (Error e) {
message ("error loading CSS provider");
}
window.show_all ();
Gtk.main ();
}
Compile with:
valac --pkg gtk+-3.0 css_provider_example.vala
add_provider is a provider for that widget only. add_provider_for_screen adds the stylesheet for all widgets in the application. I can understand for_screen can be a little misleading by making someone think it applies to all applications on that screen, but from what I can tell that is not the case.
I've moved the add_provider_for_screen section to the main () block to clarify it is for the whole application. If you want the style to only apply to GtkLabels inside GtkFlowBoxes then the selector GtkFlowBox GtkLabel should work.
Also the terminology 'node' and 'selector' seems a little confusing. I had to change label in the GTK+ CSS to GtkLabel. A 'node' is probably the part of the widget that can be affected by the CSS rather than an identifier for selection, but anyone clarifying that would be very helpful! I have found that .label does work. So label is treated like a class name in CSS and GtkLabel like an element. Note the dot before label. .flowbox doesn't seem to work though.

Overriding methods in vala

As an experiemnt, I'm extending the Gtk.HeaderBar class in vala like this, in order to have a Button instead of the title / subtitle Labels:
using Gtk;
public class WebBrowserHeaderBar : HeaderBar {
private Button title_widget;
public WebBrowserHeaderBar(){
this.show_close_button = true;
title_widget = new Button.with_label("title");
this.set_custom_title(title_widget);
}
public void set_title(string title){
title_widget.label = title;
}
}
and then I'm using it like this:
public class MainWindow: Window {
private WebBrowserHeaderBar header;
public MainWindow() {
//this.title = MyWeb.APP_TITLE;
this.window_position = WindowPosition.CENTER;
this.destroy.connect (Gtk.main_quit);
set_default_size (300, 200);
header = new WebBrowserHeaderBar();
header.set_title (MyWeb.APP_TITLE);
this.set_titlebar(header);
}
}
That works, however I get the following warning while compiling:
WebBrowserHeaderBar.vala:15.2-15.22: warning: WebBrowserHeaderBar.set_title hides inherited method `Gtk.HeaderBar.set_title'. Use the `new' keyword if hiding was intentional
public void set_title(string title){
^^^^^^^^^^^^^^^^^^^^^
Compilation succeeded - 1 warning(s)
If I change my method like this public override void set_title(string title){, it won't compile:
WebBrowserHeaderBar.vala:15.2-15.31: error: WebBrowserHeaderBar.set_title: no suitable method found to override
public override void set_title(string title){
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Compilation failed: 1 error(s), 0 warning(s)
Why am I getting this? How can I get rid of the warning and/or successfully override the set_title method?
You can only override methods that are abstract or virtual. Other methods cannot be overridden, but you can hide them using the new keyword:
public new void set_title (string title) {
title_widget.label = title;
}
If the reference is of type WebBrowserHeaderBar, or one of its children, this method will be called. If the reference is of type HeaderBar or one of its superclasses, then the original set_title will be used.
This is a somewhat there-be-dragons feature.

GWT:getting error in simple Hello Application

I am running a basic GWT application in IntelliJ, below is my code
public class test implements EntryPoint {
/**
* This is the entry point method.
*/
public void onModuleLoad() {
final Button button = new Button("Click me");
final Label label = new Label();
button.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
if (label.getText().equals("")) {
testService.App.getInstance().getMessage("h", new AsyncCallback<Inter>() {
public void onFailure(Throwable caught) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void onSuccess(Inter result) {
label.setText(result.getToken());
}
});
} else {
label.setText("");
}
}
});
Impl Class
public class testServiceImpl extends RemoteServiceServlet implements testService {
// Implementation of sample interface method
public Inter getMessage(String msg) {
RdbHelper rdbHelper = new RdbHelper();
return rdbHelper.getMsg();
}
}
RdbHelper Class
public class RdbHelper {
public Inter getMsg(){
Inter inter = new Inter();
return inter;
}
}
Inter Class
public class Inter implements Serializable{
private String token ;
public String getToken() {
token = "Hello";
return token;
}
public void setToken(String token) {
this.token = token;
}
}
I should see msg "Hello" but i am getting this error .
ERROR: Errors in 'file:/C:/work/Grails/TestFinal/src/com/test/client/test.java'.
ERROR: Unable to find type 'com.test.client.test'.
ERROR: Line 28: No source code is available for type com.test.shared.Inter; did you forget to inherit a required module?.
ERROR: Hint: Previous compiler errors may have made this type unavailable.
ERROR: Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly.
ERROR: Failed to load module 'test' from user agent 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7' at 127.0.0.1:51070.
Note: I am trying the same thing in Eclipse and its working fine, but this is the Issue i am facing in IntelliJ
Did you remember to put
<source path="shared"/>
in your Module.gwt.xml file.
You need to do this to compile the code in shared package to javascript code. If not it only compiles the code in the client package and thereby the code in the shared folder is not available on client side.

How to use gtk/glade in vala

I'm trying to make a simple app with glade/gtk/vala. So far I have this:
using Gtk;
class HelloWorldApp : GLib.Object {
const string UI = "test.glade";
public Window main_window;
[CCode (instance_pos = -1)]
public void on_btn_hello_clicked(Button source) {
stdout.printf("Hello, world");
}
construct {
Builder builder = new Builder();
builder.add_from_file(UI);
main_window = builder.get_object("window1") as Window;
main_window.destroy.connect(Gtk.main_quit);
builder.connect_signals(this);
}
}
class HelloWorld : GLib.Object {
public static int main(string[] args) {
Gtk.init (ref args);
HelloWorldApp h = new HelloWorldApp();
h.main_window.show_all();
Gtk.main();
return 0;
}
}
When I run this it outputs:
(helloworld:22641): Gtk-WARNING **: Could not find signal handler 'on_btn_hello_clicked'
but otherwise runs fine apart from the handler not being called
What am I doing wrong?
You are doing one or more of the following three things wrong:
When you compile a program using Gtk.Builder, you have to add --pkg gmodule-2.0 to your valac command line. (link)
When you place your signal handlers inside a class and/or namespace, you have to add the class and/or namespace name to the handler name in Glade, so you should be connecting to hello_world_app_on_btn_hello_clicked. (link)
If you are on Windows, you also have to add [CCode (cname="G_MODULE_EXPORT on_btn_hello_clicked")]. (link)
the live.gnome.org has all those informations, including the Windows quirks: http://live.gnome.org/Vala/GTKSample#Loading_User_Interface_from_XML_File