How to update a contentpage(GtkDrawArea) in GtkNotebook - gtk3

I have a GtkWindow with a GtkNotebook. On the first page is a DrawArea. A colorgauge is drawn there, this should display a temperature. But it is not redrawn. It only works when I move the mouse over it. Outside of the GtkNotebook widget it works fine.
Colorgauge Pic
How can I solve this?
PS: I'am using GTK3 and C on RPi4 with Raspbian

I found it:
g_signal_connect(notebook, "draw", G_CALLBACK(DrawNB),NULL); //in the main
gtk_widget_queue_draw(GtkWidget notebook); //after drawing the DrawArea
and a Draw-Method:
gboolean DrawNB(GtkWidget *widget, cairo_t *cr, gpointer data){return FALSE}

Related

Draw to GdkWindow root window with Gtk3 and Cairo

I want to be able to draw directly to the root window with Gtk3 using Cairo. I have and old Gtk2 code drawing on a fullscreened window like this:
GdkWindow* drawable;
GdkGC* gc;
drawable = gdk_screen_get_root_window (gdk_screen_get_default());
gc = gdk_gc_new (drawable);
gdk_gc_set_subwindow (gc, GDK_INCLUDE_INFERIORS);
...
do_draw(drawable, gc);
With Gtk3 I tried this,
GdkWindow* drawable;
drawable = gdk_screen_get_root_window (gdk_screen_get_default());
cairo_surface_t *source_surface = gdk_window_create_similar_surface (drawable, CAIRO_CONTENT_COLOR_ALPHA, gdk_window_get_width(drawable), gdk_window_get_height(drawable) );
cairo_t *cairo = cairo_create(source_surface);
cairo_set_source_surface(cairo, source_surface, 0, 0);
....
do_draw(cairo);
The code seems to runs fine, but nothing is ever drawn to the screen. Is there a way to do something similar with Gtk3 and Cairo?
gdk_window_create_similar_surface creates a new surface that is "similar" to an already given one. But it is still a new surface.
You are looking for gdk_cairo_create() instead, I think (which is deprecated).
Unrelated to your question, but what is the following code supposed to do? Why are you preparing to copy a surface to itself? I think that is not really an allowed operation in cairo.
cairo_t *cairo = cairo_create(source_surface);
cairo_set_source_surface(cairo, source_surface, 0, 0);

GTK ignores any type of window positioning

I've been trying to position a splash screen at the center of the screen. In Windows, such a request is easy using SetWindowPos and a bit of geometric arithmetic. I found out that all requests to move a window are ignored by the windowing manager. So my question is, how come I see so many applications with pretty splash screens properly centered? I started with GTK_WINDOW_TOPLEVEL BTW and just switch to popup trying a few things. Setting the gravity and position do not fail, they are just ignored. Even defined in a .glade file, the window is ignored.
{
GtkWidget *pNewWindow = gtk_window_new(GTK_WINDOW_POPUP);
gtk_window_move(GTK_WINDOW(pNewWindow), 0, 0);
gtk_widget_show_all(pNewWindow);
while (gtk_events_pending())
gtk_main_iteration();
gtk_widget_set_size_request(pNewWindow, width, height);
gtk_window_set_decorated(GTK_WINDOW(pNewWindow), FALSE);
// gtk_window_set_position(GTK_WINDOW(pNewWindow), GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_set_resizable(GTK_WINDOW(pNewWindow), FALSE);
// gtk_window_set_gravity(GTK_WINDOW(pNewWindow), GDK_GRAVITY_CENTER);
gtk_window_move(GTK_WINDOW(pNewWindow), 0, 0);
while (gtk_events_pending())
gtk_main_iteration();
return pNewWindow;
}

How to draw in a subclassed DrawingArea widget?

I want to implement custom widgets by subclassing DrawingArea Widget, for this I need to draw using cairo. It seems like in gtk3 there is a new signal called 'draw' introduced. How do I draw inside the widget? Should the map and realize signals also be overrided?
A simple example code would be very helpful. Thanks.
To put it simply, you'll need to override the draw signal which will supply a Cairo context:
gboolean
user_function (GtkWidget *widget,
CairoContext *cr,
gpointer user_data)
Then you can use the CairoContext crto draw the actual contents of the widget.
From the C API:
The GtkDrawingArea widget is used for creating custom user interface
elements. It’s essentially a blank widget; you can draw on it. After
creating a drawing area, the application may want to connect to:
Mouse and button press signals to respond to input from the user. (Use
gtk_widget_add_events() to enable events you wish to receive.)
The “realize” signal to take any necessary actions when the widget is instantiated on a particular display. (Create GDK resources in
response to this signal.)
The “size-allocate” signal to take any necessary actions when the widget changes size.
The “draw” signal to handle redrawing the contents of the widget.
The widget should queue some draws when the widget changes, for example, on size allocate you should use gtk_widget_queue_draw to force the widget to draw itsef again.
Example - Using a drawing area not as sub classing it but the concept remains:
(taken from Gnome C API)
gboolean
draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
{
guint width, height;
GdkRGBA color;
GtkStyleContext *context;
context = gtk_widget_get_style_context (widget);
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
gtk_render_background (context, cr, 0, 0, width, height);
cairo_arc (cr,
width / 2.0, height / 2.0,
MIN (width, height) / 2.0,
0, 2 * G_PI);
gtk_style_context_get_color (context,
gtk_style_context_get_state (context),
&color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_fill (cr);
return FALSE;
}
[...]
GtkWidget *drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 100, 100);
g_signal_connect (G_OBJECT (drawing_area), "draw",
G_CALLBACK (draw_callback), NULL);
You should also read about Height-for-width Geometry Management in GtkWidget
I've used C because there was no reference to programming language on your question and at the same time it's the original API from which all other are written.
There are some examples about creating Gtk+ custom Widgets on the internet.

Gtk3 loading PixbufAnimation inside DrawingArea?

For the purpose of mine gstreamer application I tought about simple loader before I give a handle of DrawingArea widget to sink element.The basic idea was to load an animated .gif inside Gtk.DrawingArea but I run on the problem with documentation.I found out about PixbufAnimation and I used it with Gtk.Image widget but the same logic doesn't work for Gtk.DrawingArea and since it doesn't have add method I don't know what to do so as my last resort I came here to get a help.
This is what I did with Gtk.Image:
from gi.repository import Gdk,Gtk,GdkPixbuf
class animatedWin(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self,width_request=640,height_request=480)
self.canvas=Gtk.Image()
self.add(self.canvas)
self.load_file()
self.connect("delete-event",self.Gtk.main_quit)
def load_file(self):
self.loader=GdkPixbuf.PixbufAnimation.new_from_file("loader.gif")
self.canvas.set_from_animation(self.loader)
app=animatedWin()
app.show_all()
Gtk.main()
is it possible to achieve the same thing with DrawingArea ?
DrawingArea like most widgets in gtk3 uses cairo for drawing on them. Cairo draws on surfaces using context. You can convert pixbuf into surface by
public Surface Gdk.cairo_surface_create_from_pixbuf (Pixbuf pixbuf, int scale, Window? for_window)
And back by
public Pixbuf? Gdk.pixbuf_get_from_surface (Surface surface, int src_x, int src_y, int width, int height)
(taken from valadoc.org)
Example code snippet from my drawing app (I'm learning Vala while I writing it, so it may not be best implementation):
private void on_scale (Gtk.Button button) { // on button press
var my_pixbuf = Gdk.pixbuf_get_from_surface (this.buf_surface, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
var tmp_surface = Gdk.cairo_surface_create_from_pixbuf (my_pixbuf, 2, null);
var ctx = this.ccc; //this.ccc is context of drawing surface
ctx.set_source_surface (tmp_surface, 0, 0);
ctx.paint();
drawing_area.queue_draw(); // ask drawing_area to redraw, on redraw I have function/method that will paint drawing_area widget surface with drawing surface
}
PS. see http://valadoc.org/#!api=cairo/Cairo for more info on cairo. As I see it, cairo used for vector graphics and pixbuf for raster.

Invisble GtkEventBox vs cursor change

In my application, sometimes I need to disable most of the buttons and event boxes while a process is taking place (except the "cancel" button of course). Each event box contains a label which can be clicked. To make the user understand that these labels are clickable, I have underlined the texts and have made the cursor change when hovered over those labels.
The problem is that when I disable an event box (make it insensitive), you can see a rather ugly artifact:
So, I searched and found this function: gtk_event_box_set_visible_window. Note: I'm using (I have to, unfortunately) Gtk 2.22, but they just removed the documentation from their website. Anyway, the text of this function is the same.
According to this function, you can make the event box create a GDK_INPUT_ONLY window. If I do so, then disabling the event box doesn't make it ugly anymore.
However, since the event box now doesn't have an outputable window, the
gdk_window_set_cursor(event_box->window, cursor);
makes the cursor change for the whole window instead of just the event box.
I can somewhat see the contradiction between no visible window and cursor change over window, but my question is how, otherwise, can I have the cursor change over the event box, but don't see a visible artifact when the event box is disabled?
I tried different methods, such as changing the background of the event box to transparent etc, but all of them were quite complicated.
The simplest solution I found was the following:
static GdkCursor *_normal_cursor = NULL;
static GdkCursor *_hand_cursor = NULL;
/* in main */
_normal_cursor = gdk_window_get_cursor(widgets_to_remember->window->window);
_hand_cursor = gdk_cursor_new(GDK_HAND2);
/* create the event box */
gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box), FALSE);
gtk_widget_set_events(event_box, GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
_fix_event_box(event_box, window);
/* rest of main */
static gboolean _set_hand(GtkWidget *w, GdkEventCrossing *e, gpointer data)
{
gdk_window_set_cursor(w->window, _hand_cursor);
return TRUE;
}
static gboolean _set_normal(GtkWidget *w, GdkEventCrossing *e, gpointer data)
{
gdk_window_set_cursor(w->window, _normal_cursor);
return TRUE;
}
static void _fix_event_box(GtkWidget *eb, GtkWidget *window)
{
g_signal_connect_swapped(eb, "enter_notify_event", G_CALLBACK(_set_hand), window);
g_signal_connect_swapped(eb, "leave_notify_event", G_CALLBACK(_set_normal), window);
}
What this basically does is set the event box invisible, and then set its enter-notify-event and leave-notify-event signal handlers to change the window cursor when the mouse enters or leaves their window.