Archive | Cairo Graphics Library RSS feed for this section

SWT: GTK_INCLUDE_INFERIORS worst enemy (Sash Widget)

20 Aug

Good day my fellow Developers and Engineers,

 In my previous post I’ve written about INCLUDE_INFERIORS in Tracker Widget

Today I’ve started working on  Sash Widget’s drawBand() method, and guess what I have found there ?

….”Exactly, my old “friend” OS.GTK_INCLUDE_INFERIORS.”

Why INCLUDE_INFERIORS used in SASH ?

In Sash widget, INCLUDE_INFERIORS call is needed to put stippled rectangle ON TOP of  the parent.handle.

If you try to draw rectangle without INCLUDE_INFERIORS, it appears below the parent.handle, thus you won’t be able to see it.

Hackish solution to GDK INCLUDE_INFERIORS

After “googling” this issue, I have found  this article, that seems very popular, as it is referenced by many websites.

In short, article suggests to create  “cairo” from “gtk_window”, than to create a “surface” that points to this “cairo”, and finally to create new “cairo_new” that uses surface that points to the first “cairo”. Got confused ? Yeah, me too!

Let’s try it again:

 1.  source_surface -> takes as target -> cairo (that references GTK window)
 2.  cairo_new -> uses source_surface (thus drawing on a surface that is on top of cairo)

I think  that this is very hackish way, to achieve effect of INCLUDE_INFERIORS, but it works and I would be fully satisfied with this hack, if I didn’t need to change the color of Sash.

Why Hackish way cannot be used in Sash ?

There are two important things I need to do to replicate  GDK Sash:

1. Make it appear on mouse click
2. Make it stippled or at least make it in some neat light grey colour. ( as stippling is considered outdated , maybe proposal of light grey would be accepted upstream)

Make it appear on mouse click is done by replacing:


OS.gdk_gc_set_function (gc, OS.GDK_XOR);

  with


Cairo.cairo_set_operator(cairo, Cairo.CAIRO_OPERATOR_DIFFERENCE);

Point number 2  is done in Cairo by changing source rgb:


Cairo.cairo_set_source_rgb(cairo, 1, 1, 1);

In theory, to change color of Sash to  light grey, I would just need  to change  RGB number to something like “0.3,0.3,0.3″ in the function above, and  celebrate my success.

 Unfortunately,  hackish way of replicating INCLUDE_INFERIORS, will not allow me to change RGB in this case. As I have said above, we are using cairo as target_surface, thus when I change color of Sash, it will change color of handle itself, and it is definitely not the way, I need it to behave.

Want to try it yourself and get updates on this issue ?

If you want to try it yourself:

http://fedorapeople.org/cgit/aspektor/public_git/eclipse.platform.swt.git/commit/?h=cairo_sash

I have opened a bug regarding this issue. Fastest way to get updates on this issue is to include yourself to CC list in this bug:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=387641

I will also post solution here, so everyone could use it, when this issue is resolved.

Cheers,

Anatoly

 

Check out more posts on “SWT migration From GTK+ 2 to GTK+ 3″

SWT migration to GTK+ 3.x : Tracker Dilliemma

17 Jul

Couple of weeks I was trying to solve interesting dilemma, so I decided to share it with you.

 I have submitted patch regarding Tracker widget, where I implement Cairo instead of GDK deprecated methods, more about it here .

However, I got a response from Eclipse that it does not work under one condition:

 !! When you pass DISPLAY instead of SHELL as a surface on which Tracker should operate, Tracker does not produce any output.

Sounds like an “easy-breezy” thing to do, but actually it is not.

Let’s look at Tracker Code again and I will explain why:


void drawRectangles (Rectangle [] rects) {
int   window = OS.gdk_get_default_root_window();
if (parent != null) {
window = OS.GTK_WIDGET_WINDOW (parent.paintHandle());
}
if (window == 0) return;
// My Patch
if(OS.USE_CAIRO){
int  cairo = OS.gdk_cairo_create(window);
if (cairo == 0) error (SWT.ERROR_NO_HANDLES);
Cairo.cairo_set_source_rgb(cairo, 1, 1, 1);
Cairo.cairo_set_line_width(cairo, 1);
Cairo.cairo_set_operator(cairo,Cairo.CAIRO_OPERATOR_DIFFERENCE);
Cairo.cairo_set_antialias(cairo, Cairo.CAIRO_ANTIALIAS_NONE);

for (int i=0; i
Rectangle rect = rects [i];
Cairo.cairo_rectangle (cairo, rect.x, rect.y, rect.width, rect.height);
Cairo.cairo_stroke(cairo);
}
Cairo.cairo_destroy(cairo);
return;
}
int gc = OS.gdk_gc_new (window);
if (gc == 0) return;
int /*long*/ colormap = OS.gdk_colormap_get_system ();
GdkColor color = new GdkColor ();
OS.gdk_color_white (colormap, color);
OS.gdk_gc_set_foreground (gc, color);
OS.gdk_gc_set_subwindow (gc, OS.GDK_INCLUDE_INFERIORS);
OS.gdk_gc_set_function (gc, OS.GDK_XOR);
for (int i=0; i
Rectangle rect = rects [i];
int x = rect.x;
if (parent != null && (parent.style & SWT.MIRRORED) != 0) x = parent.getClientWidth () - rect.width - x;
OS.gdk_draw_rectangle (window, gc, 0, x, rect.y, rect.width, rect.height);
}
OS.g_object_unref (gc);
}

When display is passed to tracker, “parent” variable is null so:

int   window = OS.gdk_get_default_root_window();

is triggered.

Problem is: GDK uses native X11 library, and it allows to draw on root_window (in GNOME, in KDE is not allowed to draw on root), however when you try to do it with Cairo all drawings are clipped by inferiors.

To avoid clipping  GDK uses “wonderful” function:

OS.gdk_gc_set_subwindow (gc, OS.GDK_INCLUDE_INFERIORS);

Unfortunately for me, this function is deprecated and should not be used in newly written code. Also after contacting GTK+ maintainers, I have found out that  drawing on the root window is considered very bad practice, and should not be done.

After some brainstorming, I was advised to create a TRANSPARENT GTK_WINDOW with size of the rectangle, draw rectangle on this transparent window, and move this window depending on the  rectangle coordinates that are passed to the function.. Also I need to use the same XOR method to make rectangle inside the window disappear on mouse-release event, as it happens in the original GDK.

 All of this sounds very logical and appealing. However I am facing another set of challenges.

  •      To make window transparent I need to overwrite “draw” signal, which is not implemented  in SWT, and who knows, if such operation is even allowed in SWT?
  •       GDK way of dealing with rectangles was to redraw rectangle every time mouse moves. As now I have “window” appearing every when method is called – I need to close/reopen window every time, which also is a problem, as I need to find out, If window is opened? and than close it. Much better decision in this case would be to draw one window, and not to redraw it, but than I need to change implementation of the class.

And last question: If I change this implementation, what will happen to the working “when-shell-passed” solution ?

A lot of question and no answers yet….

If you know better solution, or if you have any suggestions regarding this case – please put them as the comment to this post, I appreciate any effort!

I will keep you updated!

Regards,

Anatoly

 

Check out more posts on “SWT migration From GTK+ 2 to GTK+ 3″

SWT migration To GTK+3.x : 6 SWT – Cairo Patches (Eclipse Bugzilla)

15 Jun

I am glad that you guys showed big interest to the project I am currently working on.  I have received couple of emails from blog readers asking to share patches they I have pushed upstream.

First of all, I want to mention that patches are still in “pending” stage, but I hope that they will be reviewed very soon.

For those who want to go ahead, and try   them before they are officially reviewed by Eclipse community, here is the link to 6 SWT patches I have pushed to upstream so far:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=380287
https://bugs.eclipse.org/bugs/show_bug.cgi?id=382384
https://bugs.eclipse.org/bugs/show_bug.cgi?id=382391
https://bugs.eclipse.org/bugs/show_bug.cgi?id=382402
https://bugs.eclipse.org/bugs/show_bug.cgi?id=382407
https://bugs.eclipse.org/bugs/show_bug.cgi?id=382626

If you find anything that you think is wrong, please let me know.

Any feedback is appreciated!

Regards,

Anatoly

 

Check out more posts on “SWT migration From GTK+ 2 to GTK+ 3″

SWT migration to GTK+ 3.x: Use Cairo Instead GDK : First Patch – Tracker Widget

7 Jun

I am continuing series of posts about   SWT migration to GTK+ 3.x . Today, I will  write about patch for SWT Tracker Widget, that omits some of GTK+ 3.x deprecated methods.

When I started working on patch for Tracker, it was very important for me understand what Tracker Widget is intended to do. I found very good implementation of  SWT Tracker widget   here 

Actual code is:


import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tracker;

public class Tracker_test {

public static void main(String[] args) {
Display display = new Display();
final Shell shell = new Shell(display);
shell.open();
shell.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event e) {
Tracker tracker = new Tracker(shell, SWT.NONE);
tracker.setRectangles(new Rectangle[] { new Rectangle(e.x, e.y, 100, 100), });
tracker.open();
}
});
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}

When you run this code, you see small rectangle. It appears when you  right-mouse click and disappears when you  release right-mouse click. It looks like this:

From this example, we can see that Tracker is intended to track mouse movements and mouse clicks. It works great, the only problem is that some code in Tracker Widget is outdated, and it won’t built with GTK+ 3.x. I am talking about code in drawRectangles() method inside Tracker.java.

Let’s look at this code:


void drawRectangles (Rectangle [] rects) {
int   window = OS.gdk_get_default_root_window();
if (parent != null) {
window = OS.GTK_WIDGET_WINDOW (parent.paintHandle());
}
if (window == 0) return;
//TODO: Use Cairo
int gc = OS.gdk_gc_new (window);
if (gc == 0) return;
int /*long*/ colormap = OS.gdk_colormap_get_system ();
GdkColor color = new GdkColor ();
OS.gdk_color_white (colormap, color);
OS.gdk_gc_set_foreground (gc, color);
OS.gdk_gc_set_subwindow (gc, OS.GDK_INCLUDE_INFERIORS);
OS.gdk_gc_set_function (gc, OS.GDK_XOR);
for (int i=0; i
Rectangle rect = rects [i];
int x = rect.x;
if (parent != null && (parent.style & SWT.MIRRORED) != 0) x = parent.getClientWidth () - rect.width - x;
OS.gdk_draw_rectangle (window, gc, 0, x, rect.y, rect.width, rect.height);
}
OS.g_object_unref (gc);
}

If we take a look at  GDK documentation , we will find out that gdk_gc_newgdk_color_white gdk_gc_set_foreground, gdk_gc_set_subwindow, gdk_gc_set_function and even  gdk_draw_rectangle are all deprecated since GTK version 2.22 and should not be used in newly written code. And as a hint, there is ‘ // TODO: Use Cairo’.

So I here is some of the changes I made to this code:

1. I replaced gdk_gc_new  with  gdk_cairo_create

2. OS.gdk_gc_set_function (gc, OS.GDK_XOR)  was replaced with equivalent function  Cairo.cairo_set_operator(cairo,Cairo.CAIRO_OPERATOR_DIFFERENCE)  (this function is responsible for rectangle to disappear on mouse release)

3. gdk_draw_rectangle was replaced with cairo_rectangle, as cairo saves everything to buffer first, you need to release changes. In my case I used cairo_stroke. ( it fills just contour of rectangle)

4. gdk_color_white was replaced with  cairo_set_source_rgb(cairo, 1, 1, 1);

5. I also had to add line width,  and antialising (without antialising  line width didn’t work)

So my code looks like this:

if(OS.USE_CAIRO){
int /*long*/ cairo = OS.gdk_cairo_create(window);
if (cairo == 0) error (SWT.ERROR_NO_HANDLES);

Cairo.cairo_set_source_rgb(cairo, 1, 1, 1);
Cairo.cairo_set_line_width(cairo, 1);
Cairo.cairo_set_operator(cairo,Cairo.CAIRO_OPERATOR_DIFFERENCE);
Cairo.cairo_set_antialias(cairo, Cairo.CAIRO_ANTIALIAS_NONE);

for (int i=0; i<rects.length; i++) {
Rectangle rect = rects [i];
Cairo.cairo_rectangle (cairo, rect.x, rect.y, rect.width, rect.height);
Cairo.cairo_stroke(cairo);
}
Cairo.cairo_destroy(cairo);
return;
}

After run with Cairo, I have the same output as GTK version does.

I have posted bug report with my patch here:  https://bugs.eclipse.org/bugs/show_bug.cgi?id=380287  ( As for June 7, patch is not reviewed yet, as Eclipse reviewers are extra-busy with new version of Eclipse coming out very soon)
I have coded couple of other patches, and I will definitely do some posts on them after this first patch is reviewed.

Regards,

Anatoly

Update:

Unfortunately there is one case where current patch does not work properly, as it supposed to. This case is when you pass “display” to the Tracker constructor. In GDK version it is supposed to use GDK_INCLUDE_INFERIORS that puts rectangle on top of all other windows, however Cairo does not have this luxury, and all my attempts to put in on top is clipped by child windows.

I keep on working on it, and I will keep you updated!

 

Check out more posts on “SWT migration From GTK+ 2 to GTK+ 3″

Follow

Get every new post delivered to your Inbox.

Join 272 other followers

%d bloggers like this: