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_new, gdk_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!
