Frage

I have a problem.

I need to draw on the widget type GtkDrawingArea using functions Xlib (XDrawLine etc).

Why?

I use the library, which draws with Xlib. And I need to pass any arguments (Display, Window, GC) in the rendering function drawSome (...). All is well. I obtain these arguments (via gdk_x11_... (), GdkDrawable, GdkGC) and call drawSome (...) with obtained parameters.

But there are problems - drawing is not always done. The image is not displayed when maximizing windows, dragging, resizing DrawingArea etc.. The image is displayed only under unusual manipulation of the top window .

Then I tested the function XDrawPoint/Line/Rectangle - the same problem. If we use gdk_draw_rectangle (...) - all is normal.

Here's the code below:

...
GtkDrawingArea* area;
...
int main (int argc, char *argv[])
{
   ...
   area=GTK_DRAWING_AREA(gtk_builder_get_object(builder,"area"));
   gtk_widget_realize (GTK_WIDGET(area));
   ...
   g_signal_connect (G_OBJECT(area), "expose_event", G_CALLBACK(expose_event_callback), NULL);
   ...
}
...
gboolean expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
   Display *dpy = gdk_x11_drawable_get_xdisplay(widget->window);
   Window win =gdk_x11_drawable_get_xid(widget->window);
   GC gc = DefaultGC(dpy, DefaultScreen(dpy));

   //draw image on (0,0) in widget DrawingArea and a small black rectangle over image
   drawSome(dpy, win, gc, ...);
   XFillRectangle(dpy, win, gc, 0, 0, 10, 10);

   return FALSE;
}
...

Image and a small black rectangle displayed only in one case: if the window move beyond the desktop and return back to the desktop - the image appears. In other cases, it is not displayed. The impression is that another function erases DrawingArea.

Who can tell me what's the problem?

I would be grateful!

And... sorry to so bad English!

War es hilfreich?

Lösung 2

You'll need to use these functions X Window System Interaction but be warned but there may be other pitfalls. I think you'll also need to disable double-buffering for your GtkDrawingArea using gtk_widget_set_double_buffered

Andere Tipps

I think all you need to do is add XFlush(dpy); after the XFillRectangle command. I wrote a short routine and it seems to work.

#include <X11/Xlib.h> //-lX11
#include <gtk/gtk.h> //$$(pkg-config --cflags --libs gtk+-3.0) 
#include <gdk/gdkx.h>
void DrawOnWidget(GtkWidget *widget)
{
    GdkDisplay *gdk_dis = gdk_display_get_default();
    Display *dis = gdk_x11_display_get_xdisplay (gdk_dis);    
    GC gc = DefaultGC(dis, DefaultScreen(dis));
    GdkWindow *gdk_window = gtk_widget_get_window(widget);
    Window win = gdk_x11_window_get_xid(gdk_window);
    unsigned long valuemask = GCForeground;
    XGCValues vColor;
    vColor.foreground = 0x000000FF;
    XChangeGC(dis, gc, valuemask, &vColor);
    XFillRectangle(dis, win, gc, 0, 0, 100, 100);
    XFlush(dis);
}

This is my second answer to this question... My first answer probably addresses the original question so I left it as unchanged. Although, the more general solution which is what I was looking for when I first found this thread was not addressed therefore, I decided to post a more general solution as well.

In short, I created a gtk image widget which can be displayed independently or attached to other widgets like buttons. Then I sent the image widget to the drawing function. In the drawing function all of the xlib parameters are queried in order to create a Pixmap as the xlib drawable which is where all xlib drawing is rendered. Then the GdkPixbuf is created and the Pixmap pixels are copied to the GdkPixbuf which is then set to the image widget...

There are a few commented lines which can be used to change the behavior the explanation will be left to the reader to determine.

It should be noted that while using xlib is possible; cairo appears to be a bit less cumbersome to implement.

#include <gtk/gtk.h> //$$(pkg-config --cflags --libs gtk+-3.0)
#include <gdk/gdkx.h>
#include <X11/Xlib.h> //-lX11

void DrawOnWidget(GtkWidget *widget, int width, int height)
{    
    GdkDisplay *gdk_dis = gdk_display_get_default();
    Display *dis = gdk_x11_display_get_xdisplay (gdk_dis);    
    GC gc = DefaultGC(dis, DefaultScreen(dis));

    GdkWindow *gdk_window = gtk_widget_get_window(widget);
    Window win = gdk_x11_window_get_xid(gdk_window);
    
    GdkPixbuf *pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height);
    //GdkPixbuf *pb = gtk_image_get_pixbuf((GtkImage *) widget);
    char *data = (char *) gdk_pixbuf_read_pixels((const GdkPixbuf *) pb); //RGB(A)
    //int width = gdk_pixbuf_get_width(pb);
    //int height = gdk_pixbuf_get_height(pb);
    int pb_depth = gdk_pixbuf_get_n_channels(pb);

    int depth  = DefaultDepth(dis, DefaultScreen(dis)) / 8;
    Pixmap pm = XCreatePixmap(dis, win, width, height, depth * 8);          

    unsigned long valuemask = GCForeground;
    XGCValues vColor;
    vColor.foreground = 0x00FF0000;
    XChangeGC(dis, gc, valuemask, &vColor);
    XFillRectangle(dis, pm, gc, 0, 0, width, height);
    XFlush(dis);
    
    XImage *ximage = XGetImage(dis, pm, 0, 0, width, height, AllPlanes, ZPixmap); //BGRX
    for(int i=0, j=0; i<width*height*pb_depth; i+=pb_depth, j+=4)
    {
        data[i+0] = ximage->data[j+2];
        data[i+1] = ximage->data[j+1];
        data[i+2] = ximage->data[j+0];
        if(pb_depth == 4) data[i+3] = 255;
    }
    
    gtk_image_set_from_pixbuf((GtkImage *) widget, pb);
    XFreePixmap(dis, pm);
    g_object_unref(pb);
    return;
}
static void destroy( GtkWidget *widget, gpointer data )
{
    gtk_main_quit();
}
static void test( GtkWidget *widget, gpointer data )
{
    DrawOnWidget((GtkWidget *) data, 200, 200);
}
void GTK_Win()
{
    GtkWidget *window, *grid;
    GtkWidget *button_Exit, *button_Test;    
    
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL);
    
    grid = gtk_grid_new ();
    gtk_container_add (GTK_CONTAINER (window), grid);
       
    button_Exit = gtk_button_new_with_label ("x");
    g_signal_connect (button_Exit, "clicked", G_CALLBACK (destroy), NULL);
    
    //GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, 200, 200);
    //GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf);  
    
    GtkWidget *image = gtk_image_new();
            
    button_Test = gtk_button_new_with_label ("Test");
    g_signal_connect (button_Test, "clicked", G_CALLBACK (test), image);
    //gtk_button_set_image((GtkButton *) button_Test, image);
           
    gtk_grid_attach (GTK_GRID (grid), button_Exit, 0, 0, 1, 1);
    gtk_grid_attach (GTK_GRID (grid), button_Test, 0, 1, 1, 1);
    gtk_grid_attach (GTK_GRID (grid), image, 0, 2, 1, 1);

    gtk_widget_show_all (window);
    gtk_main();   
}
int main(int argc, char** argv)
{
    gtk_init (&argc, &argv);  
    GTK_Win();
    return 0;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top