GtkStatusIcon drawing issue - c

i'm using gtk+-2.0 in C. and i have to write a digit upon my tray icon. i do it such way:
static GdkPixbuf * transform_pixbuf(GdkPixbuf *pixbuf) {
cairo_t *cr;
int width = gdk_pixbuf_get_width(pixbuf);
int height = gdk_pixbuf_get_height(pixbuf);
GdkPixmap *pixmap = gdk_pixmap_new(NULL, width, height, 24);
cr = gdk_cairo_create(pixmap);
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
cairo_paint(cr);
cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cr, 15.0);
cairo_set_source_rgb (cr, 1.0, 0, 0);
cairo_move_to (cr, 10, 20);
cairo_show_text (cr, "8");
cairo_destroy(cr);
GdkPixbuf *pixbuf_new = gdk_pixbuf_get_from_drawable(NULL, pixmap, NULL,
0, 0, 0, 0, width, height);
return pixbuf_new;
}
where GdkPixbuf *pixbuf is GdkPixbuf i want to set in tray. i can draw a digit, but the icon's background became "dancing" - .
i guess the problem is in gdk_pixmap_new's depth argument, because the icon has 32bit format, but 32 isn't valid argument for this function. in such case i have followin warning and no icon in the tray:
Gdk-WARNING **: Using Cairo rendering requires the drawable argument to
have a specified colormap. All windows have a colormap,
however, pixmaps only have colormap by default if they
were created with a non-NULL window argument. Otherwise
a colormap must be set on them with gdk_drawable_set_colormap
Gdk-WARNING **: /build/buildd/gtk+2.0-2.24.4/gdk/gdkpixbuf-drawable.c:1249: Source drawable has no colormap; either pass in a colormap, or set the colormap on the drawable with gdk_drawable_set_colormap()
Suggest me, please...

i've solved my problem with workaround. the problem was in creating pixmap - it was "dirty" from it's "born". the solution is in to not use pixmap, but create cairo context via the functions: http://www.gtkforums.com/viewtopic.php?t=5204

Related

c printing more pages with cairo and cups

I need, in C in under a linux environment, to print documents with an image as a background.
I found an example which use Cairo vector graphics library to author a PostScript, and then sends it that off to CUPS for printing.
I modified the initial source code to integrate it with a background image (background-img.png) .
The text to be printed is more than one page, I would like to know how can I print on multiple pages keeping the same image as background and changing only the foreground text ?
How can I resize the background image to match the size of an A4 page ?
Here is the code used as a starting point :
// compile with:
// gcc -Wall -o cairo_print_png cairo_print_png.c `pkg-config --cflags --libs cairo` `cups-config --cflags --libs`
#include <stdio.h>
#include <cairo.h>
#include <cairo-ps.h>
#include <cups/cups.h>
// A4 width, height in points, from GhostView manual:
// http://www.gnu.org/software/gv/manual/html_node/Paper-Keywords-and-paper-size-in-points.html
#define WIDTH 595
#define HEIGHT 842
int main(int argc, char** argv) {
int widthPng, heightPng;
if (argc!= 2){
fprintf (stderr, "usage: %s word\n", argv[0]);
return 1;
}
// setup
char* tmpfilename = tempnam(NULL,NULL);
cairo_surface_t* surface = cairo_ps_surface_create(tmpfilename,
WIDTH,
HEIGHT);
cairo_t *context = cairo_create(surface);
// draw some text
cairo_select_font_face(context,
"mono",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(context, 30);
cairo_move_to(context, WIDTH/2, HEIGHT/2);
cairo_show_text(context, argv[1]); // the text we got as a parameter
// draw a dotted box
const double pattern[] = {15.0, 10.0};
cairo_set_dash(context, pattern, 2, 0);
cairo_set_line_width(context, 5);
cairo_rectangle(context, WIDTH*0.33, HEIGHT*0.33, WIDTH*0.5, WIDTH*0.5);
cairo_stroke(context);
cairo_surface_t* surface_png = cairo_image_surface_create_from_png("background-img.png");
if (surface_png == NULL || cairo_surface_status (surface_png)) {
printf("***** load error *****\n");
}
widthPng = cairo_image_surface_get_width(surface_png);
heightPng = cairo_image_surface_get_height(surface_png);
cairo_surface_set_device_scale (surface_png,
widthPng/WIDTH*1.33,
heightPng/HEIGHT*1.29);
cairo_set_operator(context, CAIRO_OPERATOR_DEST_OVER);
cairo_set_source_surface(context, surface_png, 0, 0);
cairo_paint(context);
/*** second page ***/
{
cairo_t *cr;
cr = cairo_create (surface);
/* Duplicate the last frame onto another page. (This is just a
* way to sneak cairo_copy_page into the test).
*/
cairo_show_page (cr);
//draw text on second page
cairo_select_font_face(cr,
"mono",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 30);
cairo_move_to(cr, WIDTH/2, HEIGHT/2);
cairo_show_text(cr, "text over second page");
cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER);
cairo_set_source_surface(cr, surface_png, 0, 0);
cairo_paint(cr);
cairo_destroy (cr);
}
// finish up
cairo_show_page(context);
cairo_destroy(context);
cairo_surface_flush(surface);
cairo_surface_destroy(surface);
cairo_surface_flush(surface_png);
cairo_surface_destroy(surface_png);
// print
cupsPrintFile("Cups-PDF", tmpfilename, "cairo PS", 0, NULL);
unlink(tmpfilename);
return 0;
}
Update :
I added the text enclosed in "second page". I can create another page, but I can't resize the background image.
How can I resize the image to fit the A4 size?
Update
I used cairo_surface_set_device_scale to resize the image, and the mono font to use a fixed width font
Update
The problem now is that the code works with cairo-1.15.12-4 while if I try to compile with cairo-1.8.8-3.1 I get undefined reference to cairo_surface_set_device_scale'.
What can I solve the problem? At the moment I cannot update the libraries using rpm as I would have to update the whole operating system.
Can I somehow replace the cairo_surface_set_device_scale with functions that perform the same task?
Update:
In the Cairo Mailing Lists I found the following function that does the job :
cairo_surface_t *scale_to_half(cairo_surface_t *s, int orig_width, int
orig_height, double x_scale, double y_scale)
{
cairo_surface_t *result = cairo_surface_create_similar(s,
cairo_surface_get_content(s), orig_width*x_scale, orig_height*y_scale);
cairo_t *cr = cairo_create(result);
cairo_scale(cr, x_scale, y_scale);
cairo_set_source_surface(cr, s, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
cairo_destroy(cr);
return result;
}
but the quality is very low compared to cairo_surface_set_device_scale.

Multiple sequentual glPushAttrib/glPopAttrib incorrect behaviour

#include <GL/glut.h>
void reshape(int w, int h){
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-w/2, w - w/2, -h/2, h - h/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void display(){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 1, 1);
glPushAttrib(GL_ALL_ATTRIB_BITS);
glColor3f(1, 0, 0);
glPopAttrib();
glRecti(0, 0, 10, 10); // draws white rect
// Commenting the line makes next rect white
// Uncommenting the line makes next rect red
glTranslatef(0, 0, 0);
glPushAttrib(GL_ALL_ATTRIB_BITS);
glColor3f(1, 0, 0);
glPopAttrib();
glRecti(20, 20, 30, 30); // draws white or red rect
glutSwapBuffers();
}
int main (int argc, char * argv[]){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
glutInitWindowSize(800, 600);
glutCreateWindow("OpenGL lesson 1");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
The code above is full compilable programm that renders two rectangles. The programm produce different results depending on weather line "glTranslatef(0, 0, 0);" commented or not. Is that a bug, or misusage of OpenGL?
Is that a bug, or misusage of OpenGL?
That is just a bug. The spec clearly states that glColor will set the current RGBA color value, which will become the vertex's color the next time a vertex is formed. This would happen by the next glVertex call inside a glBegin/glEnd block. glRect is specified to be equivalent to glBegin(); glVertex() [4x]; glEnd().
The current RGBA color value is part of the GL_CURRENT_BIT attribute group, and is of course included in GL_ALL_ATTRIB_BITS. glTranslate is to only affect the top element of the currenttly selected matrid stack. The correct output for this code are two wihite rectangles, no matter if a glTranslate is there or not.
However, all this stuff is horribly outdated, and deprecated since 2008.

Cairo image blurred when scaled

I have the following cairo code:
cairo_set_source_rgba(cr, 1, 1, 1, 1);
cairo_rectangle(cr, 0, 0, WINDOW_SIZE, WINDOW_SIZE);
cairo_fill(cr);
cairo_scale(cr, 8, 8);
draw_image(cr, "q.png", 5, 5);
And
void draw_image(cairo_t* cr, char* img_name, int x, int y)
{
cairo_translate(cr, x, y);
cairo_surface_t* img = cairo_image_surface_create_from_png(img_name);
cairo_set_source_surface(cr, img, 0, 0);
cairo_paint(cr);
cairo_translate(cr, -x, -y);
}
q.png is a 5x5 image:
But when the program is run, the image is slightly blurred:
I have already tried
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
but it does not work.
Is there any way to fix this problem?
This is because of how the image is scaled up. Instead of setting a source surface directly, create a pattern out of the surface with cairo_pattern_create_for_surface(), call cairo_pattern_set_filter() on it to set the scaling mode, and then call cairo_set_source() to load the pattern. See the documentation for cairo_filter_t for the scaling modes. CAIRO_FILTER_NEAREST, for example, will give you a normal pixel zoom with no blurring or other transformations.

How to create a cairo_t on a Gtk 2 window

I have an old app, now compiling on Gtk 2, but I need to introduce the use of Cairo. I can't figure out how to create the necessary cairo context (cairo_t) from my Widgets.
Here's the code I'm trying to learn with so far, modified (*ahem* cribbed) from a Gtk 3 tutorial. The crux of the matter is creating a cairo surface from the window widget. As it stands, that call is a sketch and it won't compile, let alone run. Remember, my target is Gtk2, not 3, at least at this point.
/* Snitched from http://zetcode.com/gfx/cairo/cairobackends/ on 13 Jan 2014 */
#include <cairo.h>
#include <cairo-xlib.h>
#include <gtk/gtk.h>
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
cairo_surface_t *surface;
cairo_t *cr;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window), darea);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 90);
gtk_window_set_title(GTK_WINDOW(window), "GTK window");
surface = cairo_xlib_surface_create(
gtk_widget_get_display(window), /* must be Display *, not struct GdkDisplay * */
window, /* must be Drawable (no star) */
gtk_widget_get_visual(window), /* must be Visual * */
gtk_widget_get_width(window), /* int */
gtk_widget_get_height(window) /* int */
);
cr = cairo_create(surface);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 40.0);
cairo_move_to(cr, 10.0, 50.0);
cairo_show_text(cr, "Discipline is power.");
gtk_widget_show_all(window);
gtk_main();
return 0;
}
I hope the tutorial did not do cairo drawing in main()... The meaningful place to draw onto a GTK2 widget is in the expose-event (and if you want to force a redraw from somewhere else, just call gtk_widget_queue_draw()). It is easier to use gdk_cairo_create() to get a cairo context.
Something like this:
static gboolean
on_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
cairo_t *cr;
cr = gdk_cairo_create (gtk_widget_get_window (widget));
cairo_move_to (cr, 30, 30);
cairo_show_text (cr, "Text");
cairo_destroy (cr);
return FALSE;
}
g_signal_connect(darea, "expose-event",
G_CALLBACK(on_expose_event), NULL);
Jan Bodnar has a more complete example (in the end).
This is all a lot nicer in GTK3 in my opinion. Still, even if your goal is to port to GTK3 it may make sense to change the drawing to use cairo first as you're doing -- changing to GTK3 afterwards should just simplify the code.

OpenGL 2D texture rendering too large, glViewport broken

I've written a small tiling game engine with OpenGL and C, and I can't seem to figure out what the problem is. My main loop looks like this:
void main_game_loop()
{
(poll for events and respond to them)
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
draw_block(WALL, 10, 10);
}
draw_block:
void draw_block(block b, int x, int y)
{
(load b's texture from a hash and store it in GLuint tex)
glPushMatrix();
glTranslatef(x, y, 0);
glBindTexture(GL_TEXTURE_2D, tex);
glBegin(GL_QUADS);
//BLOCK_DIM is 32, the width and height of the texture
glTexCoord2i(0, 0); glVertex3f(0, 0, 0);
glTexCoord2i(1, 0); glVertex3f(BLOCK_DIM, 0, 0);
glTexCoord2i(1, 1); glVertex3f(BLOCK_DIM, BLOCK_DIM, 0);
glTexCoord2i(0, 1); glVertex3f(0, BLOCK_DIM, 0);
glEnd();
glPopMatrix;
}
initialization function: (called before main_game_loop)
void init_gl()
{
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0, 0, 0, 0);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
When run, this displays a black screen. However, if I remove the glViewport call, it seemingly displays the texture, but huge and in the corner of the window. Screenshot:
The texture IS being drawn correctly, because if I scale out by a huge factor, I can see the entire image. The y-axis also seems to be flipped from what I used in the gluOrtho2D call (discovered by making events add or subtract from x/y coordinates of the image, subtracting from the y coordinate causes the image to move downward). I'm starting to get frustrated, because this is the simplest possible example I can think of. I'm using SDL, and am passing SDL_OPENGL to SDL_SetVideoMode. What is going on here?
Looks like a problem with glViewport, but just to be sure, did you try clearing the color buffer to purple?
I've always thought of glViewport as a video/windowing function, not actually part of OpenGL itself, because it is the intermediate between the window manager and the OpenGL subsystem, and it uses window coordinates. As such, you should probably look at it along with the other SDL video calls. I suggest updating the question with the full code, or at least with those parts relevant to the video/window subsystem.
Or is it that you omitted to call glViewport after a resize?
You should also try your code without SDL_FULLSCREEN and/or with a smaller window. I usually start with a 512x512 or 640x480 window until I get the viewport and some basic controls right.
the first two parameters of glViewPort specifies the lower left of the view
http://www.opengl.org/sdk/docs/man/xhtml/glViewport.xml
You can try
glViewport(0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT);
For gluOrtho2D, the parameters are left, right, top, bottom
so I would probably use
gluOrtho2D(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT);

Resources