Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoramitin2015-05-18 16:25:56 +0000
committeramitin2015-05-18 16:25:56 +0000
commit1c6d758f274c2661e7a54eeb04a70e5fb86bf3b4 (patch)
tree2aec97990899083568f806956c7ecf0155801188
parentb152a938470f608c77636d74a27dccb7e49578f7 (diff)
downloadorg.eclipse.windowbuilder-1c6d758f274c2661e7a54eeb04a70e5fb86bf3b4.tar.gz
org.eclipse.windowbuilder-1c6d758f274c2661e7a54eeb04a70e5fb86bf3b4.tar.xz
org.eclipse.windowbuilder-1c6d758f274c2661e7a54eeb04a70e5fb86bf3b4.zip
Gtk3 support
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/Makefile73
-rwxr-xr-xorg.eclipse.wb.os.linux/native/gtk/arch_dir.sh13
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/common/utils.c (renamed from org.eclipse.wb.os.linux/native/gtk/utils.c)0
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/common/utils.h (renamed from org.eclipse.wb.os.linux/native/gtk/utils.h)0
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/common/wbp.h (renamed from org.eclipse.wb.os.linux/native/gtk/wbp.h)0
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/core.c61
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/gtk2/CMakeLists.txt28
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/gtk2/gconf.c (renamed from org.eclipse.wb.os.linux/native/gtk/gconf.c)0
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/gtk2/rcp.c (renamed from org.eclipse.wb.os.linux/native/gtk/rcp.c)1262
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/gtk3/CMakeLists.txt30
-rw-r--r--org.eclipse.wb.os.linux/native/gtk/gtk3/rcp.c305
-rwxr-xr-x[-rw-r--r--]org.eclipse.wb.os.linux/os/linux/amd64/libwbp.sobin23064 -> 22984 bytes
-rwxr-xr-xorg.eclipse.wb.os.linux/os/linux/amd64/libwbp3.sobin0 -> 14600 bytes
-rwxr-xr-xorg.eclipse.wb.os.linux/os/linux/x86/libwbp.sobin17968 -> 17956 bytes
-rwxr-xr-xorg.eclipse.wb.os.linux/os/linux/x86/libwbp3.sobin0 -> 13756 bytes
-rwxr-xr-xorg.eclipse.wb.os.linux/os/linux/x86_64/libwbp.sobin18848 -> 22984 bytes
-rwxr-xr-xorg.eclipse.wb.os.linux/os/linux/x86_64/libwbp3.sobin0 -> 14600 bytes
-rw-r--r--org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/IScreenshotCallback.java4
-rw-r--r--org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/OSSupportLinux.java130
19 files changed, 1086 insertions, 820 deletions
diff --git a/org.eclipse.wb.os.linux/native/gtk/Makefile b/org.eclipse.wb.os.linux/native/gtk/Makefile
deleted file mode 100644
index af24e670..00000000
--- a/org.eclipse.wb.os.linux/native/gtk/Makefile
+++ /dev/null
@@ -1,73 +0,0 @@
-# Makefile for creating WBP library for Linux GTK
-
-# determine arch bits
-ARCH_BITS = $(shell getconf LONG_BIT)
-
-WBP_LIB = libwbp.so
-WBP_COMPIZ_LIB = libwbp-compiz.so
-
-OUTPUT_DIR = ../../os/linux/x86$(shell ./arch_dir.sh)
-
-# Do not use pkg-config to get libs because it includes unnecessary dependencies (i.e. pangoxft-1.0)
-GTKCFLAGS = `pkg-config --cflags gtk+-2.0`
-GTKLIBS = `pkg-config --libs-only-L gtk+-2.0 gthread-2.0` -lgtk-x11-2.0 -L/usr/X11R6/lib $(XLIB64)
-GCONFFLAGS = `pkg-config --cflags gconf-2.0`
-GCONFLIBS = `pkg-config --libs gconf-2.0`
-
-DEFINES = -DWBP_ARCH$(ARCH_BITS)
-
-CFLAGS = -O2 \
- -Wall \
- -fPIC \
- -fno-stack-protector \
- -g \
- -I. \
- -I$(JAVA_HOME)/include \
- -I$(JAVA_HOME)/include/linux
-
-LIBS = -shared -Wl,--as-needed
-
-WBP_OBJECTS = utils.o core.o rcp.o
-WBP_COMPIZ_OBJECTS = utils.o gconf.o
-
-ifndef NO_STRIP
- LIBS := $(LIBS) -s
-endif
-
-all: make_wbp make_wbp_compiz
-
-#
-# WBP lib
-#
-make_wbp:$(WBP_LIB)
-make_wbp_compiz:$(WBP_COMPIZ_LIB)
-
-$(WBP_LIB): $(WBP_OBJECTS)
- $(CC) -o $(WBP_LIB) $(GTKCFLAGS) $(CFLAGS) $(WBP_OBJECTS) $(GTKLIBS) $(LIBS)
-
-$(WBP_COMPIZ_LIB): $(WBP_COMPIZ_OBJECTS)
- $(CC) -o $(WBP_COMPIZ_LIB) $(GTKCFLAGS) $(CFLAGS) $(WBP_COMPIZ_OBJECTS) $(GTKLIBS) $(GCONFLIBS) $(LIBS)
-
-utils.o: utils.c
- $(CC) $(GTKCFLAGS) $(CFLAGS) $(DEFINES) -c utils.c
-core.o: core.c
- $(CC) $(GTKCFLAGS) $(CFLAGS) $(DEFINES) -c core.c
-rcp.o: rcp.c
- $(CC) $(GTKCFLAGS) $(CFLAGS) $(DEFINES) -c rcp.c
-gconf.o: gconf.c
- $(CC) $(GTKCFLAGS) $(CFLAGS) $(GCONFFLAGS) $(DEFINES) -c gconf.c
-
-
-
-#
-# Install
-#
-install: all
- mkdir -p $(OUTPUT_DIR)
- cp *.so $(OUTPUT_DIR)
-
-#
-# Clean
-#
-clean:
- rm -f *.o *.so
diff --git a/org.eclipse.wb.os.linux/native/gtk/arch_dir.sh b/org.eclipse.wb.os.linux/native/gtk/arch_dir.sh
deleted file mode 100755
index da339043..00000000
--- a/org.eclipse.wb.os.linux/native/gtk/arch_dir.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#*******************************************************************************
-# Copyright (c) 2011 Google, Inc.
-# All rights reserved. This program and the accompanying materials
-# are made available under the terms of the Eclipse Public License v1.0
-# which accompanies this distribution, and is available at
-# http://www.eclipse.org/legal/epl-v10.html
-#
-# Contributors:
-# Google, Inc. - initial API and implementation
-#*******************************************************************************
-#/bin/bash
-
-if test `getconf LONG_BIT` = "64";then echo _64;fi \ No newline at end of file
diff --git a/org.eclipse.wb.os.linux/native/gtk/utils.c b/org.eclipse.wb.os.linux/native/gtk/common/utils.c
index c24da12f..c24da12f 100644
--- a/org.eclipse.wb.os.linux/native/gtk/utils.c
+++ b/org.eclipse.wb.os.linux/native/gtk/common/utils.c
diff --git a/org.eclipse.wb.os.linux/native/gtk/utils.h b/org.eclipse.wb.os.linux/native/gtk/common/utils.h
index b7269385..b7269385 100644
--- a/org.eclipse.wb.os.linux/native/gtk/utils.h
+++ b/org.eclipse.wb.os.linux/native/gtk/common/utils.h
diff --git a/org.eclipse.wb.os.linux/native/gtk/wbp.h b/org.eclipse.wb.os.linux/native/gtk/common/wbp.h
index 239b0f14..239b0f14 100644
--- a/org.eclipse.wb.os.linux/native/gtk/wbp.h
+++ b/org.eclipse.wb.os.linux/native/gtk/common/wbp.h
diff --git a/org.eclipse.wb.os.linux/native/gtk/core.c b/org.eclipse.wb.os.linux/native/gtk/core.c
deleted file mode 100644
index 4797868d..00000000
--- a/org.eclipse.wb.os.linux/native/gtk/core.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2011 Google, Inc.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Google, Inc. - initial API and implementation
- *******************************************************************************/
-#include "wbp.h"
-
-static int isValidVersion() {
- return gtk_major_version == 2 && gtk_minor_version >= 12;
-}
-static jboolean isPlusMinusTreeClick(GtkTreeView *tree, gint x, gint y) {
- gint cell_x;
- gint cell_y;
- GtkTreePath *path;
- GtkTreeViewColumn *column;
- //
- if (gtk_tree_view_get_path_at_pos(tree, x, y, &path, &column, &cell_x, &cell_y)) {
- GtkTreeViewColumn *expanderColumn = gtk_tree_view_get_expander_column(tree);
- if (expanderColumn == column) {
- GdkRectangle rect;
- gtk_tree_view_get_cell_area(tree, path, column, &rect);
- if (x < rect.x) {
- return JNI_TRUE;
- }
- }
- }
- return JNI_FALSE;
-
-}
-JNIEXPORT void JNICALL OS_NATIVE(_1setAlpha)(
- JNIEnv *envir, jobject that, JHANDLE jshellHandle, jint jalpha) {
- if (isValidVersion()) {
- GtkWidget *shell = (GtkWidget*)unwrap_pointer(envir, jshellHandle);
- if (gtk_widget_is_composited(shell)) {
- int alpha = (int)jalpha;
- alpha &= 0xFF;
- gtk_window_set_opacity((GtkWindow*)shell, alpha / 255.0);
- }
- }
-}
-
-JNIEXPORT jint JNICALL OS_NATIVE(_1getAlpha)(
- JNIEnv *envir, jobject that, JHANDLE jshellHandle) {
- if (isValidVersion()) {
- GtkWidget *shell = (GtkWidget*)unwrap_pointer(envir, jshellHandle);
- if (gtk_widget_is_composited(shell)) {
- return (jint) (gtk_window_get_opacity((GtkWindow*)shell) * 255);
- }
- }
- return 255;
-}
-JNIEXPORT jboolean JNICALL OS_NATIVE(_1isPlusMinusTreeClick)(
- JNIEnv *envir, jobject that, JHANDLE jhandle, jint jx, jint jy) {
- return isPlusMinusTreeClick((GtkTreeView*)unwrap_pointer(envir, jhandle), (gint)jx, (gint)jy);
-}
-
diff --git a/org.eclipse.wb.os.linux/native/gtk/gtk2/CMakeLists.txt b/org.eclipse.wb.os.linux/native/gtk/gtk2/CMakeLists.txt
new file mode 100644
index 00000000..a5a57f0c
--- /dev/null
+++ b/org.eclipse.wb.os.linux/native/gtk/gtk2/CMakeLists.txt
@@ -0,0 +1,28 @@
+project(wbp-libs C)
+cmake_minimum_required(VERSION 2.6)
+
+if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(WBPLIBS_BITNESS_DEF "-DWBP_ARCH64")
+else()
+ set(WBPLIBS_BITNESS_DEF "-DWBP_ARCH32")
+endif()
+
+find_package(JNI REQUIRED)
+if (NOT JNI_FOUND)
+ message (FATAL_ERROR "Cannot found JNI dev files")
+endif()
+include_directories(${JNI_INCLUDE_DIRS})
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(GTK2 REQUIRED "gtk+-2.0")
+if (GTK2_FOUND)
+ include_directories(${GTK2_INCLUDE_DIRS})
+ link_directories(${GTK2_LIBRARY_DIRS})
+ add_definitions(${GTK2_CFLAGS_OTHER})
+ add_definitions(${WBPLIBS_BITNESS_DEF})
+ add_library(wbp SHARED ../common/utils.c rcp.c)
+ target_link_libraries(wbp ${GTK2_LIBRARIES})
+else()
+ message (FATAL_ERROR "Cannot found dev libs for Gtk2")
+endif()
+
diff --git a/org.eclipse.wb.os.linux/native/gtk/gconf.c b/org.eclipse.wb.os.linux/native/gtk/gtk2/gconf.c
index ffa5d2f4..ffa5d2f4 100644
--- a/org.eclipse.wb.os.linux/native/gtk/gconf.c
+++ b/org.eclipse.wb.os.linux/native/gtk/gtk2/gconf.c
diff --git a/org.eclipse.wb.os.linux/native/gtk/rcp.c b/org.eclipse.wb.os.linux/native/gtk/gtk2/rcp.c
index 3c8aa959..01697e13 100644
--- a/org.eclipse.wb.os.linux/native/gtk/rcp.c
+++ b/org.eclipse.wb.os.linux/native/gtk/gtk2/rcp.c
@@ -8,609 +8,659 @@
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
-#include "wbp.h"
-#include <stdlib.h>
-#include <string.h>
-
-#include <X11/Xatom.h>
-
-#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
-#define MAX_PROPERTY_VALUE_LEN 4096
-
-////////////////////////////////////////////////////////////////////////////
-//
-// Toggle "above" state for Eclipse, move preview window to another workspace
-//
-////////////////////////////////////////////////////////////////////////////
-int m_currentDesktop = 0;
-int m_desktopCount = 0;
-
-// gets the property of the X Window
-static gchar *get_property (Display *disp, Window win, Atom xa_prop_type, gchar *prop_name, unsigned long *size) {
- Atom xa_prop_name;
- Atom xa_ret_type;
- int ret_format;
- unsigned long ret_nitems;
- unsigned long ret_bytes_after;
- unsigned long tmp_size;
- unsigned char *ret_prop;
- gchar *ret;
-
- xa_prop_name = XInternAtom(disp, prop_name, False);
-
- /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage):
- *
- * long_length = Specifies the length in 32-bit multiples of the
- * data to be retrieved.
- */
- if (XGetWindowProperty(disp, win, xa_prop_name, 0, MAX_PROPERTY_VALUE_LEN / 4, False,
- xa_prop_type, &xa_ret_type, &ret_format,
- &ret_nitems, &ret_bytes_after, &ret_prop) != Success) {
- return NULL;
- }
-
- if (xa_ret_type != xa_prop_type) {
- XFree(ret_prop);
- return NULL;
- }
-
- /* null terminate the result to make string handling easier */
- tmp_size = (ret_format / 8) * ret_nitems;
- ret = g_malloc(tmp_size + 1);
- memcpy(ret, ret_prop, tmp_size);
- ret[tmp_size] = '\0';
-
- if (size) {
- *size = tmp_size;
- }
-
- XFree(ret_prop);
- return ret;
-}
-// sends the client message to the X Window
-static int client_msg(Display *disp, Window win, char *msg,
- unsigned long data0, unsigned long data1,
- unsigned long data2, unsigned long data3,
- unsigned long data4) {
- XEvent event;
- long mask = SubstructureRedirectMask | SubstructureNotifyMask;
-
- event.xclient.type = ClientMessage;
- event.xclient.serial = 0;
- event.xclient.send_event = True;
- event.xclient.message_type = XInternAtom(disp, msg, False);
- event.xclient.window = win;
- event.xclient.format = 32;
- event.xclient.data.l[0] = data0;
- event.xclient.data.l[1] = data1;
- event.xclient.data.l[2] = data2;
- event.xclient.data.l[3] = data3;
- event.xclient.data.l[4] = data4;
-
- if (XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) {
- return EXIT_SUCCESS;
- } else {
- fprintf(stderr, "Cannot send %s event.\n", msg);fflush(stderr);
- return EXIT_FAILURE;
- }
-}
-// toggles the "above" state of the X Window
-static int toggle_window_state_above(Display *disp, Window win) {
- unsigned long action = _NET_WM_STATE_TOGGLE;
- Atom prop1 = XInternAtom(disp, "_NET_WM_STATE_ABOVE", False);
- int result = client_msg(disp, win, "_NET_WM_STATE", action, (unsigned long)prop1, 0, 0, 0);
- return result;
-}
-// determines is the X Window has "above" state
-static Bool isWindowAbove (Display *disp, Window win) {
- Atom actual;
- int format;
- unsigned long n, left;
- unsigned char *data;
-
- int result = XGetWindowProperty(disp, win, XInternAtom(disp, "_NET_WM_STATE", False),
- 0L, 1024L, FALSE, XA_ATOM, &actual, &format, &n, &left, &data);
-
- if (result == Success && n && data) {
- Atom *a = (Atom *) data;
- while (n--) {
- if (XInternAtom (disp, "_NET_WM_STATE_ABOVE", 0) == *a++) {
- XFree ((void *) data);
- return True;
- }
- }
- XFree ((void *) data);
- }
-
- return False;
-}
-
-static Bool isOverrideRedirect(Display* disp, Window win) {
- XWindowAttributes attrs;
- XGetWindowAttributes(disp, win, &attrs);
- return attrs.override_redirect;
-}
-static void gtk_widget_show_map_callback (GtkWidget *widget, GdkEvent *event, gint *flag) {
- *flag = TRUE;
- g_signal_handlers_disconnect_by_func (widget,gtk_widget_show_map_callback, flag);
-}
-
-// moves the preview window onto another workspace (desktop).
-static int moveWindowToDesktop(GtkWidget *shellWidget) {
- if (GTK_WIDGET_VISIBLE(shellWidget)) {
- // can't do anything, because it's already visible
- return JNI_FALSE;
- }
- // get underlying X resources
- GdkWindow *window = shellWidget->window;
- Window x11window = GDK_WINDOW_XID(window);
- Display* disp = GDK_DRAWABLE_XDISPLAY(window);
- // remove "override_redirect" flag
- // https://fogbugz.instantiations.com:443/default.php?41586
- Bool wasOverride = isOverrideRedirect(disp, x11window);
- if (wasOverride) {
- gdk_window_set_override_redirect(window, FALSE);
- }
- // disable showing preview window by any helpers
- gtk_window_set_focus_on_map((GtkWindow*)shellWidget, FALSE);
- gtk_window_set_skip_taskbar_hint((GtkWindow*)shellWidget, TRUE);
- gtk_window_set_skip_pager_hint((GtkWindow*)shellWidget, TRUE);
- // get current desktop/desktop count
- unsigned long *desktopCountPtr = NULL;
- unsigned long *currentDesktopPtr = NULL;
- Window root = DefaultRootWindow(disp);
- if (!(desktopCountPtr = (unsigned long *)get_property(disp, root,
- XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS", NULL))) {
- if (!(desktopCountPtr = (unsigned long *)get_property(disp, root,
- XA_CARDINAL, "_WIN_WORKSPACE_COUNT", NULL))) {
- return JNI_FALSE;
- }
- }
- if (!(currentDesktopPtr = (unsigned long *)get_property(disp, root,
- XA_CARDINAL, "_NET_CURRENT_DESKTOP", NULL))) {
- if (!(currentDesktopPtr = (unsigned long *)get_property(disp, root,
- XA_CARDINAL, "_WIN_WORKSPACE", NULL))) {
- return JNI_FALSE;
- }
- }
- m_currentDesktop = *currentDesktopPtr;
- m_desktopCount = *desktopCountPtr;
- g_free(currentDesktopPtr);
- g_free(desktopCountPtr);
- // determine the desktop number on which the preview window would be moved
- int desktop;
- int desktopCountActual = m_desktopCount;
- if (m_desktopCount == 1 ) {
- // create new desktop if the only one exists, would be removed later
- if (!client_msg(disp, DefaultRootWindow(disp), "_NET_NUMBER_OF_DESKTOPS", 2, 0, 0, 0, 0)) {
- // success
- desktopCountActual++;
- XSync(disp, False);
- }
- }
- if (m_currentDesktop == desktopCountActual - 1) {
- desktop = desktopCountActual - 2;
- } else {
- desktop = m_currentDesktop + 1;
- }
- // show widget required, only mapped windows can be moved to another desktop.
- // this could cause flickering in rare cases (a few events in queue?)
- gint flag = FALSE;
- gtk_widget_show(shellWidget);
- // move window to another desktop
- client_msg(disp, x11window, "_NET_WM_DESKTOP", (unsigned long)desktop, 0, 0, 0, 0);
- // wait for window to be completely shown: wait for ConfigureNotify which has no above window.
- g_signal_connect (shellWidget, "configure-event", G_CALLBACK (gtk_widget_show_map_callback),&flag);
- while (!flag) {
- gtk_main_iteration();
- }
- if (wasOverride) {
- gdk_window_set_override_redirect(window, TRUE);
- }
- // success
- return JNI_TRUE;
-}
-
-static int restoreWindow(GtkWidget *shellWidget) {
- if (m_desktopCount == 0) {
- // nothing to do?
- return JNI_FALSE;
- }
- // get underlying X resources
- GdkWindow *window = shellWidget->window;
- Display* disp = GDK_DRAWABLE_XDISPLAY(window);
- // remove the extra desktop maybe created above
- if (m_desktopCount == 1) {
- client_msg(disp, DefaultRootWindow(disp), "_NET_NUMBER_OF_DESKTOPS", 1, 0, 0, 0, 0);
- }
- // cleanup
- m_currentDesktop = 0;
- m_desktopCount = 0;
- // success
- return JNI_TRUE;
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// Shell screen shot
-//
-////////////////////////////////////////////////////////////////////////////
-static GdkPixmap* copyPixmap(GdkPixmap *source, gint width, gint height) {
- if (source) {
- GdkPixmap* pixmap = gdk_pixmap_new(source, width, height, -1);
- GdkGC *gc = gdk_gc_new(source);
- gdk_draw_drawable(pixmap, gc, source, 0, 0, 0, 0, -1, -1);
- g_object_unref(gc);
- g_object_unref(source);
- return pixmap;
- }
- return NULL;
-}
-/*
-not used because produces screenshot with errors, but may be useful in future when gtk fixes their bugs.
-static GdkPixmap* makeShot2(GtkWidget *widget) {
- GdkPixmap* source = gtk_widget_get_snapshot(widget, NULL);
- if (source == NULL) {
- return NULL;
- }
- // determine snapshot rectangle
- int x = widget->allocation.x;
- int y = widget->allocation.y;
- int width = widget->allocation.width;
- int height = widget->allocation.height;
- // grow snapshot rectangle to cover all widget windows
- if (widget->parent && !GTK_WIDGET_NO_WINDOW (widget)){
- GdkWindow *parent_window = gtk_widget_get_parent_window (widget);
- GList *windows = NULL, *list;
- for (list = gdk_window_peek_children (parent_window); list; list = list->next) {
- GdkWindow *subwin = list->data;
- gpointer windata;
- int wx, wy, ww, wh;
- gdk_window_get_user_data (subwin, &windata);
- if (windata != widget) {
- continue;
- }
- windows = g_list_prepend (windows, subwin);
- gdk_window_get_position (subwin, &wx, &wy);
- gdk_drawable_get_size (subwin, &ww, &wh);
- // grow snapshot rectangle by extra widget sub window
- if (wx < x) {
- width += x - wx;
- x = wx;
- }
- if (wy < y) {
- height += y - wy;
- y = wy;
- }
- if (x + width < wx + ww) {
- width += wx + ww - (x + width);
- }
- if (y + height < wy + wh) {
- height += wy + wh - (y + height);
- }
- }
- } else if (!widget->parent) {
- x = y = 0; // toplevel
- }
- // return it copied to avoid incompatibility with SWT.
- return copyPixmap(source, width, height);
-}*/
-
-JNIEnv *m_envir;
-jobject m_callback;
-jmethodID m_IScreenshotCallback_storeImage;
-//
-typedef struct _GdkWindowPaint GdkWindowPaint;
-struct _GdkWindowPaint {
- GdkRegion *region;
- GdkPixmap *pixmap;
- gint x_offset;
- gint y_offset;
-};
-static void exposeAllWidgetsCallback(GtkWidget *widget, gpointer data);
-//
-#define PREPARE_EVENT \
- GdkEventExpose ev;\
- ev.type = GDK_EXPOSE;\
- ev.send_event = TRUE;\
- ev.area.x = 0;\
- ev.area.y = 0;\
- ev.count = 0;
-
-#define UPDATE_EVENT \
- gdk_window_get_geometry(ev.window, NULL, NULL, &ev.area.width, &ev.area.height, NULL);\
- ev.region = gdk_region_rectangle(&ev.area);
-
-static void exposeWidget(GtkWidget *widget) {
- GdkWindow *window = widget->window;
- if (!GTK_WIDGET_REALIZED(widget)) {
- return;
- }
-// g_warning ("type = %s", G_OBJECT_TYPE_NAME (widget));
- if (GTK_IS_SPIN_BUTTON(widget)) {
- // spin button
- GtkWidgetClass *clazz = (GtkWidgetClass *)GTK_SPIN_BUTTON_GET_CLASS(widget);
- GtkSpinButton *spin = GTK_SPIN_BUTTON (widget);
- {
- PREPARE_EVENT
- ev.window = spin->panel;
- UPDATE_EVENT
- clazz->expose_event(widget, &ev);
- }
- // spin button also contains GtkEntry, so give a chance to expose it too, so no 'else' statement
- }
- if (GTK_IS_ENTRY(widget)) {
- // single text
- GtkWidgetClass *clazz = (GtkWidgetClass *)GTK_ENTRY_GET_CLASS(widget);
- {
- PREPARE_EVENT
- ev.window = window;
- UPDATE_EVENT
- clazz->expose_event(widget, &ev);
- }
- //
- {
- PREPARE_EVENT
- ev.window = ((GtkEntry*)widget)->text_area;
- UPDATE_EVENT
- clazz->expose_event(widget, &ev);
- }
- } else if (GTK_IS_TEXT_VIEW(widget)) {
- // multi-line text
- {
- PREPARE_EVENT
- ev.window = gtk_text_view_get_window((GtkTextView *)widget, GTK_TEXT_WINDOW_TEXT);
- UPDATE_EVENT
- gtk_widget_send_expose(widget, (GdkEvent*)&ev);
- }
- } else if (GTK_IS_TREE_VIEW(widget)) {
- // tree
- GtkWidgetClass *clazz = (GtkWidgetClass *)GTK_TREE_VIEW_GET_CLASS(widget);
- GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
- {
- PREPARE_EVENT
- ev.window = gtk_tree_view_get_bin_window(tree_view);
- UPDATE_EVENT
- clazz->expose_event(widget, &ev);
- }
- } else {
- // everything else
- {
- PREPARE_EVENT
- ev.window = window;
- UPDATE_EVENT
- gtk_widget_send_expose(widget, (GdkEvent*)&ev);
- }
- }
-}
-
-static void exposeAllWidgets(GtkWidget *widget) {
- if (!GTK_IS_WIDGET(widget)) {
- return;
- }
- exposeWidget(widget);
- if (!GTK_IS_CONTAINER(widget)) {
- return;
- }
- GtkContainer *container = GTK_CONTAINER(widget);
- gtk_container_forall(container, exposeAllWidgetsCallback, 0);
-}
-
-static GdkPixmap* getPixmap(GdkWindow *window, int shouldCallback) {
- if (!gdk_window_is_visible(window)) {
- // don't deal with unmapped windows
- return NULL;
- }
- gint width, height;
- gdk_window_get_geometry(window, NULL, NULL, &width, &height, NULL);
- //
- GdkRectangle rect;
- rect.x = 0; rect.y = 0; rect.width = width; rect.height = height;
- //
- GdkRegion *region = gdk_region_rectangle(&rect);
- gdk_window_begin_paint_region(window, region);
- //
- region = gdk_region_rectangle(&rect);
- gdk_window_invalidate_region(window, region, TRUE);
- //
- gpointer widget = NULL;
- gdk_window_get_user_data(window, &widget);
- if (widget != NULL) {
- exposeAllWidgets((GtkWidget*)widget);
- }
- //
- gdk_window_process_updates(window, TRUE);
- //
- GdkWindowObject *private = (GdkWindowObject *)(window);
- GdkPixmap *internalPixmap = ((GdkWindowPaint *)private->paint_stack->data)->pixmap;
- if (internalPixmap == NULL) {
- return NULL;
- }
- //
- g_object_ref(internalPixmap);
- GdkPixmap *pixmap = copyPixmap(internalPixmap, width, height);
- gdk_window_end_paint(window);
- //
- if (shouldCallback) {
- (*m_envir)->CallVoidMethod(m_envir, m_callback, m_IScreenshotCallback_storeImage, wrap_pointer(m_envir, widget), wrap_pointer(m_envir, pixmap));
- }
- //
- return pixmap;
-}
-
-static GdkPixmap* traverse(GdkWindow *window, int shouldCallback){
- gint depth;
- gdk_window_get_geometry(window, NULL, NULL, NULL, NULL, &depth);
- // strange window
- if (depth == 0) {
- return NULL;
- }
- //
- GdkPixmap *pixmap = getPixmap(window, shouldCallback);
- if (pixmap == NULL) {
- return NULL;
- }
- //
- GdkGC *gc = gdk_gc_new(pixmap);
- GList *children = gdk_window_get_children(window);
- guint length = g_list_length(children);
- //
- guint i;
- for (i = 0; i < length; i++) {
- GdkWindow *win = g_list_nth_data(children, i);
- GdkPixmap* pix = traverse(win, shouldCallback);
- if (pix == NULL) {
- continue;
- }
- gint x, y, width, height;
- gdk_window_get_geometry(win, &x, &y, &width, &height, NULL);
- gdk_draw_drawable(pixmap, gc, pix, 0, 0, x, y, width, height);
- if (!shouldCallback) {
- g_object_unref(pix);
- }
- }
- g_object_unref(gc);
- return pixmap;
-}
-
-static void exposeAllWidgetsCallback(GtkWidget *widget, gpointer data) {
- exposeAllWidgets(widget);
-}
-static GdkPixmap* makeShot(GtkWidget* shellWidget) {
- GdkWindow *window = shellWidget->window;
- return traverse(window, m_callback != NULL);
-}
-////////////////////////////////////////////////////////////////////////////
-//
-// Widget bounds
-//
-////////////////////////////////////////////////////////////////////////////
-static void getWidgetBounds(GtkWidget* widget, JNIEnv *envir, jintArray jsizes) {
- // prepare buffer
- jsize sizesSize = (*envir)->GetArrayLength(envir, jsizes);
- jint *sizes = malloc(sizesSize * sizeof(jint));
- *(sizes + 0) = GTK_WIDGET_X(widget);
- *(sizes + 1) = GTK_WIDGET_Y(widget);
- *(sizes + 2) = GTK_WIDGET_WIDTH(widget);
- *(sizes + 3) = GTK_WIDGET_HEIGHT(widget);
- // copy dimensions into java array
- (*envir)->SetIntArrayRegion(envir, jsizes, 0, sizesSize, sizes);
- free(sizes);
-}
-////////////////////////////////////////////////////////////////////////////
-//
-// Menu
-//
-////////////////////////////////////////////////////////////////////////////
-static GdkPixmap* fetchMenuVisualData(GtkMenu *menu, JNIEnv *envir, jintArray jsizes) {
- GtkWidget *menuWidget = GTK_WIDGET (menu);
- // try to move menu window outside ot the screen
- gtk_window_move ((GtkWindow*)menu->toplevel, -100, -100);
- // display menu window
- gtk_widget_show (menuWidget);
- gtk_widget_show (menu->toplevel);
- // get menu items sizes
- // prepare buffer
- jsize sizesSize = (*envir)->GetArrayLength(envir, jsizes);
- jint *sizes = malloc(sizesSize * sizeof(jint));
- // get border thickness
- gint border_x = GTK_CONTAINER (menuWidget)->border_width + menuWidget->style->xthickness;
- gint border_y = GTK_CONTAINER (menuWidget)->border_width + menuWidget->style->ythickness;
- // traverse thru children
- GList* children = gtk_container_get_children(GTK_CONTAINER(menu));
- gint count = g_list_length (children);
- if (count > 0) {
- GtkWidget *menuItem;
- gint i;
- for (i = 0; i < count; ++i) {
- menuItem = GTK_WIDGET(g_list_nth_data(children, i));
- *(sizes + i * 4 + 0) = menuItem->allocation.x + border_x;
- *(sizes + i * 4 + 1) = menuItem->allocation.y + border_y;
- *(sizes + i * 4 + 2) = menuItem->allocation.width;
- *(sizes + i * 4 + 3) = menuItem->allocation.height;
- }
- }
- g_list_free(children);
- // copy dimensions into java array
- (*envir)->SetIntArrayRegion(envir, jsizes, 0, sizesSize, sizes);
- free(sizes);
- // make screenshot
- GdkPixmap *pixmap = NULL;
- GdkWindow *window = menu->toplevel->window;
- pixmap = traverse(window, 0);
- // hide menu
- gtk_widget_hide (menu->toplevel);
- gtk_widget_hide (GTK_WIDGET (menu));
- // all done
- return pixmap;
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// JNI
-//
-////////////////////////////////////////////////////////////////////////////
-JNIEXPORT jboolean JNICALL
- OS_NATIVE(_1toggle_1above)
- (JNIEnv *envir, jobject that, JHANDLE widgetHandle, jboolean forceToggle) {
-
- GtkWidget* shellWidget = (GtkWidget*)unwrap_pointer(envir, widgetHandle);
- GdkWindow *window = shellWidget->window;
-
- Window x11window = GDK_WINDOW_XWINDOW(window);
- Display* display = GDK_DRAWABLE_XDISPLAY(window);
- if (!isWindowAbove(display, x11window) || forceToggle == JNI_TRUE) {
- toggle_window_state_above(display, x11window);
- return JNI_TRUE;
- }
- return JNI_FALSE;
-}
-JNIEXPORT jboolean JNICALL
- OS_NATIVE(_1begin_1shot)
- (JNIEnv *envir, jobject that, JHANDLE widgetHandle) {
-
- GtkWidget* shellWidget = (GtkWidget*)unwrap_pointer(envir, widgetHandle);
- return moveWindowToDesktop(shellWidget);
-}
-JNIEXPORT jboolean JNICALL
- OS_NATIVE(_1end_1shot)
- (JNIEnv *envir, jobject that, JHANDLE widgetHandle) {
-
- GtkWidget* shellWidget = (GtkWidget*)unwrap_pointer(envir, widgetHandle);
- return restoreWindow(shellWidget);
-}
-// shot
-JNIEXPORT JHANDLE JNICALL OS_NATIVE(_1makeShot)(
- JNIEnv *envir, jobject that, JHANDLE widgetHandle, jobject callback) {
- m_envir = envir;
- if (callback != NULL) {
- m_callback = (*envir)->NewGlobalRef(envir, callback);
- jclass clazz = (*envir)->GetObjectClass(envir, m_callback);
- m_IScreenshotCallback_storeImage = (*envir)->GetMethodID(envir, clazz, "storeImage", CALLBACK_SIG);
- }
- // make shot
- GdkPixmap* pixmap = makeShot((GtkWidget*)unwrap_pointer(envir, widgetHandle));
- // clean up
- if (callback != NULL) {
- (*envir)->DeleteGlobalRef(envir, m_callback);
- }
- m_callback = NULL;
- return (JHANDLE)wrap_pointer(envir, pixmap);
-}
-// menu
-JNIEXPORT JHANDLE JNICALL OS_NATIVE(_1fetchMenuVisualData)(
- JNIEnv *envir, jobject that, JHANDLE jmenuHandle, jintArray jsizes) {
- GtkWidget* menu = (GtkWidget*)unwrap_pointer(envir, jmenuHandle);
- GdkPixmap* pixmap = fetchMenuVisualData(GTK_MENU(menu), envir, jsizes);
- return wrap_pointer(envir, pixmap);
-}
-// tab item bounds
-JNIEXPORT void JNICALL OS_NATIVE(_1getWidgetBounds)(
- JNIEnv *envir, jobject that, JHANDLE jhandle, jintArray jsizes) {
- getWidgetBounds((GtkWidget*)unwrap_pointer(envir, jhandle), envir, jsizes);
-}
-// unref
-JNIEXPORT void JNICALL OS_NATIVE(_1g_1object_1unref)(
- JNIEnv *envir, jobject that, JHANDLE jhandle) {
- g_object_unref((GObject*)unwrap_pointer(envir, jhandle));
-}
+#include "../common/wbp.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xatom.h>
+
+#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
+#define MAX_PROPERTY_VALUE_LEN 4096
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Toggle "above" state for Eclipse, move preview window to another workspace
+//
+////////////////////////////////////////////////////////////////////////////
+int m_currentDesktop = 0;
+int m_desktopCount = 0;
+
+// gets the property of the X Window
+static gchar *get_property (Display *disp, Window win, Atom xa_prop_type, gchar *prop_name, unsigned long *size) {
+ Atom xa_prop_name;
+ Atom xa_ret_type;
+ int ret_format;
+ unsigned long ret_nitems;
+ unsigned long ret_bytes_after;
+ unsigned long tmp_size;
+ unsigned char *ret_prop;
+ gchar *ret;
+
+ xa_prop_name = XInternAtom(disp, prop_name, False);
+
+ /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage):
+ *
+ * long_length = Specifies the length in 32-bit multiples of the
+ * data to be retrieved.
+ */
+ if (XGetWindowProperty(disp, win, xa_prop_name, 0, MAX_PROPERTY_VALUE_LEN / 4, False,
+ xa_prop_type, &xa_ret_type, &ret_format,
+ &ret_nitems, &ret_bytes_after, &ret_prop) != Success) {
+ return NULL;
+ }
+
+ if (xa_ret_type != xa_prop_type) {
+ XFree(ret_prop);
+ return NULL;
+ }
+
+ /* null terminate the result to make string handling easier */
+ tmp_size = (ret_format / 8) * ret_nitems;
+ ret = g_malloc(tmp_size + 1);
+ memcpy(ret, ret_prop, tmp_size);
+ ret[tmp_size] = '\0';
+
+ if (size) {
+ *size = tmp_size;
+ }
+
+ XFree(ret_prop);
+ return ret;
+}
+// sends the client message to the X Window
+static int client_msg(Display *disp, Window win, char *msg,
+ unsigned long data0, unsigned long data1,
+ unsigned long data2, unsigned long data3,
+ unsigned long data4) {
+ XEvent event;
+ long mask = SubstructureRedirectMask | SubstructureNotifyMask;
+
+ event.xclient.type = ClientMessage;
+ event.xclient.serial = 0;
+ event.xclient.send_event = True;
+ event.xclient.message_type = XInternAtom(disp, msg, False);
+ event.xclient.window = win;
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = data0;
+ event.xclient.data.l[1] = data1;
+ event.xclient.data.l[2] = data2;
+ event.xclient.data.l[3] = data3;
+ event.xclient.data.l[4] = data4;
+
+ if (XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) {
+ return EXIT_SUCCESS;
+ } else {
+ fprintf(stderr, "Cannot send %s event.\n", msg);fflush(stderr);
+ return EXIT_FAILURE;
+ }
+}
+// toggles the "above" state of the X Window
+static int toggle_window_state_above(Display *disp, Window win) {
+ unsigned long action = _NET_WM_STATE_TOGGLE;
+ Atom prop1 = XInternAtom(disp, "_NET_WM_STATE_ABOVE", False);
+ int result = client_msg(disp, win, "_NET_WM_STATE", action, (unsigned long)prop1, 0, 0, 0);
+ return result;
+}
+// determines is the X Window has "above" state
+static Bool isWindowAbove (Display *disp, Window win) {
+ Atom actual;
+ int format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ int result = XGetWindowProperty(disp, win, XInternAtom(disp, "_NET_WM_STATE", False),
+ 0L, 1024L, FALSE, XA_ATOM, &actual, &format, &n, &left, &data);
+
+ if (result == Success && n && data) {
+ Atom *a = (Atom *) data;
+ while (n--) {
+ if (XInternAtom (disp, "_NET_WM_STATE_ABOVE", 0) == *a++) {
+ XFree ((void *) data);
+ return True;
+ }
+ }
+ XFree ((void *) data);
+ }
+
+ return False;
+}
+
+static Bool isOverrideRedirect(Display* disp, Window win) {
+ XWindowAttributes attrs;
+ XGetWindowAttributes(disp, win, &attrs);
+ return attrs.override_redirect;
+}
+static void gtk_widget_show_map_callback (GtkWidget *widget, GdkEvent *event, gint *flag) {
+ *flag = TRUE;
+ g_signal_handlers_disconnect_by_func (widget,gtk_widget_show_map_callback, flag);
+}
+
+// moves the preview window onto another workspace (desktop).
+static int moveWindowToDesktop(GtkWidget *shellWidget) {
+ if (GTK_WIDGET_VISIBLE(shellWidget)) {
+ // can't do anything, because it's already visible
+ return JNI_FALSE;
+ }
+ // get underlying X resources
+ GdkWindow *window = shellWidget->window;
+ Window x11window = GDK_WINDOW_XID(window);
+ Display* disp = GDK_DRAWABLE_XDISPLAY(window);
+ // remove "override_redirect" flag
+ // https://fogbugz.instantiations.com:443/default.php?41586
+ Bool wasOverride = isOverrideRedirect(disp, x11window);
+ if (wasOverride) {
+ gdk_window_set_override_redirect(window, FALSE);
+ }
+ // disable showing preview window by any helpers
+ gtk_window_set_focus_on_map((GtkWindow*)shellWidget, FALSE);
+ gtk_window_set_skip_taskbar_hint((GtkWindow*)shellWidget, TRUE);
+ gtk_window_set_skip_pager_hint((GtkWindow*)shellWidget, TRUE);
+ // get current desktop/desktop count
+ unsigned long *desktopCountPtr = NULL;
+ unsigned long *currentDesktopPtr = NULL;
+ Window root = DefaultRootWindow(disp);
+ if (!(desktopCountPtr = (unsigned long *)get_property(disp, root,
+ XA_CARDINAL, "_NET_NUMBER_OF_DESKTOPS", NULL))) {
+ if (!(desktopCountPtr = (unsigned long *)get_property(disp, root,
+ XA_CARDINAL, "_WIN_WORKSPACE_COUNT", NULL))) {
+ return JNI_FALSE;
+ }
+ }
+ if (!(currentDesktopPtr = (unsigned long *)get_property(disp, root,
+ XA_CARDINAL, "_NET_CURRENT_DESKTOP", NULL))) {
+ if (!(currentDesktopPtr = (unsigned long *)get_property(disp, root,
+ XA_CARDINAL, "_WIN_WORKSPACE", NULL))) {
+ return JNI_FALSE;
+ }
+ }
+ m_currentDesktop = *currentDesktopPtr;
+ m_desktopCount = *desktopCountPtr;
+ g_free(currentDesktopPtr);
+ g_free(desktopCountPtr);
+ // determine the desktop number on which the preview window would be moved
+ int desktop;
+ int desktopCountActual = m_desktopCount;
+ if (m_desktopCount == 1 ) {
+ // create new desktop if the only one exists, would be removed later
+ if (!client_msg(disp, DefaultRootWindow(disp), "_NET_NUMBER_OF_DESKTOPS", 2, 0, 0, 0, 0)) {
+ // success
+ desktopCountActual++;
+ XSync(disp, False);
+ }
+ }
+ if (m_currentDesktop == desktopCountActual - 1) {
+ desktop = desktopCountActual - 2;
+ } else {
+ desktop = m_currentDesktop + 1;
+ }
+ // show widget required, only mapped windows can be moved to another desktop.
+ // this could cause flickering in rare cases (a few events in queue?)
+ gint flag = FALSE;
+ gtk_widget_show(shellWidget);
+ // move window to another desktop
+ client_msg(disp, x11window, "_NET_WM_DESKTOP", (unsigned long)desktop, 0, 0, 0, 0);
+ // wait for window to be completely shown: wait for ConfigureNotify which has no above window.
+ g_signal_connect (shellWidget, "configure-event", G_CALLBACK (gtk_widget_show_map_callback),&flag);
+ while (!flag) {
+ gtk_main_iteration();
+ }
+ if (wasOverride) {
+ gdk_window_set_override_redirect(window, TRUE);
+ }
+ // success
+ return JNI_TRUE;
+}
+
+static int restoreWindow(GtkWidget *shellWidget) {
+ if (m_desktopCount == 0) {
+ // nothing to do?
+ return JNI_FALSE;
+ }
+ // get underlying X resources
+ GdkWindow *window = shellWidget->window;
+ Display* disp = GDK_DRAWABLE_XDISPLAY(window);
+ // remove the extra desktop maybe created above
+ if (m_desktopCount == 1) {
+ client_msg(disp, DefaultRootWindow(disp), "_NET_NUMBER_OF_DESKTOPS", 1, 0, 0, 0, 0);
+ }
+ // cleanup
+ m_currentDesktop = 0;
+ m_desktopCount = 0;
+ // success
+ return JNI_TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Shell screen shot
+//
+////////////////////////////////////////////////////////////////////////////
+static GdkPixmap* copyPixmap(GdkPixmap *source, gint width, gint height) {
+ if (source) {
+ GdkPixmap* pixmap = gdk_pixmap_new(source, width, height, -1);
+ GdkGC *gc = gdk_gc_new(source);
+ gdk_draw_drawable(pixmap, gc, source, 0, 0, 0, 0, -1, -1);
+ g_object_unref(gc);
+ g_object_unref(source);
+ return pixmap;
+ }
+ return NULL;
+}
+/*
+not used because produces screenshot with errors, but may be useful in future when gtk fixes their bugs.
+static GdkPixmap* makeShot2(GtkWidget *widget) {
+ GdkPixmap* source = gtk_widget_get_snapshot(widget, NULL);
+ if (source == NULL) {
+ return NULL;
+ }
+ // determine snapshot rectangle
+ int x = widget->allocation.x;
+ int y = widget->allocation.y;
+ int width = widget->allocation.width;
+ int height = widget->allocation.height;
+ // grow snapshot rectangle to cover all widget windows
+ if (widget->parent && !GTK_WIDGET_NO_WINDOW (widget)){
+ GdkWindow *parent_window = gtk_widget_get_parent_window (widget);
+ GList *windows = NULL, *list;
+ for (list = gdk_window_peek_children (parent_window); list; list = list->next) {
+ GdkWindow *subwin = list->data;
+ gpointer windata;
+ int wx, wy, ww, wh;
+ gdk_window_get_user_data (subwin, &windata);
+ if (windata != widget) {
+ continue;
+ }
+ windows = g_list_prepend (windows, subwin);
+ gdk_window_get_position (subwin, &wx, &wy);
+ gdk_drawable_get_size (subwin, &ww, &wh);
+ // grow snapshot rectangle by extra widget sub window
+ if (wx < x) {
+ width += x - wx;
+ x = wx;
+ }
+ if (wy < y) {
+ height += y - wy;
+ y = wy;
+ }
+ if (x + width < wx + ww) {
+ width += wx + ww - (x + width);
+ }
+ if (y + height < wy + wh) {
+ height += wy + wh - (y + height);
+ }
+ }
+ } else if (!widget->parent) {
+ x = y = 0; // toplevel
+ }
+ // return it copied to avoid incompatibility with SWT.
+ return copyPixmap(source, width, height);
+}*/
+
+JNIEnv *m_envir;
+jobject m_callback;
+jmethodID m_IScreenshotCallback_storeImage;
+//
+typedef struct _GdkWindowPaint GdkWindowPaint;
+struct _GdkWindowPaint {
+ GdkRegion *region;
+ GdkPixmap *pixmap;
+ gint x_offset;
+ gint y_offset;
+};
+static void exposeAllWidgetsCallback(GtkWidget *widget, gpointer data);
+//
+#define PREPARE_EVENT \
+ GdkEventExpose ev;\
+ ev.type = GDK_EXPOSE;\
+ ev.send_event = TRUE;\
+ ev.area.x = 0;\
+ ev.area.y = 0;\
+ ev.count = 0;
+
+#define UPDATE_EVENT \
+ gdk_window_get_geometry(ev.window, NULL, NULL, &ev.area.width, &ev.area.height, NULL);\
+ ev.region = gdk_region_rectangle(&ev.area);
+
+static void exposeWidget(GtkWidget *widget) {
+ GdkWindow *window = widget->window;
+ if (!GTK_WIDGET_REALIZED(widget)) {
+ return;
+ }
+// g_warning ("type = %s", G_OBJECT_TYPE_NAME (widget));
+ if (GTK_IS_SPIN_BUTTON(widget)) {
+ // spin button
+ GtkWidgetClass *clazz = (GtkWidgetClass *)GTK_SPIN_BUTTON_GET_CLASS(widget);
+ GtkSpinButton *spin = GTK_SPIN_BUTTON (widget);
+ {
+ PREPARE_EVENT
+ ev.window = spin->panel;
+ UPDATE_EVENT
+ clazz->expose_event(widget, &ev);
+ }
+ // spin button also contains GtkEntry, so give a chance to expose it too, so no 'else' statement
+ }
+ if (GTK_IS_ENTRY(widget)) {
+ // single text
+ GtkWidgetClass *clazz = (GtkWidgetClass *)GTK_ENTRY_GET_CLASS(widget);
+ {
+ PREPARE_EVENT
+ ev.window = window;
+ UPDATE_EVENT
+ clazz->expose_event(widget, &ev);
+ }
+ //
+ {
+ PREPARE_EVENT
+ ev.window = ((GtkEntry*)widget)->text_area;
+ UPDATE_EVENT
+ clazz->expose_event(widget, &ev);
+ }
+ } else if (GTK_IS_TEXT_VIEW(widget)) {
+ // multi-line text
+ {
+ PREPARE_EVENT
+ ev.window = gtk_text_view_get_window((GtkTextView *)widget, GTK_TEXT_WINDOW_TEXT);
+ UPDATE_EVENT
+ gtk_widget_send_expose(widget, (GdkEvent*)&ev);
+ }
+ } else if (GTK_IS_TREE_VIEW(widget)) {
+ // tree
+ GtkWidgetClass *clazz = (GtkWidgetClass *)GTK_TREE_VIEW_GET_CLASS(widget);
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ {
+ PREPARE_EVENT
+ ev.window = gtk_tree_view_get_bin_window(tree_view);
+ UPDATE_EVENT
+ clazz->expose_event(widget, &ev);
+ }
+ } else {
+ // everything else
+ {
+ PREPARE_EVENT
+ ev.window = window;
+ UPDATE_EVENT
+ gtk_widget_send_expose(widget, (GdkEvent*)&ev);
+ }
+ }
+}
+
+static void exposeAllWidgets(GtkWidget *widget) {
+ if (!GTK_IS_WIDGET(widget)) {
+ return;
+ }
+ exposeWidget(widget);
+ if (!GTK_IS_CONTAINER(widget)) {
+ return;
+ }
+ GtkContainer *container = GTK_CONTAINER(widget);
+ gtk_container_forall(container, exposeAllWidgetsCallback, 0);
+}
+
+static GdkPixmap* getPixmap(GdkWindow *window, int shouldCallback) {
+ if (!gdk_window_is_visible(window)) {
+ // don't deal with unmapped windows
+ return NULL;
+ }
+ gint width, height;
+ gdk_window_get_geometry(window, NULL, NULL, &width, &height, NULL);
+ //
+ GdkRectangle rect;
+ rect.x = 0; rect.y = 0; rect.width = width; rect.height = height;
+ //
+ GdkRegion *region = gdk_region_rectangle(&rect);
+ gdk_window_begin_paint_region(window, region);
+ //
+ region = gdk_region_rectangle(&rect);
+ gdk_window_invalidate_region(window, region, TRUE);
+ //
+ gpointer widget = NULL;
+ gdk_window_get_user_data(window, &widget);
+ if (widget != NULL) {
+ exposeAllWidgets((GtkWidget*)widget);
+ }
+ //
+ gdk_window_process_updates(window, TRUE);
+ //
+ GdkWindowObject *private = (GdkWindowObject *)(window);
+ GdkPixmap *internalPixmap = ((GdkWindowPaint *)private->paint_stack->data)->pixmap;
+ if (internalPixmap == NULL) {
+ return NULL;
+ }
+ //
+ g_object_ref(internalPixmap);
+ GdkPixmap *pixmap = copyPixmap(internalPixmap, width, height);
+ gdk_window_end_paint(window);
+ //
+ if (shouldCallback) {
+ (*m_envir)->CallVoidMethod(m_envir, m_callback, m_IScreenshotCallback_storeImage, wrap_pointer(m_envir, widget), wrap_pointer(m_envir, pixmap));
+ }
+ //
+ return pixmap;
+}
+
+static GdkPixmap* traverse(GdkWindow *window, int shouldCallback){
+ gint depth;
+ gdk_window_get_geometry(window, NULL, NULL, NULL, NULL, &depth);
+ // strange window
+ if (depth == 0) {
+ return NULL;
+ }
+ //
+ GdkPixmap *pixmap = getPixmap(window, shouldCallback);
+ if (pixmap == NULL) {
+ return NULL;
+ }
+ //
+ GdkGC *gc = gdk_gc_new(pixmap);
+ GList *children = gdk_window_get_children(window);
+ guint length = g_list_length(children);
+ //
+ guint i;
+ for (i = 0; i < length; i++) {
+ GdkWindow *win = g_list_nth_data(children, i);
+ GdkPixmap* pix = traverse(win, shouldCallback);
+ if (pix == NULL) {
+ continue;
+ }
+ gint x, y, width, height;
+ gdk_window_get_geometry(win, &x, &y, &width, &height, NULL);
+ gdk_draw_drawable(pixmap, gc, pix, 0, 0, x, y, width, height);
+ if (!shouldCallback) {
+ g_object_unref(pix);
+ }
+ }
+ g_object_unref(gc);
+ return pixmap;
+}
+
+static void exposeAllWidgetsCallback(GtkWidget *widget, gpointer data) {
+ exposeAllWidgets(widget);
+}
+static GdkPixmap* makeShot(GtkWidget* shellWidget) {
+ GdkWindow *window = shellWidget->window;
+ return traverse(window, m_callback != NULL);
+}
+////////////////////////////////////////////////////////////////////////////
+//
+// Widget bounds
+//
+////////////////////////////////////////////////////////////////////////////
+static void getWidgetBounds(GtkWidget* widget, JNIEnv *envir, jintArray jsizes) {
+ // prepare buffer
+ jsize sizesSize = (*envir)->GetArrayLength(envir, jsizes);
+ jint *sizes = malloc(sizesSize * sizeof(jint));
+ *(sizes + 0) = GTK_WIDGET_X(widget);
+ *(sizes + 1) = GTK_WIDGET_Y(widget);
+ *(sizes + 2) = GTK_WIDGET_WIDTH(widget);
+ *(sizes + 3) = GTK_WIDGET_HEIGHT(widget);
+ // copy dimensions into java array
+ (*envir)->SetIntArrayRegion(envir, jsizes, 0, sizesSize, sizes);
+ free(sizes);
+}
+////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+////////////////////////////////////////////////////////////////////////////
+static GdkPixmap* fetchMenuVisualData(GtkMenu *menu, JNIEnv *envir, jintArray jsizes) {
+ GtkWidget *menuWidget = GTK_WIDGET (menu);
+ // try to move menu window outside ot the screen
+ gtk_window_move ((GtkWindow*)menu->toplevel, -100, -100);
+ // display menu window
+ gtk_widget_show (menuWidget);
+ gtk_widget_show (menu->toplevel);
+ // get menu items sizes
+ // prepare buffer
+ jsize sizesSize = (*envir)->GetArrayLength(envir, jsizes);
+ jint *sizes = malloc(sizesSize * sizeof(jint));
+ // get border thickness
+ gint border_x = GTK_CONTAINER (menuWidget)->border_width + menuWidget->style->xthickness;
+ gint border_y = GTK_CONTAINER (menuWidget)->border_width + menuWidget->style->ythickness;
+ // traverse thru children
+ GList* children = gtk_container_get_children(GTK_CONTAINER(menu));
+ gint count = g_list_length (children);
+ if (count > 0) {
+ GtkWidget *menuItem;
+ gint i;
+ for (i = 0; i < count; ++i) {
+ menuItem = GTK_WIDGET(g_list_nth_data(children, i));
+ *(sizes + i * 4 + 0) = menuItem->allocation.x + border_x;
+ *(sizes + i * 4 + 1) = menuItem->allocation.y + border_y;
+ *(sizes + i * 4 + 2) = menuItem->allocation.width;
+ *(sizes + i * 4 + 3) = menuItem->allocation.height;
+ }
+ }
+ g_list_free(children);
+ // copy dimensions into java array
+ (*envir)->SetIntArrayRegion(envir, jsizes, 0, sizesSize, sizes);
+ free(sizes);
+ // make screenshot
+ GdkPixmap *pixmap = NULL;
+ GdkWindow *window = menu->toplevel->window;
+ pixmap = traverse(window, 0);
+ // hide menu
+ gtk_widget_hide (menu->toplevel);
+ gtk_widget_hide (GTK_WIDGET (menu));
+ // all done
+ return pixmap;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// JNI
+//
+////////////////////////////////////////////////////////////////////////////
+JNIEXPORT jboolean JNICALL
+ OS_NATIVE(_1toggle_1above)
+ (JNIEnv *envir, jobject that, JHANDLE widgetHandle, jboolean forceToggle) {
+
+ GtkWidget* shellWidget = (GtkWidget*)unwrap_pointer(envir, widgetHandle);
+ GdkWindow *window = shellWidget->window;
+
+ Window x11window = GDK_WINDOW_XWINDOW(window);
+ Display* display = GDK_DRAWABLE_XDISPLAY(window);
+ if (!isWindowAbove(display, x11window) || forceToggle == JNI_TRUE) {
+ toggle_window_state_above(display, x11window);
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+}
+JNIEXPORT jboolean JNICALL
+ OS_NATIVE(_1begin_1shot)
+ (JNIEnv *envir, jobject that, JHANDLE widgetHandle) {
+
+ GtkWidget* shellWidget = (GtkWidget*)unwrap_pointer(envir, widgetHandle);
+ return moveWindowToDesktop(shellWidget);
+}
+JNIEXPORT jboolean JNICALL
+ OS_NATIVE(_1end_1shot)
+ (JNIEnv *envir, jobject that, JHANDLE widgetHandle) {
+
+ GtkWidget* shellWidget = (GtkWidget*)unwrap_pointer(envir, widgetHandle);
+ return restoreWindow(shellWidget);
+}
+// shot
+JNIEXPORT JHANDLE JNICALL OS_NATIVE(_1makeShot)(
+ JNIEnv *envir, jobject that, JHANDLE widgetHandle, jobject callback) {
+ m_envir = envir;
+ if (callback != NULL) {
+ m_callback = (*envir)->NewGlobalRef(envir, callback);
+ jclass clazz = (*envir)->GetObjectClass(envir, m_callback);
+ m_IScreenshotCallback_storeImage = (*envir)->GetMethodID(envir, clazz, "storeImage", CALLBACK_SIG);
+ }
+ // make shot
+ GdkPixmap* pixmap = makeShot((GtkWidget*)unwrap_pointer(envir, widgetHandle));
+ // clean up
+ if (callback != NULL) {
+ (*envir)->DeleteGlobalRef(envir, m_callback);
+ }
+ m_callback = NULL;
+ return (JHANDLE)wrap_pointer(envir, pixmap);
+}
+// menu
+JNIEXPORT JHANDLE JNICALL OS_NATIVE(_1fetchMenuVisualData)(
+ JNIEnv *envir, jobject that, JHANDLE jmenuHandle, jintArray jsizes) {
+ GtkWidget* menu = (GtkWidget*)unwrap_pointer(envir, jmenuHandle);
+ GdkPixmap* pixmap = fetchMenuVisualData(GTK_MENU(menu), envir, jsizes);
+ return wrap_pointer(envir, pixmap);
+}
+// tab item bounds
+JNIEXPORT void JNICALL OS_NATIVE(_1getWidgetBounds)(
+ JNIEnv *envir, jobject that, JHANDLE jhandle, jintArray jsizes) {
+ getWidgetBounds((GtkWidget*)unwrap_pointer(envir, jhandle), envir, jsizes);
+}
+// unref
+JNIEXPORT void JNICALL OS_NATIVE(_1disposeImageHandle)(
+ JNIEnv *envir, jobject that, JHANDLE jhandle) {
+ g_object_unref((GObject*)unwrap_pointer(envir, jhandle));
+}
+// other
+static int isValidVersion() {
+ return gtk_major_version == 2 && gtk_minor_version >= 12;
+}
+static jboolean isPlusMinusTreeClick(GtkTreeView *tree, gint x, gint y) {
+ gint cell_x;
+ gint cell_y;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ //
+ if (gtk_tree_view_get_path_at_pos(tree, x, y, &path, &column, &cell_x, &cell_y)) {
+ GtkTreeViewColumn *expanderColumn = gtk_tree_view_get_expander_column(tree);
+ if (expanderColumn == column) {
+ GdkRectangle rect;
+ gtk_tree_view_get_cell_area(tree, path, column, &rect);
+ if (x < rect.x) {
+ return JNI_TRUE;
+ }
+ }
+ }
+ return JNI_FALSE;
+
+}
+JNIEXPORT void JNICALL OS_NATIVE(_1setAlpha)(
+ JNIEnv *envir, jobject that, JHANDLE jshellHandle, jint jalpha) {
+ if (isValidVersion()) {
+ GtkWidget *shell = (GtkWidget*)unwrap_pointer(envir, jshellHandle);
+ if (gtk_widget_is_composited(shell)) {
+ int alpha = (int)jalpha;
+ alpha &= 0xFF;
+ gtk_window_set_opacity((GtkWindow*)shell, alpha / 255.0);
+ }
+ }
+}
+
+JNIEXPORT jint JNICALL OS_NATIVE(_1getAlpha)(
+ JNIEnv *envir, jobject that, JHANDLE jshellHandle) {
+ if (isValidVersion()) {
+ GtkWidget *shell = (GtkWidget*)unwrap_pointer(envir, jshellHandle);
+ if (gtk_widget_is_composited(shell)) {
+ return (jint) (gtk_window_get_opacity((GtkWindow*)shell) * 255);
+ }
+ }
+ return 255;
+}
+JNIEXPORT jboolean JNICALL OS_NATIVE(_1isPlusMinusTreeClick)(
+ JNIEnv *envir, jobject that, JHANDLE jhandle, jint jx, jint jy) {
+ return isPlusMinusTreeClick((GtkTreeView*)unwrap_pointer(envir, jhandle), (gint)jx, (gint)jy);
+}
+
diff --git a/org.eclipse.wb.os.linux/native/gtk/gtk3/CMakeLists.txt b/org.eclipse.wb.os.linux/native/gtk/gtk3/CMakeLists.txt
new file mode 100644
index 00000000..4f47f766
--- /dev/null
+++ b/org.eclipse.wb.os.linux/native/gtk/gtk3/CMakeLists.txt
@@ -0,0 +1,30 @@
+project(wbp-libs C)
+cmake_minimum_required(VERSION 2.6)
+
+if (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(WBPLIBS_BITNESS_DEF "-DWBP_ARCH64")
+else()
+ set(WBPLIBS_BITNESS_DEF "-DWBP_ARCH32")
+endif()
+
+find_package(JNI REQUIRED)
+if (NOT JNI_FOUND)
+ message (FATAL_ERROR "Cannot found JNI dev files")
+endif()
+include_directories(${JNI_INCLUDE_DIRS})
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(GTK3 REQUIRED "gtk+-3.0")
+if (GTK3_FOUND)
+ include_directories(${GTK3_INCLUDE_DIRS})
+ link_directories(${GTK3_LIBRARY_DIRS})
+ add_definitions(${GTK3_CFLAGS_OTHER})
+ add_definitions(${WBPLIBS_BITNESS_DEF})
+ add_library(wbp3 SHARED ../common/utils.c rcp.c)
+ target_link_libraries(wbp3 ${GTK3_LIBRARIES})
+else()
+ message (FATAL_ERROR "Cannot found dev libs for Gtk3")
+endif()
+
+
+
diff --git a/org.eclipse.wb.os.linux/native/gtk/gtk3/rcp.c b/org.eclipse.wb.os.linux/native/gtk/gtk3/rcp.c
new file mode 100644
index 00000000..b75285ff
--- /dev/null
+++ b/org.eclipse.wb.os.linux/native/gtk/gtk3/rcp.c
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Google, Inc. - initial API and implementation
+ * Alexander Mitin <Alexander.Mitin@gmail.com> Gtk3 support
+ *******************************************************************************/
+#include "../common/wbp.h"
+#include <stdlib.h>
+#include <string.h>
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Widget bounds
+//
+////////////////////////////////////////////////////////////////////////////
+static void getWidgetBounds(GtkWidget* widget, JNIEnv *envir, jintArray jsizes) {
+ GtkAllocation a;
+ // prepare buffer
+ jsize sizesSize = (*envir)->GetArrayLength(envir, jsizes);
+ jint *sizes = malloc(sizesSize * sizeof(jint));
+ memset(&a, 0, sizeof(GtkAllocation));
+ gtk_widget_get_allocation(widget, &a);
+ *(sizes + 0) = a.x;
+ *(sizes + 1) = a.y;
+ *(sizes + 2) = a.width;
+ *(sizes + 3) = a.height;
+ // copy dimensions into java array
+ (*envir)->SetIntArrayRegion(envir, jsizes, 0, sizesSize, sizes);
+ free(sizes);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Screenshot
+//
+////////////////////////////////////////////////////////////////////////////
+JNIEnv *m_envir;
+jobject m_callback;
+jmethodID m_IScreenshotCallback_storeImage;
+
+/* for debug purposes uncomment this and add void log(String msg) method to callback object class
+jmethodID m_IScreenshotCallback_log;
+static void logJava(char *str, void *p) {
+ char buf[1024];
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "%s = %p", str, p);
+ jobject jstr = (*m_envir)->NewStringUTF(m_envir, buf);
+ (*m_envir)->CallVoidMethod(m_envir, m_callback, m_IScreenshotCallback_log, jstr);
+ (*m_envir)->DeleteLocalRef(m_envir, jstr);
+} */
+
+static cairo_surface_t* copyImageSurface(GdkWindow *sourceWindow, gint width, gint height) {
+ cairo_surface_t *targetSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+ cairo_t *cr = cairo_create(targetSurface);
+ gdk_cairo_set_source_window(cr, sourceWindow, 0, 0);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+ cairo_surface_flush(targetSurface);
+ return targetSurface;
+}
+
+static cairo_surface_t* getImageSurface(GdkWindow *window) {
+ if (!gdk_window_is_visible(window)) {
+ // don't deal with unmapped windows
+ return NULL;
+ }
+ gint width, height;
+ gdk_window_get_geometry(window, NULL, NULL, &width, &height);
+ // force paint. Note, not all widgets do this completely, known so far is GtkTreeViewer.
+ GdkRectangle rect;
+ rect.x = 0; rect.y = 0; rect.width = width; rect.height = height;
+ gdk_window_begin_paint_rect(window, &rect);
+ gdk_window_invalidate_rect(window, &rect, TRUE);
+ // access a widget registered with the window
+ gpointer widget = NULL;
+ gdk_window_get_user_data(window, &widget);
+ // end force paint and copy image
+ gdk_window_process_updates(window, TRUE);
+ gdk_window_end_paint(window);
+ cairo_surface_t *surface = copyImageSurface(window, width, height);
+ // get Java code notified
+ if (m_callback) {
+ (*m_envir)->CallVoidMethod(m_envir, m_callback, m_IScreenshotCallback_storeImage, wrap_pointer(m_envir, widget), wrap_pointer(m_envir, surface));
+ }
+ // done
+ return surface;
+}
+
+static cairo_surface_t* traverse(GdkWindow *window) {
+ cairo_surface_t *surface = getImageSurface(window);
+ if (surface == NULL) {
+ return NULL;
+ }
+ GList *children = gdk_window_get_children(window);
+ guint length = g_list_length(children);
+ guint i;
+ for (i = 0; i < length; i++) {
+ GdkWindow *win = g_list_nth_data(children, i);
+ cairo_surface_t* sur = traverse(win);
+ if (sur == NULL) {
+ continue;
+ }
+ if (!m_callback) {
+ cairo_surface_destroy(sur);
+ }
+ }
+ return surface;
+}
+
+static cairo_surface_t *makeShot(GtkWidget* shellWidget) {
+ GdkWindow *window = gtk_widget_get_window(shellWidget);
+ return traverse(window);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+////////////////////////////////////////////////////////////////////////////
+
+// A (partial) copy of GtkMenuPrivate struct to get an access to toplevel widget.
+// Careful, this struct could be changed in Gtk in future, so this must be kept
+// in sync to avoid crashing.
+typedef struct _GtkMenuPrivateCopy
+{
+ GtkWidget *parent_menu_item;
+ GtkWidget *old_active_menu_item;
+
+ GtkAccelGroup *accel_group;
+ gchar *accel_path;
+
+ GtkMenuPositionFunc position_func;
+ gpointer position_func_data;
+ GDestroyNotify position_func_data_destroy;
+ gint position_x;
+ gint position_y;
+
+ guint toggle_size;
+ guint accel_size;
+
+ GtkWidget *toplevel;
+} GtkMenuPrivateCopy;
+
+static cairo_surface_t* fetchMenuVisualData(GtkMenu *menu, JNIEnv *envir, jintArray jsizes) {
+ m_callback = NULL;
+ GtkWidget *menuWidget = GTK_WIDGET (menu);
+ GtkMenuPrivateCopy *priv = (GtkMenuPrivateCopy*)menu->priv;
+ // try to move menu window outside of the screen
+ gtk_window_move((GtkWindow*)priv->toplevel, -1000, -1000);
+ // display menu window
+ gtk_widget_show_now(menuWidget);
+ gtk_widget_show_now(priv->toplevel);
+ // get menu items sizes
+ // prepare buffer
+ jsize sizesSize = (*envir)->GetArrayLength(envir, jsizes);
+ jint *sizes = malloc(sizesSize * sizeof(jint));
+ // traverse thru children
+ GList* children = gtk_container_get_children(GTK_CONTAINER(menu));
+ gint count = g_list_length (children);
+ if (count > 0) {
+ GtkWidget *menuItem;
+ gint i;
+ for (i = 0; i < count; ++i) {
+ GtkAllocation a;
+ menuItem = GTK_WIDGET(g_list_nth_data(children, i));
+ gtk_widget_get_allocation(menuItem, &a);
+ *(sizes + i * 4 + 0) = a.x;
+ *(sizes + i * 4 + 1) = a.y;
+ *(sizes + i * 4 + 2) = a.width;
+ *(sizes + i * 4 + 3) = a.height;
+ }
+ }
+ g_list_free(children);
+ // copy dimensions into java array
+ (*envir)->SetIntArrayRegion(envir, jsizes, 0, sizesSize, sizes);
+ free(sizes);
+ // make screenshot
+ cairo_surface_t *surface = NULL;
+ GdkWindow *window = gtk_widget_get_window(menuWidget);
+ surface = traverse(window);
+ // hide menu
+ gtk_widget_hide(priv->toplevel);
+ gtk_widget_hide(GTK_WIDGET (menu));
+ // all done
+ return surface;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// JNI
+//
+////////////////////////////////////////////////////////////////////////////
+JNIEXPORT jboolean JNICALL
+ OS_NATIVE(_1toggle_1above)
+ (JNIEnv *envir, jobject that, JHANDLE widgetHandle, jboolean forceToggle) {
+ // NOT IMPLEMENTED
+ return JNI_TRUE;
+}
+JNIEXPORT jboolean JNICALL
+ OS_NATIVE(_1begin_1shot)
+ (JNIEnv *envir, jobject that, JHANDLE widgetHandle) {
+ // just show it
+ gtk_widget_show_now((GtkWidget*)unwrap_pointer(envir, widgetHandle));
+ return JNI_TRUE;
+}
+JNIEXPORT jboolean JNICALL
+ OS_NATIVE(_1end_1shot)
+ (JNIEnv *envir, jobject that, JHANDLE widgetHandle) {
+ // hide then
+ gtk_widget_hide((GtkWidget*)unwrap_pointer(envir, widgetHandle));
+ return JNI_TRUE;
+}
+// shot
+JNIEXPORT JHANDLE JNICALL OS_NATIVE(_1makeShot)(
+ JNIEnv *envir, jobject that, JHANDLE widgetHandle, jobject callback) {
+ m_envir = envir;
+ if (callback != NULL) {
+ m_callback = (*envir)->NewGlobalRef(envir, callback);
+ jclass clazz = (*envir)->GetObjectClass(envir, m_callback);
+ m_IScreenshotCallback_storeImage = (*envir)->GetMethodID(envir, clazz, "storeImage", CALLBACK_SIG);
+ /* uncomment this for debug purposes
+ m_IScreenshotCallback_log = (*envir)->GetMethodID(envir, clazz, "log", "(Ljava/lang/String;)V"); */
+ }
+ // make shot
+ cairo_surface_t* surface = makeShot((GtkWidget*)unwrap_pointer(envir, widgetHandle));
+ // clean up
+ if (callback != NULL) {
+ (*envir)->DeleteGlobalRef(envir, m_callback);
+ }
+ m_callback = NULL;
+ return (JHANDLE)wrap_pointer(envir, surface);
+}
+// menu
+JNIEXPORT JHANDLE JNICALL OS_NATIVE(_1fetchMenuVisualData)(
+ JNIEnv *envir, jobject that, JHANDLE jmenuHandle, jintArray jsizes) {
+ GtkWidget* menu = (GtkWidget*)unwrap_pointer(envir, jmenuHandle);
+ cairo_surface_t* surface = fetchMenuVisualData(GTK_MENU(menu), envir, jsizes);
+ return wrap_pointer(envir, surface);
+}
+// tab item bounds
+JNIEXPORT void JNICALL OS_NATIVE(_1getWidgetBounds)(
+ JNIEnv *envir, jobject that, JHANDLE jhandle, jintArray jsizes) {
+ getWidgetBounds((GtkWidget*)unwrap_pointer(envir, jhandle), envir, jsizes);
+}
+// unref
+JNIEXPORT void JNICALL OS_NATIVE(_1disposeImageHandle)(
+ JNIEnv *envir, jobject that, JHANDLE jhandle) {
+ cairo_surface_destroy((cairo_surface_t*)unwrap_pointer(envir, jhandle));
+}
+// other
+static int isValidVersion() {
+ return gtk_major_version == 3 && gtk_minor_version >= 0;
+}
+static jboolean isPlusMinusTreeClick(GtkTreeView *tree, gint x, gint y) {
+ gint cell_x;
+ gint cell_y;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ //
+ if (gtk_tree_view_get_path_at_pos(tree, x, y, &path, &column, &cell_x, &cell_y)) {
+ GtkTreeViewColumn *expanderColumn = gtk_tree_view_get_expander_column(tree);
+ if (expanderColumn == column) {
+ GdkRectangle rect;
+ gtk_tree_view_get_cell_area(tree, path, column, &rect);
+ if (x < rect.x) {
+ return JNI_TRUE;
+ }
+ }
+ }
+ return JNI_FALSE;
+
+}
+JNIEXPORT void JNICALL OS_NATIVE(_1setAlpha)(
+ JNIEnv *envir, jobject that, JHANDLE jshellHandle, jint jalpha) {
+ if (isValidVersion()) {
+ GtkWidget *shell = (GtkWidget*)unwrap_pointer(envir, jshellHandle);
+ if (gtk_widget_is_composited(shell)) {
+ int alpha = (int)jalpha;
+ alpha &= 0xFF;
+ gtk_widget_set_opacity(shell, alpha / 255.0);
+ }
+ }
+}
+
+JNIEXPORT jint JNICALL OS_NATIVE(_1getAlpha)(
+ JNIEnv *envir, jobject that, JHANDLE jshellHandle) {
+ if (isValidVersion()) {
+ GtkWidget *shell = (GtkWidget*)unwrap_pointer(envir, jshellHandle);
+ if (gtk_widget_is_composited(shell)) {
+ return (jint) (gtk_widget_get_opacity(shell) * 255);
+ }
+ }
+ return 255;
+}
+JNIEXPORT jboolean JNICALL OS_NATIVE(_1isPlusMinusTreeClick)(
+ JNIEnv *envir, jobject that, JHANDLE jhandle, jint jx, jint jy) {
+ return isPlusMinusTreeClick((GtkTreeView*)unwrap_pointer(envir, jhandle), (gint)jx, (gint)jy);
+}
+
diff --git a/org.eclipse.wb.os.linux/os/linux/amd64/libwbp.so b/org.eclipse.wb.os.linux/os/linux/amd64/libwbp.so
index b122a174..65efc495 100644..100755
--- a/org.eclipse.wb.os.linux/os/linux/amd64/libwbp.so
+++ b/org.eclipse.wb.os.linux/os/linux/amd64/libwbp.so
Binary files differ
diff --git a/org.eclipse.wb.os.linux/os/linux/amd64/libwbp3.so b/org.eclipse.wb.os.linux/os/linux/amd64/libwbp3.so
new file mode 100755
index 00000000..37a37adf
--- /dev/null
+++ b/org.eclipse.wb.os.linux/os/linux/amd64/libwbp3.so
Binary files differ
diff --git a/org.eclipse.wb.os.linux/os/linux/x86/libwbp.so b/org.eclipse.wb.os.linux/os/linux/x86/libwbp.so
index 2a8a7c52..c638144b 100755
--- a/org.eclipse.wb.os.linux/os/linux/x86/libwbp.so
+++ b/org.eclipse.wb.os.linux/os/linux/x86/libwbp.so
Binary files differ
diff --git a/org.eclipse.wb.os.linux/os/linux/x86/libwbp3.so b/org.eclipse.wb.os.linux/os/linux/x86/libwbp3.so
new file mode 100755
index 00000000..897f6ae6
--- /dev/null
+++ b/org.eclipse.wb.os.linux/os/linux/x86/libwbp3.so
Binary files differ
diff --git a/org.eclipse.wb.os.linux/os/linux/x86_64/libwbp.so b/org.eclipse.wb.os.linux/os/linux/x86_64/libwbp.so
index 0267b494..65efc495 100755
--- a/org.eclipse.wb.os.linux/os/linux/x86_64/libwbp.so
+++ b/org.eclipse.wb.os.linux/os/linux/x86_64/libwbp.so
Binary files differ
diff --git a/org.eclipse.wb.os.linux/os/linux/x86_64/libwbp3.so b/org.eclipse.wb.os.linux/os/linux/x86_64/libwbp3.so
new file mode 100755
index 00000000..37a37adf
--- /dev/null
+++ b/org.eclipse.wb.os.linux/os/linux/x86_64/libwbp3.so
Binary files differ
diff --git a/org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/IScreenshotCallback.java b/org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/IScreenshotCallback.java
index e0f17f14..92fc0bb5 100644
--- a/org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/IScreenshotCallback.java
+++ b/org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/IScreenshotCallback.java
@@ -13,14 +13,14 @@ package org.eclipse.wb.internal.os.linux;
/**
* The callback interface for screen shot support. See details in
* {@link OSSupportLinux#makeShots(Object)}.
- *
+ *
* @author mitin_aa
* @coverage os.linux
*/
public interface IScreenshotCallback<H extends Number> {
/**
* Called from native code when the <code>pixmap</code> available for <code>handle</code>.
- *
+ *
* @param handle
* the handle of widget (GtkWidget*).
* @param pixmap
diff --git a/org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/OSSupportLinux.java b/org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/OSSupportLinux.java
index f12b57eb..664736fb 100644
--- a/org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/OSSupportLinux.java
+++ b/org.eclipse.wb.os.linux/src/org/eclipse/wb/internal/os/linux/OSSupportLinux.java
@@ -12,9 +12,9 @@ package org.eclipse.wb.internal.os.linux;
/**
* OSSupport for Linux.
- *
+ *
* @author mitin_aa
- *
+ *
* @coverage os.linux
*/
import com.google.common.collect.Maps;
@@ -56,7 +56,15 @@ import java.util.Set;
public abstract class OSSupportLinux<H extends Number> extends OSSupport {
static {
- System.loadLibrary("wbp");
+ String libName;
+ try {
+ Class<?> OSClass = Class.forName("org.eclipse.swt.internal.gtk.OS");
+ boolean isGtk3 = ReflectionUtils.getFieldBoolean(OSClass, "GTK3");
+ libName = isGtk3 ? "wbp3" : "wbp";
+ } catch (Throwable e) {
+ libName = "wbp";
+ }
+ System.loadLibrary(libName);
}
// constants
private static final Color TITLE_BORDER_COLOR_DARKEST = DrawUtils.getShiftedColor(
@@ -101,7 +109,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
/**
* Registers the control to be checked in screen shot callback. Every control can be registered
- * multiple times. The first pixmap received for this control in callback is "root" for this
+ * multiple times. The first image handle received for this control in callback is "root" for this
* control and should be bound as {@link Image}.
*/
private void registerControl(Control control) throws Exception {
@@ -137,7 +145,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
/**
* Gets the {@link Shell} of given {@link Control}.
- *
+ *
* @return the found parent {@link Shell} or throws {@link AssertionFailedException} if the given
* <code>controlObject</code> is not instance of {@link Control}.
*/
@@ -156,9 +164,9 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
// prepare
_begin_shot(getShellHandle(shell));
try {
- // Bug/feature is SWT: since the widget is already shown, the Shell.setVisible() invocation
+ // Bug/feature is SWT: since the widget is already shown, the Shell.setVisible() invocation
// has no effect, so we've end up with wrong shell trimming.
- // The workaround is to call adjustTrim() explicitly.
+ // The workaround is to call adjustTrim() explicitly.
ReflectionUtils.invokeMethod(shell, "adjustTrim()", new Object[0]);
} catch (Throwable e) {
DesignerPlugin.log(e);
@@ -208,45 +216,45 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
/**
* Screen shot algorithm is the following:
- *
+ *
* <pre>
* 1. Register controls which requires the image. See {@link #registerControl(Control)}.
* 2. Create the callback, which should be passed into native code. See {@link #_makeShot(int, IScreenshotCallback)}.
- * 3. While traversing the gtk widgets/gdk windows in native code, the callback returns native widget handle and the pixmap
- * for it (see {@link IScreenshotCallback}). At this time if the control found in registry, the received pixmap converted
- * into {@link Image} and bind to control (see {@link #bindImage(Display, Control, int)}).
- * Otherwise, the pixmap is disposed later (because it may be used in drawing in native code).
- * 4. Since its not possible to capture window decorations, it needs to be drawn manually. The root shell image replaced with
- * the one with decorations (if applicable/available to draw).
+ * 3. While traversing the gtk widgets/gdk windows in native code, the callback returns native widget handle and the image handle
+ * for it (see {@link IScreenshotCallback}). At this time if the control found in registry, the received image handle converted
+ * into {@link Image} and bound to control (see {@link #bindImage(Display, Control, int)}).
+ * Otherwise, the image handle is disposed later (because it may be used in drawing in native code).
+ * 4. Since its not possible to capture window decorations, it needs to be drawn manually. The root shell image replaced with
+ * the one with decorations (if applicable/available to draw).
* </pre>
*/
private void makeShots0(final Shell shell) throws Exception {
prepareScreenshot(shell);
// get the handle for the root window
H shellHandle = getShellHandle(shell);
- final Set<H> disposePixmaps = Sets.newHashSet();
+ final Set<H> disposeImageHandles = Sets.newHashSet();
// apply shot magic
_makeShot(shellHandle, new IScreenshotCallback<H>() {
- public void storeImage(H handle, H pixmap) {
- // get the registered control by handle
+ public void storeImage(H handle, H imageHandle) {
+ // get the registered control by handle
Control imageForControl = m_controlsRegistry.get(handle);
- if (imageForControl == null || !bindImage(imageForControl, pixmap)) {
- // this means given pixmap used to draw the gtk widget internally
- disposePixmaps.add(pixmap);
+ if (imageForControl == null || !bindImage(imageForControl, imageHandle)) {
+ // this means given image handle used to draw the gtk widget internally
+ disposeImageHandles.add(imageHandle);
}
}
});
- // done, dispose pixmaps needed to draw internally.
- for (H pixmap : disposePixmaps) {
- _g_object_unref(pixmap);
+ // done, dispose image handles needed to draw internally.
+ for (H imageHandle : disposeImageHandles) {
+ _disposeImageHandle(imageHandle);
}
}
- private boolean bindImage(final Control control, final H pixmap) {
+ private boolean bindImage(final Control control, final H imageHandle) {
return ExecutionUtils.runObject(new RunnableObjectEx<Boolean>() {
public Boolean runObject() throws Exception {
if (control.getData(WBP_NEED_IMAGE) != null && control.getData(WBP_IMAGE) == null) {
- Image image = createImage(pixmap);
+ Image image = createImage(imageHandle);
control.setData(WBP_IMAGE, image);
return true;
}
@@ -276,8 +284,8 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
widgetHandle = getHandleValue(shell, "handle");
}
// apply shot magic
- H pixmap = _makeShot(widgetHandle, null);
- return createImage(pixmap);
+ H imageHandle = _makeShot(widgetHandle, null);
+ return createImage(imageHandle);
} finally {
shell.setVisible(false);
restoreTitle(shell);
@@ -291,9 +299,9 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
Rectangle shellBounds = shell.getBounds();
Image shellImage = (Image) shell.getData(WBP_IMAGE);
if (shellImage != null) {
- // 27.02.2008: while using some window managers, such as compiz, the returned Shell
+ // 27.02.2008: while using some window managers, such as compiz, the returned Shell
// bounds are not include the window decorations geometry.
- // 17.11.2008: compiz works fine with GTK 2.14 and later
+ // 17.11.2008: compiz works fine with GTK 2.14 and later
Rectangle imageBounds = shellImage.getBounds();
if (imageBounds.width != shellBounds.width || imageBounds.height != shellBounds.height) {
Point offset = shell.toControl(shell.getLocation());
@@ -382,7 +390,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
/**
* Calls native code, pass there the handle of {@link Control} and returns widget's bounds as
* {@link Rectangle}.
- *
+ *
* @return the widget's bounds as {@link Rectangle}.
*/
private Rectangle getWidgetBounds(Object widget) {
@@ -412,25 +420,17 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
/**
* @return the Image instance created by SWT internal method Image.gtk_new which uses external
- * GtkPixmap* pointer.
+ * GtkPixmap* or cairo_surface_t* pointer.
*/
- protected abstract Image createImage0(H pixmap) throws Exception;
-
- private Image createImage(H pixmap) throws Exception {
- Image image = createImage0(pixmap);
- {
- // BUG in SWT: Cairo surface is not fully initialized.
- // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=382175
- try {
- Number surfaceValue = (Number) ReflectionUtils.getFieldObject(image, "surface");
- if (surfaceValue.longValue() != 0) {
- image.getImageData();
- }
- } catch (Throwable e) {
- // ignore
- }
- }
- return image;
+ protected abstract Image createImage0(H imageHandle) throws Exception;
+
+ private Image createImage(H imageHandle) throws Exception {
+ Image image = createImage0(imageHandle);
+ // BUG in SWT: Image instance is not fully initialized
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=382175
+ Image newImage = new Image(null, image.getImageData());
+ image.dispose();
+ return newImage;
}
////////////////////////////////////////////////////////////////////////////
@@ -442,9 +442,9 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
public Image getMenuPopupVisualData(Menu menu, int[] bounds) throws Exception {
// create new image and fetch item sizes
H handle = getHandleValue(menu, "handle");
- H pixmap = _fetchMenuVisualData(handle, bounds);
+ H imageHandle = _fetchMenuVisualData(handle, bounds);
// set new handle to image
- return createImage(pixmap);
+ return createImage(imageHandle);
}
/**
@@ -534,7 +534,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
/**
* Sets the <code>alpha</code> value for given <code>shell</code>.
- *
+ *
* @param shellHandle
* the handle of {@link Shell}.
* @param alpha
@@ -544,7 +544,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
/**
* Returns the current alpha value for given <code>shellHandle</code>.
- *
+ *
* @param shellHandle
* the handle of {@link Shell}.
* @return the alpha value.
@@ -553,7 +553,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
/**
* Fills the given array of int with bounds as x, y, width, height sequence.
- *
+ *
* @param widgetHandle
* the handle (GtkWidget*) of widget.
* @param bounds
@@ -562,37 +562,37 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
private static native <H extends Number> void _getWidgetBounds(H widgetHandle, int[] bounds);
/**
- * Fetches the menu data: returns item bounds as plain array and the pixmap of menu image.
- *
+ * Fetches the menu data: returns item bounds as plain array and the image handle of menu image.
+ *
* @param menuHandle
* the handle (GtkWidget*) of menu.
* @param bounds
* the array of integer with size 4 * menu item count.
- * @return the GdkPixmap* of menu widget.
+ * @return the GdkPixmap* or cairo_surface_t* of menu widget.
*/
private static native <H extends Number> H _fetchMenuVisualData(H menuHandle, int[] bounds);
/**
* Causes taking the screen shot.
- *
+ *
* @param windowHandle
* the handle (GtkWidget*) of root gtk widget of {@link Shell}.
* @param callback
* the instance of {@link IScreenshotCallback}. Can be <code>null</code>.
- * @return the GdkPixmap* of {@link Shell}.
+ * @return the GdkPixmap* or cairo_surface_t* of {@link Shell}.
*/
private static native <H extends Number> H _makeShot(H windowHandle,
IScreenshotCallback<H> callback);
/**
- * Simply calls g_object_unref() for given <code>widgetHandle</code>.
+ * Do dispose for given <code>imageHandle</code>.
*/
- private static native <H extends Number> void _g_object_unref(H widgetHandle);
+ private static native <H extends Number> void _disposeImageHandle(H imageHandle);
/**
* Toggles the "above" X Window property. If <code>forceToggle</code> is <code>false</code> then
* no toggling if window already has the "above" property set.
- *
+ *
* @param windowHandle
* the handle (GtkWidget*) of root gtk widget of {@link Shell}.
* @param forceToggle
@@ -627,7 +627,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
}
@Override
- protected Image createImage0(Long pixmap) throws Exception {
+ protected Image createImage0(Long imageHandle) throws Exception {
return (Image) ReflectionUtils.invokeMethod2(
Image.class,
"gtk_new",
@@ -637,7 +637,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
long.class,
null,
SWT.BITMAP,
- pixmap.longValue(),
+ imageHandle.longValue(),
0);
}
}
@@ -652,7 +652,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
}
@Override
- protected Image createImage0(Integer pixmap) throws Exception {
+ protected Image createImage0(Integer imageHandle) throws Exception {
return (Image) ReflectionUtils.invokeMethod2(
Image.class,
"gtk_new",
@@ -662,7 +662,7 @@ public abstract class OSSupportLinux<H extends Number> extends OSSupport {
int.class,
null,
SWT.BITMAP,
- pixmap.intValue(),
+ imageHandle.intValue(),
0);
}
}

Back to the top