Compare commits
262 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c53063e2f | |||
| 7e08f94c9a | |||
| f549b02a09 | |||
| 08111aea4c | |||
| 975a3424e7 | |||
| 00eab88efc | |||
| dd498d825f | |||
| 88a1d2584a | |||
| acad37d372 | |||
| c5ae193124 | |||
| 535e6c5c6e | |||
| 251f318ff8 | |||
| 811019f261 | |||
| aeaa762b7e | |||
| 992cfb285c | |||
| c7327d2bc5 | |||
| 5b2be2f6f1 | |||
| b51662cafa | |||
| a328313885 | |||
| 8528385c80 | |||
| c7eba11400 | |||
| 2cb50c9af2 | |||
| bc5e401de4 | |||
| fb99b5eeb4 | |||
| d6e23b0924 | |||
| 42c0d95791 | |||
| 6d7ac9e87e | |||
| 607a1e8fc5 | |||
| 02eeed70bd | |||
| 849661a573 | |||
| ca84ac7a6a | |||
| 8d421b2af2 | |||
| b2776581da | |||
| f7eb9edb9b | |||
| fe87311f51 | |||
| c38159d4d7 | |||
| 075911ccfd | |||
| 20a5364a5f | |||
| 4a3037574d | |||
| fee9840d52 | |||
| 10bd4f8a72 | |||
| 1d986aa8a4 | |||
| 33790437ce | |||
| 239f52d543 | |||
| f2d71d3da5 | |||
| 61e625d9a6 | |||
| 9e3330c90b | |||
| 108c831e23 | |||
| 77f071b5ff | |||
| fb35e29a19 | |||
| b1f4497697 | |||
| 29569e6049 | |||
| c201145d02 | |||
| eb214aae74 | |||
| fbef4384aa | |||
| 88909ac9b2 | |||
| 84d9872a26 | |||
| 576ba1a03d | |||
| bb448f619c | |||
| 9827003e06 | |||
| 14100b867c | |||
| 5926e3cfec | |||
| e09d7b5456 | |||
| c9b8f866df | |||
| eea525ac89 | |||
| 76e7a9e5b7 | |||
| 5a523e500b | |||
| 33ea7850c9 | |||
| 9856a2faeb | |||
| a19c4b207c | |||
| 264739e6ad | |||
| 10b4eaa10b | |||
| be21cc53bc | |||
| cda35f142f | |||
| 5c98ea081e | |||
| 78866ca13d | |||
| d4382300b4 | |||
| 7ef01e70f7 | |||
| 10316b6ab2 | |||
| e11d9904bc | |||
| f1d33f76c7 | |||
| fe72a8192d | |||
| bf543ac8f4 | |||
| 93f7a97f01 | |||
| cc188dffa9 | |||
| 33e3b9ddbb | |||
| 8c4b0b66b8 | |||
| 2781c9544b | |||
| 4765dde5cf | |||
| 658b0e8092 | |||
| 0e5d05f8e0 | |||
| f1570c5c92 | |||
| e042c53caa | |||
| a7b6859561 | |||
| 14235c9c17 | |||
| 6a6bed8e04 | |||
| 7a07995944 | |||
| 62afe5cda6 | |||
| 95f6b7fa82 | |||
| ae2438df90 | |||
| fafb78e38e | |||
| 4068758bb8 | |||
| bb87595220 | |||
| 001a1517da | |||
| 76b285f475 | |||
| 0b796299c1 | |||
| 5d2af3e13d | |||
| 15d2f1697d | |||
| 460a54ce15 | |||
| 3ab0ccf643 | |||
| cebd79e7eb | |||
| 4e321365cf | |||
| 1b088606f7 | |||
| 7bf410f927 | |||
| 5476f09d35 | |||
| a49c9a27fb | |||
| e5a3cf5a36 | |||
| 59a0f62079 | |||
| fbbd6b2c2e | |||
| d77977aa62 | |||
| da35350ee3 | |||
| 40996af9c1 | |||
| 7e29b38bd4 | |||
| c1b86a5eab | |||
| 68587c203c | |||
| 80e08d1b1b | |||
| 0a05318277 | |||
| 5c187245a4 | |||
| 739059cc91 | |||
| 86e966b944 | |||
| ef08d3975c | |||
| c50007b33a | |||
| 9f20e16683 | |||
| 4f2ce2f7b6 | |||
| a404a56254 | |||
| 7a59b443ee | |||
| 127bfd71d7 | |||
| 35341511b9 | |||
| 65888ac515 | |||
| 313f51d1f8 | |||
| 5ddf0f4e5f | |||
| 5e726db14e | |||
| 705dde471f | |||
| d83640dc34 | |||
| ed20c3255b | |||
| 0a189935ad | |||
| 1f5681e419 | |||
| 8dd4a0adf1 | |||
| dcec8dfdde | |||
| 8e85702dca | |||
| b58d50a0da | |||
| 1578585c08 | |||
| a18b3f2ed4 | |||
| 039eb8dc04 | |||
| 5f0c4fc20f | |||
| 04b36dabd0 | |||
| cfe65a0d6c | |||
| ccf7867c35 | |||
| bf89bc624b | |||
| 392fdff8e5 | |||
| 444f562955 | |||
| db8555ed31 | |||
| cc1b29cd67 | |||
| a0b4ab109d | |||
| 87d979f498 | |||
| f9be52cb2f | |||
| fae1be06cd | |||
| e1a625aa78 | |||
| 347328adb0 | |||
| cb775a6a6d | |||
| 6c2b7a9441 | |||
| bef12c003c | |||
| 19da38b811 | |||
| 453aecd346 | |||
| 2d57c5c374 | |||
| c2426516c4 | |||
| 18ea4825cf | |||
| 1f698e4f62 | |||
| 49a23acd89 | |||
| 80f0feda98 | |||
| 06b34b3fc1 | |||
| 92322a63f5 | |||
| 5e77e1c117 | |||
| 6dbb4d6384 | |||
| 988cbb6300 | |||
| 1cbaca6c60 | |||
| 2abe72283e | |||
| 126e941466 | |||
| 51c6e8329d | |||
| 91b4781ae9 | |||
| 92618eb8e2 | |||
| 9cc827fcd1 | |||
| 40974b1463 | |||
| dc1929a9de | |||
| 57e057df60 | |||
| 32f1a5ad83 | |||
| 1f05f94885 | |||
| 05e2124f24 | |||
| 1fd311803a | |||
| 7f44feab19 | |||
| 3a7ed2e7bd | |||
| bad24bc119 | |||
| 5aaeaa7b81 | |||
| bcc4186388 | |||
| 74a53b542b | |||
| 9da3d8b7b9 | |||
| 73944c6e81 | |||
| a9c2a586b1 | |||
| 83de34882b | |||
| 1ccedc5fa4 | |||
| 33e54e45be | |||
| 46187037a3 | |||
| ae132c0a1a | |||
| 4c61f1f663 | |||
| 4e37d56d51 | |||
| 8f201d62d9 | |||
| d7cff0797e | |||
| ed5aa953d5 | |||
| cb128cc6e9 | |||
| 23a5f7a22c | |||
| 03a2b338ee | |||
| c5cfb6e02b | |||
| 1f68d7d827 | |||
| 6ed16b5b41 | |||
| 43ffb8521d | |||
| 1f7cc92219 | |||
| 3f92e24cb7 | |||
| cc127c64a9 | |||
| 327e36e360 | |||
| f2aaffaf07 | |||
| cd300835d7 | |||
| e56adaebea | |||
| dbbe4c12fa | |||
| 296cd814e5 | |||
| 5bd4c234fb | |||
| 4226551fff | |||
| bdb8931bda | |||
| 3a35895a00 | |||
| d3b30bff0c | |||
| 2a8d3f78e9 | |||
| ff1f5de62f | |||
| 1720e8ebf3 | |||
| 8178578359 | |||
| 8d1565df94 | |||
| 9161119329 | |||
| 9b81322409 | |||
| e1bf3b6650 | |||
| efccf87961 | |||
| 2c24e3cb6a | |||
| ce8212c5a8 | |||
| ea6ac7131e | |||
| e06ccb0fbb | |||
| 021f5e0365 | |||
| 759765114f | |||
| 3b6e316e74 | |||
| e2bde55277 | |||
| abdbe207fe | |||
| a04fa5300a | |||
| 8dc9866e2a | |||
| 4b200a0429 | |||
| 713c532940 | |||
| a3b097639f |
+5
-1
@@ -935,7 +935,7 @@ if test "x$enable_x11_backend" = xyes; then
|
||||
have_base_x_pc=true
|
||||
X_PACKAGES="$X_PACKAGES x11 xext"
|
||||
x_libs="`$PKG_CONFIG --libs x11 xext`"
|
||||
X_CFLAGS="`$PKG_CONFIG --cflags x11 xext`"
|
||||
X_CFLAGS="`$PKG_CONFIG --cflags x11 xext` -DXINPUT2_1_USE_UNSTABLE_PROTOCOL -DXINPUT2_2_USE_UNSTABLE_PROTOCOL"
|
||||
|
||||
# Strip out any .la files that pkg-config might give us (this happens
|
||||
# with -uninstalled.pc files)
|
||||
@@ -1126,6 +1126,10 @@ if test "x$enable_x11_backend" = xyes; then
|
||||
AC_DEFINE(XINPUT_2, 1, [Define to 1 if XInput 2.0 is available]),
|
||||
X_EXTENSIONS="$X_EXTENSIONS XInput")
|
||||
|
||||
gtk_save_LIBS="$LIBS"
|
||||
LIBS="$LIBS -lXi"
|
||||
AC_CHECK_FUNC(XIAllowTouchEvents, AC_DEFINE(XINPUT_2_2, 1, [Define to 1 if XInput 2.2 is available]))
|
||||
LIBS="$gtk_save_LIBS"
|
||||
else
|
||||
AC_DEFINE(XINPUT_NONE, 1,
|
||||
[Define to 1 if no XInput should be used])
|
||||
|
||||
@@ -29,6 +29,7 @@ demos = \
|
||||
links.c \
|
||||
list_store.c \
|
||||
menus.c \
|
||||
multitouch.c \
|
||||
offscreen_window.c \
|
||||
offscreen_window2.c \
|
||||
overlay.c \
|
||||
|
||||
@@ -36,26 +36,17 @@ change_color_callback (GtkWidget *button,
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkColorSelection *colorsel;
|
||||
GtkColorSelectionDialog *selection_dialog;
|
||||
GtkColorChooserDialog *selection_dialog;
|
||||
gint response;
|
||||
|
||||
dialog = gtk_color_selection_dialog_new ("Changing color");
|
||||
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
|
||||
|
||||
selection_dialog = GTK_COLOR_SELECTION_DIALOG (dialog);
|
||||
colorsel = GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (selection_dialog));
|
||||
|
||||
gtk_color_selection_set_previous_rgba (colorsel, &color);
|
||||
gtk_color_selection_set_current_rgba (colorsel, &color);
|
||||
gtk_color_selection_set_has_palette (colorsel, TRUE);
|
||||
dialog = gtk_color_chooser_dialog_new ("Changing color", GTK_WINDOW (window));
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &color);
|
||||
|
||||
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
|
||||
if (response == GTK_RESPONSE_OK)
|
||||
{
|
||||
gtk_color_selection_get_current_rgba (colorsel, &color);
|
||||
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &color);
|
||||
gtk_widget_override_background_color (da, 0, &color);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,698 @@
|
||||
/* Multitouch
|
||||
*
|
||||
* Demonstrates some general multitouch event handling,
|
||||
* using GdkTouchCluster in order to get grouped motion
|
||||
* events for the touches within a cluster. Each of the
|
||||
* created rectangles has one of those GdkTouchCluster
|
||||
* objects.
|
||||
*
|
||||
* Touch events are also enabled on additional widgets,
|
||||
* enabling simultaneous touch interaction on those. Not
|
||||
* all widgets are prepared for multitouch interaction,
|
||||
* as there are constraints that not all widgets may
|
||||
* apply to.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "demo-common.h"
|
||||
|
||||
#define RECT_BORDER_WIDTH 6
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
static GtkWidget *area = NULL;
|
||||
static GtkWidget *red = NULL;
|
||||
static GtkWidget *green = NULL;
|
||||
static GtkWidget *blue = NULL;
|
||||
static GtkWidget *alpha = NULL;
|
||||
|
||||
static GQueue *shapes = NULL;
|
||||
|
||||
typedef struct {
|
||||
GdkTouchCluster *cluster;
|
||||
GdkRGBA color;
|
||||
|
||||
gdouble angle;
|
||||
gdouble zoom;
|
||||
|
||||
gdouble center_x;
|
||||
gdouble center_y;
|
||||
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble width;
|
||||
gdouble height;
|
||||
|
||||
gdouble base_zoom;
|
||||
gdouble base_angle;
|
||||
gdouble initial_distance;
|
||||
gdouble initial_angle;
|
||||
|
||||
GdkPoint points[4];
|
||||
} ShapeInfo;
|
||||
|
||||
static void
|
||||
calculate_rotated_point (gdouble angle,
|
||||
gdouble zoom,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gdouble point_x,
|
||||
gdouble point_y,
|
||||
gdouble *ret_x,
|
||||
gdouble *ret_y)
|
||||
{
|
||||
gdouble distance, xd, yd, ang;
|
||||
|
||||
if (angle == 0)
|
||||
{
|
||||
*ret_x = point_x;
|
||||
*ret_y = point_y;
|
||||
return;
|
||||
}
|
||||
|
||||
xd = center_x - point_x;
|
||||
yd = center_y - point_y;
|
||||
|
||||
if (xd == 0 && yd == 0)
|
||||
{
|
||||
*ret_x = center_x;
|
||||
*ret_y = center_y;
|
||||
return;
|
||||
}
|
||||
|
||||
distance = sqrt ((xd * xd) + (yd * yd));
|
||||
distance *= zoom;
|
||||
|
||||
ang = atan2 (xd, yd);
|
||||
|
||||
/* Invert angle */
|
||||
ang = (2 * G_PI) - ang;
|
||||
|
||||
/* Shift it 270° */
|
||||
ang += 3 * (G_PI / 2);
|
||||
|
||||
/* And constraint it to 0°-360° */
|
||||
ang = fmod (ang, 2 * G_PI);
|
||||
ang += angle;
|
||||
|
||||
*ret_x = center_x + (distance * cos (ang));
|
||||
*ret_y = center_y + (distance * sin (ang));
|
||||
}
|
||||
|
||||
static void
|
||||
shape_info_allocate_input_rect (ShapeInfo *info)
|
||||
{
|
||||
gint width, height, i;
|
||||
|
||||
width = info->width;
|
||||
height = info->height;
|
||||
|
||||
/* Top/left */
|
||||
info->points[0].x = info->x - info->center_x;
|
||||
info->points[0].y = info->y - info->center_y;
|
||||
|
||||
/* Top/right */
|
||||
info->points[1].x = info->x - info->center_x + width;
|
||||
info->points[1].y = info->y - info->center_y;
|
||||
|
||||
/* Bottom/right */
|
||||
info->points[2].x = info->x - info->center_x + width;
|
||||
info->points[2].y = info->y - info->center_y + height;
|
||||
|
||||
/* Bottom/left */
|
||||
info->points[3].x = info->x - info->center_x;
|
||||
info->points[3].y = info->y - info->center_y + height;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
gdouble ret_x, ret_y;
|
||||
|
||||
calculate_rotated_point (info->angle,
|
||||
info->zoom,
|
||||
info->x,
|
||||
info->y,
|
||||
(gdouble) info->points[i].x,
|
||||
(gdouble) info->points[i].y,
|
||||
&ret_x,
|
||||
&ret_y);
|
||||
|
||||
info->points[i].x = (gint) ret_x;
|
||||
info->points[i].y = (gint) ret_y;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shape_info_bounding_rect (ShapeInfo *info,
|
||||
GdkRectangle *rect)
|
||||
{
|
||||
gint i, left, right, top, bottom;
|
||||
|
||||
left = top = G_MAXINT;
|
||||
right = bottom = 0;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (info->points[i].x < left)
|
||||
left = info->points[i].x;
|
||||
|
||||
if (info->points[i].x > right)
|
||||
right = info->points[i].x;
|
||||
|
||||
if (info->points[i].y < top)
|
||||
top = info->points[i].y;
|
||||
|
||||
if (info->points[i].y > bottom)
|
||||
bottom = info->points[i].y;
|
||||
}
|
||||
|
||||
rect->x = left - 20;
|
||||
rect->y = top - 20;
|
||||
rect->width = right - left + 40;
|
||||
rect->height = bottom - top + 40;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shape_info_point_in (ShapeInfo *info,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GdkPoint *left, *right, *top, *bottom;
|
||||
gint i;
|
||||
|
||||
left = right = top = bottom = NULL;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
GdkPoint *p = &info->points[i];
|
||||
|
||||
if (!left ||
|
||||
p->x < left->x ||
|
||||
(p->x == left->x && p->y > left->y))
|
||||
left = p;
|
||||
|
||||
if (!right ||
|
||||
p->x > right->x ||
|
||||
(p->x == right->x && p->y < right->y))
|
||||
right = p;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
GdkPoint *p = &info->points[i];
|
||||
|
||||
if (p == left || p == right)
|
||||
continue;
|
||||
|
||||
if (!top ||
|
||||
p->y < top->y)
|
||||
top = p;
|
||||
|
||||
if (!bottom ||
|
||||
p->y > bottom->y)
|
||||
bottom = p;
|
||||
}
|
||||
|
||||
g_assert (left && right && top && bottom);
|
||||
|
||||
if (x < left->x ||
|
||||
x > right->x ||
|
||||
y < top->y ||
|
||||
y > bottom->y)
|
||||
return FALSE;
|
||||
|
||||
/* Check whether point is above the sides
|
||||
* between leftmost and topmost, and
|
||||
* topmost and rightmost corners.
|
||||
*/
|
||||
if (x <= top->x)
|
||||
{
|
||||
if (left->y - ((left->y - top->y) * (((gdouble) x - left->x) / (top->x - left->x))) > y)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (top->y + ((right->y - top->y) * (((gdouble) x - top->x) / (right->x - top->x))) > y)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check whether point is below the sides
|
||||
* between leftmost and bottom, and
|
||||
* bottom and rightmost corners.
|
||||
*/
|
||||
if (x <= bottom->x)
|
||||
{
|
||||
if (left->y + ((bottom->y - left->y) * (((gdouble) x - left->x) / (bottom->x - left->x))) < y)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bottom->y - ((bottom->y - right->y) * (((gdouble) x - bottom->x) / (right->x - bottom->x))) < y)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static ShapeInfo *
|
||||
shape_info_new (gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
ShapeInfo *info;
|
||||
|
||||
info = g_slice_new0 (ShapeInfo);
|
||||
info->cluster = NULL;
|
||||
info->color = *color;
|
||||
|
||||
info->x = x;
|
||||
info->y = y;
|
||||
info->width = width;
|
||||
info->height = height;
|
||||
|
||||
info->angle = 0;
|
||||
info->zoom = 1;
|
||||
|
||||
info->base_zoom = 1;
|
||||
info->base_angle = 0;
|
||||
info->initial_distance = 0;
|
||||
info->initial_angle = 0;
|
||||
|
||||
shape_info_allocate_input_rect (info);
|
||||
|
||||
g_queue_push_tail (shapes, info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void
|
||||
shape_info_free (ShapeInfo *info)
|
||||
{
|
||||
g_slice_free (ShapeInfo, info);
|
||||
}
|
||||
|
||||
static void
|
||||
shape_info_draw (cairo_t *cr,
|
||||
ShapeInfo *info)
|
||||
{
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_translate (cr,
|
||||
info->points[0].x + RECT_BORDER_WIDTH / 2,
|
||||
info->points[0].y + RECT_BORDER_WIDTH / 2);
|
||||
|
||||
cairo_scale (cr, info->zoom, info->zoom);
|
||||
cairo_rotate (cr, info->angle);
|
||||
|
||||
cairo_rectangle (cr, 0, 0,
|
||||
info->width - RECT_BORDER_WIDTH,
|
||||
info->height - RECT_BORDER_WIDTH);
|
||||
gdk_cairo_set_source_rgba (cr, &info->color);
|
||||
cairo_fill_preserve (cr);
|
||||
|
||||
cairo_set_line_width (cr, RECT_BORDER_WIDTH);
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
shape_update_scales (ShapeInfo *info)
|
||||
{
|
||||
gtk_range_set_value (GTK_RANGE (red), info->color.red);
|
||||
gtk_range_set_value (GTK_RANGE (green), info->color.green);
|
||||
gtk_range_set_value (GTK_RANGE (blue), info->color.blue);
|
||||
gtk_range_set_value (GTK_RANGE (alpha), info->color.alpha);
|
||||
}
|
||||
|
||||
static void
|
||||
range_value_changed_cb (GtkRange *range,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GdkRectangle rect;
|
||||
ShapeInfo *shape;
|
||||
gdouble value;
|
||||
|
||||
widget = GTK_WIDGET (range);
|
||||
shape = g_queue_peek_head (shapes);
|
||||
|
||||
if (!shape)
|
||||
return;
|
||||
|
||||
value = gtk_range_get_value (range);
|
||||
|
||||
if (widget == red)
|
||||
shape->color.red = value;
|
||||
else if (widget == green)
|
||||
shape->color.green = value;
|
||||
else if (widget == blue)
|
||||
shape->color.blue = value;
|
||||
else if (widget == alpha)
|
||||
shape->color.alpha = value;
|
||||
|
||||
shape_info_bounding_rect (shape, &rect);
|
||||
gdk_window_invalidate_rect (gtk_widget_get_window (area),
|
||||
&rect, FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
draw_cb (GtkWidget *widget,
|
||||
cairo_t *cr,
|
||||
gpointer user_data)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
cairo_paint (cr);
|
||||
|
||||
for (l = shapes->tail; l; l = l->prev)
|
||||
shape_info_draw (cr, l->data);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
button_press_cb (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShapeInfo *shape = NULL;
|
||||
guint touch_id;
|
||||
|
||||
if (gdk_event_get_touch_id (event, &touch_id))
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = shapes->tail; l; l = l->prev)
|
||||
{
|
||||
ShapeInfo *info = l->data;
|
||||
|
||||
if (shape_info_point_in (info,
|
||||
(gint) event->button.x,
|
||||
(gint) event->button.y))
|
||||
shape = info;
|
||||
}
|
||||
|
||||
if (!shape)
|
||||
return FALSE;
|
||||
|
||||
/* Put on top */
|
||||
g_queue_remove (shapes, shape);
|
||||
g_queue_push_head (shapes, shape);
|
||||
|
||||
shape_update_scales (shape);
|
||||
|
||||
if (!shape->cluster)
|
||||
shape->cluster = gdk_window_create_touch_cluster (gtk_widget_get_window (widget),
|
||||
gdk_event_get_device (event));
|
||||
else if (gdk_touch_cluster_get_n_touches (shape->cluster) == 0)
|
||||
{
|
||||
/* Only change cluster device if there were no touches */
|
||||
gdk_touch_cluster_set_device (shape->cluster,
|
||||
gdk_event_get_device (event));
|
||||
}
|
||||
|
||||
gdk_touch_cluster_add_touch (shape->cluster, touch_id);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
multitouch_cb (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShapeInfo *info = NULL;
|
||||
gboolean new_center = FALSE;
|
||||
gboolean new_position = FALSE;
|
||||
gdouble event_x, event_y;
|
||||
cairo_region_t *region;
|
||||
GdkRectangle rect;
|
||||
GList *l;
|
||||
|
||||
for (l = shapes->head; l; l = l->next)
|
||||
{
|
||||
ShapeInfo *shape = l->data;
|
||||
|
||||
if (event->multitouch.group == shape->cluster)
|
||||
{
|
||||
info = shape;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!info)
|
||||
return FALSE;
|
||||
|
||||
shape_info_bounding_rect (info, &rect);
|
||||
region = cairo_region_create_rectangle ((cairo_rectangle_int_t *) &rect);
|
||||
|
||||
if (event->multitouch.n_events == 1)
|
||||
{
|
||||
/* Update center if we just got to
|
||||
* this situation from either way */
|
||||
if (event->type == GDK_MULTITOUCH_ADDED ||
|
||||
event->type == GDK_MULTITOUCH_REMOVED)
|
||||
new_center = TRUE;
|
||||
|
||||
event_x = event->multitouch.events[0]->x;
|
||||
event_y = event->multitouch.events[0]->y;
|
||||
new_position = TRUE;
|
||||
}
|
||||
else if (event->multitouch.n_events == 2)
|
||||
{
|
||||
gdouble distance, angle;
|
||||
|
||||
gdk_events_get_center ((GdkEvent *) event->multitouch.events[0],
|
||||
(GdkEvent *) event->multitouch.events[1],
|
||||
&event_x, &event_y);
|
||||
|
||||
gdk_events_get_distance ((GdkEvent *) event->multitouch.events[0],
|
||||
(GdkEvent *) event->multitouch.events[1],
|
||||
&distance);
|
||||
|
||||
gdk_events_get_angle ((GdkEvent *) event->multitouch.events[0],
|
||||
(GdkEvent *) event->multitouch.events[1],
|
||||
&angle);
|
||||
|
||||
if (event->type == GDK_MULTITOUCH_ADDED)
|
||||
{
|
||||
/* Second touch was just added, update base zoom/angle */
|
||||
info->base_zoom = info->zoom;
|
||||
info->base_angle = info->angle;
|
||||
info->initial_angle = angle;
|
||||
info->initial_distance = distance;
|
||||
new_center = TRUE;
|
||||
}
|
||||
|
||||
info->zoom = MAX (info->base_zoom * (distance / info->initial_distance), 1.0);
|
||||
info->angle = info->base_angle + (angle - info->initial_angle);
|
||||
new_position = TRUE;
|
||||
}
|
||||
|
||||
if (new_center)
|
||||
{
|
||||
gdouble origin_x, origin_y;
|
||||
|
||||
origin_x = info->x - info->center_x;
|
||||
origin_y = info->y - info->center_y;
|
||||
|
||||
calculate_rotated_point (- info->angle,
|
||||
1 / info->zoom,
|
||||
info->x - origin_x,
|
||||
info->y - origin_y,
|
||||
event_x - origin_x,
|
||||
event_y - origin_y,
|
||||
&info->center_x,
|
||||
&info->center_y);
|
||||
}
|
||||
|
||||
if (new_position)
|
||||
{
|
||||
info->x = event_x;
|
||||
info->y = event_y;
|
||||
}
|
||||
|
||||
shape_info_allocate_input_rect (info);
|
||||
|
||||
shape_info_bounding_rect (info, &rect);
|
||||
cairo_region_union_rectangle (region, (cairo_rectangle_int_t *) &rect);
|
||||
gdk_window_invalidate_region (gtk_widget_get_window (widget), region, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
window_destroyed_cb (GtkWidget *widget,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_queue_foreach (shapes, (GFunc) shape_info_free, NULL);
|
||||
g_queue_free (shapes);
|
||||
|
||||
shapes = NULL;
|
||||
window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
new_rectangle_clicked_cb (GtkButton *button,
|
||||
gpointer user_data)
|
||||
{
|
||||
GdkRectangle rect;
|
||||
ShapeInfo *info;
|
||||
GdkRGBA color;
|
||||
|
||||
color.red = color.green = color.blue = color.alpha = 0.5;
|
||||
info = shape_info_new (0, 0, 100, 150, &color);
|
||||
|
||||
shape_info_bounding_rect (info, &rect);
|
||||
gdk_window_invalidate_rect (gtk_widget_get_window (area), &rect, FALSE);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
create_drawing_area (void)
|
||||
{
|
||||
area = gtk_drawing_area_new ();
|
||||
|
||||
gtk_widget_add_events (area,
|
||||
GDK_TOUCH_MASK |
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_PRESS_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK);
|
||||
|
||||
gtk_widget_set_size_request (area, 600, 600);
|
||||
|
||||
g_signal_connect (area, "draw",
|
||||
G_CALLBACK (draw_cb), NULL);
|
||||
g_signal_connect (area, "button-press-event",
|
||||
G_CALLBACK (button_press_cb), NULL);
|
||||
g_signal_connect (area, "multitouch-event",
|
||||
G_CALLBACK (multitouch_cb), NULL);
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
create_scale (void)
|
||||
{
|
||||
GtkWidget *scale;
|
||||
|
||||
scale = gtk_scale_new_with_range (GTK_ORIENTATION_VERTICAL, 0, 1, 0.01);
|
||||
gtk_range_set_inverted (GTK_RANGE (scale), TRUE);
|
||||
|
||||
gtk_widget_set_vexpand (scale, TRUE);
|
||||
gtk_widget_set_margin_left (scale, 15);
|
||||
gtk_widget_set_margin_right (scale, 15);
|
||||
|
||||
gtk_widget_add_events (scale, GDK_TOUCH_MASK);
|
||||
|
||||
g_signal_connect (scale, "value-changed",
|
||||
G_CALLBACK (range_value_changed_cb), NULL);
|
||||
return scale;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
create_window (void)
|
||||
{
|
||||
GtkWidget *grid, *label, *button;
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Multitouch demo");
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (window_destroyed_cb), NULL);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_container_add (GTK_CONTAINER (window), grid);
|
||||
|
||||
area = create_drawing_area ();
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
area, 0, 0, 1, 3);
|
||||
gtk_widget_set_hexpand (area, TRUE);
|
||||
gtk_widget_set_vexpand (area, TRUE);
|
||||
|
||||
/* "red" label/scale */
|
||||
label = gtk_label_new ("Red");
|
||||
gtk_widget_set_vexpand (label, FALSE);
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
label, 1, 0, 1, 1);
|
||||
|
||||
red = create_scale ();
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
red, 1, 1, 1, 1);
|
||||
|
||||
/* "green" label/scale */
|
||||
label = gtk_label_new ("Green");
|
||||
gtk_widget_set_vexpand (label, FALSE);
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
label, 2, 0, 1, 1);
|
||||
|
||||
green = create_scale ();
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
green, 2, 1, 1, 1);
|
||||
|
||||
/* "blue" label/scale */
|
||||
label = gtk_label_new ("Blue");
|
||||
gtk_widget_set_vexpand (label, FALSE);
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
label, 3, 0, 1, 1);
|
||||
|
||||
blue = create_scale ();
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
blue, 3, 1, 1, 1);
|
||||
|
||||
/* "alpha" label/scale */
|
||||
label = gtk_label_new ("Alpha");
|
||||
gtk_widget_set_vexpand (label, FALSE);
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
label, 4, 0, 1, 1);
|
||||
|
||||
alpha = create_scale ();
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
alpha, 4, 1, 1, 1);
|
||||
|
||||
/* button */
|
||||
button = gtk_button_new_from_stock (GTK_STOCK_NEW);
|
||||
gtk_widget_add_events (button, GDK_TOUCH_MASK);
|
||||
gtk_grid_attach (GTK_GRID (grid),
|
||||
button, 1, 2, 4, 1);
|
||||
gtk_widget_set_vexpand (button, FALSE);
|
||||
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (new_rectangle_clicked_cb), NULL);
|
||||
|
||||
gtk_widget_show_all (grid);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_multitouch (GtkWidget *do_widget)
|
||||
{
|
||||
if (!shapes)
|
||||
shapes = g_queue_new ();
|
||||
|
||||
if (!window)
|
||||
window = create_window ();
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
{
|
||||
gtk_widget_destroy (window);
|
||||
window = NULL;
|
||||
|
||||
g_queue_foreach (shapes, (GFunc) shape_info_free, NULL);
|
||||
g_queue_free (shapes);
|
||||
shapes = NULL;
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -42,7 +42,8 @@ show_about (GtkMenuItem *item, GtkWidget *window)
|
||||
GdkPixbuf *pixbuf;
|
||||
const gchar *authors[] = {
|
||||
"Andrea Cimitan",
|
||||
"Cosimo Cecchi"
|
||||
"Cosimo Cecchi",
|
||||
NULL
|
||||
};
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_resource ("/logos/gtk-logo-256.png", NULL);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
<xi:include href="xml/windows.xml" />
|
||||
<xi:include href="xml/events.xml" />
|
||||
<xi:include href="xml/event_structs.xml" />
|
||||
<xi:include href="xml/touchcluster.xml" />
|
||||
<xi:include href="xml/keys.xml" />
|
||||
<xi:include href="xml/selections.xml" />
|
||||
<xi:include href="xml/dnd.xml" />
|
||||
|
||||
@@ -781,11 +781,13 @@ gdk_event_get_root_coords
|
||||
gdk_event_get_scroll_direction
|
||||
gdk_event_get_state
|
||||
gdk_event_get_time
|
||||
gdk_event_get_touch_id
|
||||
gdk_event_request_motions
|
||||
gdk_events_get_angle
|
||||
gdk_events_get_center
|
||||
gdk_events_get_distance
|
||||
gdk_event_triggers_context_menu
|
||||
gdk_event_get_touch_id
|
||||
|
||||
<SUBSECTION>
|
||||
gdk_event_handler_set
|
||||
@@ -833,6 +835,7 @@ GdkEventWindowState
|
||||
GdkEventSetting
|
||||
GdkEventOwnerChange
|
||||
GdkEventGrabBroken
|
||||
GdkEventMultiTouch
|
||||
|
||||
<SUBSECTION>
|
||||
GdkScrollDirection
|
||||
@@ -860,6 +863,29 @@ gdk_event_get_type
|
||||
gdk_owner_change_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<TITLE>Multitouch</TITLE>
|
||||
<FILE>touchcluster</FILE>
|
||||
GdkTouchCluster
|
||||
gdk_touch_cluster_add_touch
|
||||
gdk_touch_cluster_remove_touch
|
||||
gdk_touch_cluster_remove_all
|
||||
gdk_touch_cluster_set_device
|
||||
gdk_touch_cluster_get_device
|
||||
gdk_touch_cluster_get_touches
|
||||
|
||||
<SUBSECTION>
|
||||
gdk_window_create_touch_cluster
|
||||
gdk_window_remove_touch_cluster
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GDK_TYPE_TOUCH_CLUSTER
|
||||
|
||||
<SUBSECTION Private>
|
||||
gdk_touch_cluster_get_type
|
||||
</SECTION>
|
||||
|
||||
|
||||
<SECTION>
|
||||
<TITLE>Cursors</TITLE>
|
||||
<FILE>cursors</FILE>
|
||||
|
||||
@@ -9,5 +9,6 @@ gdk_display_manager_get_type
|
||||
gdk_drag_context_get_type
|
||||
gdk_keymap_get_type
|
||||
gdk_screen_get_type
|
||||
gdk_touch_cluster_get_type
|
||||
gdk_visual_get_type
|
||||
gdk_window_get_type
|
||||
|
||||
@@ -119,6 +119,7 @@ content_files = \
|
||||
running.sgml \
|
||||
building.sgml \
|
||||
compiling.sgml \
|
||||
device-interaction-patterns.xml \
|
||||
drawing-model.xml \
|
||||
glossary.xml \
|
||||
migrating-2to3.xml \
|
||||
@@ -142,6 +143,7 @@ content_files = \
|
||||
overview.xml
|
||||
|
||||
expand_content_files = \
|
||||
device-interaction-patterns.xml \
|
||||
drawing-model.xml \
|
||||
getting_started.xml \
|
||||
glossary.xml \
|
||||
@@ -287,6 +289,7 @@ HTML_IMAGES = \
|
||||
$(srcdir)/images/check-button.png \
|
||||
$(srcdir)/images/color-button.png \
|
||||
$(srcdir)/images/colorsel.png \
|
||||
$(srcdir)/images/colorchooser.png \
|
||||
$(srcdir)/images/combo-box.png \
|
||||
$(srcdir)/images/combo-box-entry.png \
|
||||
$(srcdir)/images/entry.png \
|
||||
@@ -296,6 +299,7 @@ HTML_IMAGES = \
|
||||
$(srcdir)/images/filechooser.png \
|
||||
$(srcdir)/images/font-button.png \
|
||||
$(srcdir)/images/fontsel.png \
|
||||
$(srcdir)/images/fontchooser.png \
|
||||
$(srcdir)/images/frame.png \
|
||||
$(srcdir)/images/icon-view.png \
|
||||
$(srcdir)/images/image.png \
|
||||
|
||||
@@ -0,0 +1,578 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
]>
|
||||
<chapter id="gtk-device-interaction-patterns">
|
||||
<title>Multitouch and other device interaction patterns</title>
|
||||
|
||||
<para>
|
||||
Depending on the platform, GTK+ is able to handle a wide range of input
|
||||
devices. Those are offered to applications in a 2-level hierarchy, with
|
||||
virtual devices (or master devices) representing the visual cursors
|
||||
displayed in the screen, which are each controlled by a number of physical
|
||||
devices (or slave devices). Those devices can respectively be retrieved
|
||||
from an input event with gdk_event_get_device() and
|
||||
gdk_event_get_source_device().
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In X11, GTK+ uses XInput2 for input events, which caters for a fully dynamic
|
||||
device hierarchy, and support for multiple virtual pointer/keyboard pairs.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Listing and modifying the device hierarchy</title>
|
||||
<programlisting>
|
||||
carlos@sacarino:~$ xinput list
|
||||
⎡ Virtual core pointer id=2 [master pointer (3)]
|
||||
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
|
||||
⎜ ↳ Wacom ISDv4 E6 Pen stylus id=10 [slave pointer (2)]
|
||||
⎜ ↳ Wacom ISDv4 E6 Finger touch id=11 [slave pointer (2)]
|
||||
⎜ ↳ SynPS/2 Synaptics TouchPad id=13 [slave pointer (2)]
|
||||
⎜ ↳ TPPS/2 IBM TrackPoint id=14 [slave pointer (2)]
|
||||
⎜ ↳ Wacom ISDv4 E6 Pen eraser id=16 [slave pointer (2)]
|
||||
⎣ Virtual core keyboard id=3 [master keyboard (2)]
|
||||
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
|
||||
↳ Power Button id=6 [slave keyboard (3)]
|
||||
↳ Video Bus id=7 [slave keyboard (3)]
|
||||
↳ Sleep Button id=8 [slave keyboard (3)]
|
||||
↳ Integrated Camera id=9 [slave keyboard (3)]
|
||||
↳ AT Translated Set 2 keyboard id=12 [slave keyboard (3)]
|
||||
↳ ThinkPad Extra Buttons id=15 [slave keyboard (3)]
|
||||
|
||||
carlos@sacarino:~$ xinput create-master eek
|
||||
carlos@sacarino:~$ xinput list
|
||||
...
|
||||
⎡ eek pointer id=17 [master pointer (18)]
|
||||
⎜ ↳ eek XTEST pointer id=19 [slave pointer (17)]
|
||||
⎣ eek keyboard id=18 [master keyboard (17)]
|
||||
↳ eek XTEST keyboard id=20 [slave keyboard (18)]
|
||||
|
||||
carlos@sacarino:~$ xinput reattach 10 17
|
||||
carlos@sacarino:~$ xinput list
|
||||
...
|
||||
⎡ eek pointer id=17 [master pointer (18)]
|
||||
⎜ ↳ Wacom ISDv4 E6 Pen stylus id=10 [slave pointer (17)]
|
||||
⎜ ↳ eek XTEST pointer id=19 [slave pointer (17)]
|
||||
⎣ eek keyboard id=18 [master keyboard (17)]
|
||||
↳ eek XTEST keyboard id=20 [slave keyboard (18)]
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
Anytime a virtual device is added or removed, or a physical device
|
||||
is attached to another virtual device, or left floating (detached
|
||||
from any virtual device), #GdkDeviceManager will emit the corresponding
|
||||
#GdkDeviceManager::device-added, #GdkDeviceManager::device-removed, or
|
||||
#GdkDeviceManager::device-changed signals.
|
||||
</para>
|
||||
|
||||
<section id="gtk-device-patterns-client-pointer">
|
||||
<title>The client pointer</title>
|
||||
|
||||
<para>
|
||||
In X11, Under the presence of multiple virtual pointers, GDK and XInput2
|
||||
use the "client pointer" principle to allow several legacy applications
|
||||
to interact simultaneously with different virtual pointer/keyboard pairs,
|
||||
it would be usually set by the window manager for a focused window, so
|
||||
different application windows could operate on different client pointers.
|
||||
gdk_device_manager_get_client_pointer() may be called to get the client
|
||||
pointer #GdkDevice
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Under the hood, X11 uses the client pointer (or its paired keyboard) to
|
||||
satisfy core calls such as XGrabPointer/Keyboard, XQueryPointer and
|
||||
others that have been superseded by XInput2.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In platforms without multidevice features, gdk_device_manager_get_client_pointer()
|
||||
will return the only virtual pointer available.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="gtk-device-patterns-simple">
|
||||
<title>Simple device handling</title>
|
||||
|
||||
<para>
|
||||
There are applications that could have little gain in knowing about
|
||||
multiple devices, although there are situations where a device could
|
||||
be needed (i.e. popping up a menu on the pointer coordinates).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For such applications, the client pointer may be a good enough
|
||||
approximation for these operations. Under the presence of multiple
|
||||
device pairs, this gives a behavior that is most similar to that
|
||||
of legacy applications (i.e. gtk+2).
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Getting the client pointer and keyboard</title>
|
||||
<programlisting>
|
||||
GdkDisplay *display;
|
||||
GdkDeviceManager *device_manager;
|
||||
GdkDevice *client_pointer, client_keyboard;
|
||||
|
||||
display = gdk_display_get_default ();
|
||||
device_manager = gdk_display_get_device_manager (display);
|
||||
client_pointer = gdk_device_manager_get_client_pointer (device_manager);
|
||||
|
||||
/* Or if we need a keyboard too */
|
||||
client_keyboard = gdk_device_get_associated_device (client_pointer);
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
<section id="gtk-device-patterns-multiple-devices">
|
||||
<title>Dealing with multiple devices</title>
|
||||
|
||||
<para>
|
||||
There may be several usecases to deal with multiple devices, including,
|
||||
but not limited to:
|
||||
</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
Retrieving advanced information from an input device: i.e. stylus pressure/tilt
|
||||
in drawing applications.
|
||||
</listitem>
|
||||
<listitem>
|
||||
Receiving events from a dedicated input device: i.e. joysticks in games.
|
||||
</listitem>
|
||||
<listitem>
|
||||
Collaborative interfaces, handling simultaneous input from multiple users.
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>
|
||||
However, the patterns to make them work are very similar.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<title>Event handling</title>
|
||||
|
||||
<para>
|
||||
Each device will emit its own event stream, this means
|
||||
that you will need to check the GdkEvent you get in
|
||||
your event handlers
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Reacting differently to devices</title>
|
||||
<programlisting>
|
||||
static gboolean
|
||||
my_widget_motion_notify (GtkWidget *widget,
|
||||
GdkEventMotion *event)
|
||||
{
|
||||
GdkDevice *device, *source_device;
|
||||
|
||||
device = gdk_event_get_device ((GdkEvent *) event);
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
g_print ("Motion event by '%s', coming from HW device '%s'\n",
|
||||
gdk_device_get_name (device),
|
||||
gdk_device_get_name (source_device));
|
||||
|
||||
/* Handle touch devices differently */
|
||||
if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
{
|
||||
...
|
||||
}
|
||||
else
|
||||
{
|
||||
...
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
The mechanism above could also be used for fine grained event discarding
|
||||
(i.e. so rubberband selection doesn't jump to another pointer entering
|
||||
the widget for example)
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Reacting differently to devices</title>
|
||||
<programlisting>
|
||||
static gboolean
|
||||
my_widget_button_press (Gtkwidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GET_PRIV(widget)->current_pointer = gdk_event_get_device ((GdkEvent *) event);
|
||||
...
|
||||
}
|
||||
|
||||
static gboolean
|
||||
my_widget_button_release (Gtkwidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GET_PRIV(widget)->current_pointer = NULL;
|
||||
...
|
||||
}
|
||||
|
||||
static gboolean
|
||||
my_widget_motion_notify (Gtkwidget *widget,
|
||||
GdkEventMotion *event)
|
||||
{
|
||||
if (gdk_event_get_device (event) !=
|
||||
GET_PRIV(widget)->current_pointer)
|
||||
return FALSE;
|
||||
|
||||
...
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Grabs</title>
|
||||
|
||||
<para>
|
||||
Grabs are a mechanism to coerce a device into sending events to
|
||||
a window, but with multidevice there's an other side of the coin,
|
||||
how other devices are supposed to interact while the grab is in
|
||||
effect.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The GdkGrabOwnership enum passed to gdk_device_grab() may be used
|
||||
to block other devices' interaction. %GDK_OWNERSHIP_NONE applies
|
||||
no restrictions, allowing other devices to interact, even with
|
||||
the grab window. %GDK_OWNERSHIP_WINDOW blocks other devices from
|
||||
interacting with the grab window, but they'll still be able to
|
||||
interact with the rest of the application, whereas
|
||||
%GDK_OWNERSHIP_APPLICATION will render the whole application
|
||||
insensitive to input from other devices. Different devices may
|
||||
have simultaneous grabs on the same or different windows.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Grabbing as a result of an input event</title>
|
||||
<programlisting>
|
||||
gboolean
|
||||
my_widget_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GdkDevice *pointer, *keyboard;
|
||||
|
||||
pointer = gdk_event_get_device ((GdkEvent *) event);
|
||||
keyboard = gdk_device_get_associated_device (pointer);
|
||||
|
||||
/* Grab both keyboard/pointer, other devices will be
|
||||
* unable to interact with the widget window meanwhile
|
||||
*/
|
||||
gdk_device_grab (pointer,
|
||||
gtk_widget_get_window (widget),
|
||||
GDK_OWNERSHIP_WINDOW,
|
||||
...);
|
||||
gdk_device_grab (keyboard,
|
||||
gtk_widget_get_window (widget),
|
||||
GDK_OWNERSHIP_WINDOW,
|
||||
...);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
For GTK+ grabs, there's only a boolean value, equivalent to
|
||||
%GDK_OWNERSHIP_NONE and %GDK_OWNERSHIP_WINDOW, but the mechanism
|
||||
is quite similar.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once the device is grabbed, there may be different situations
|
||||
that could break the grabs, so the widget needs to listen to
|
||||
#GdkGrabBrokenEvent and the #GtkWidget::grab-notify signal to
|
||||
handle these situations.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Handling broken grabs</title>
|
||||
<programlisting>
|
||||
static gboolean
|
||||
my_widget_grab_broken (GtkWidget *widget,
|
||||
GdkEventGrabBroken *event)
|
||||
{
|
||||
MyWidgetPrivate *priv = GET_PRIV (widget);
|
||||
|
||||
if (gdk_event_get_device (event) == priv->grab_pointer)
|
||||
{
|
||||
/* Undo state */
|
||||
...
|
||||
priv->grab_pointer = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
my_widget_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed)
|
||||
{
|
||||
MyWidgetPrivate *priv = GET_PRIV (widget);
|
||||
|
||||
if (gtk_widget_device_is_shadowed (widget, priv->grab_device))
|
||||
{
|
||||
/* Device was "shadowed" by another widget's grab,
|
||||
* release and undo state
|
||||
*/
|
||||
...
|
||||
priv->grab_pointer = NULL;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Handling multipointer</title>
|
||||
|
||||
<para>
|
||||
Widgets do react by default to every virtual device, although
|
||||
by default they are set in a compatibility mode that makes them
|
||||
behave better with multiple pointers, without necessarily
|
||||
being multipointer aware.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This compatibility mode most notably disables per-device
|
||||
enter/leave events, so these are stacked, and the crossing
|
||||
events are only emitted when the first pointer enters the
|
||||
window, and after the last pointer leaves it. This behavior
|
||||
is controlled through gtk_widget_set_support_multidevice()
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Reading device axis values</title>
|
||||
|
||||
<para>
|
||||
Button and motion events provide further information about
|
||||
the device axes' current state. Note the device axes are
|
||||
hardware and driver dependent, therefore the set of axes
|
||||
is not set in stone, although there are a few more common ones.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Getting to know the axes provided by a device</title>
|
||||
<programlisting>
|
||||
carlos@sacarino:~$ xinput list "Wacom ISDv4 E6 Pen stylus" |grep "Label"
|
||||
Label: Abs X
|
||||
Label: Abs Y
|
||||
Label: Abs Pressure
|
||||
Label: Abs Tilt X
|
||||
Label: Abs Tilt Y
|
||||
Label: Abs Wheel
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Getting an axis value</title>
|
||||
<programlisting>
|
||||
gboolean
|
||||
my_widget_motion_notify (GtkWidget *widget,
|
||||
GdkEventMotion *event)
|
||||
{
|
||||
GdkAtom *label_atom;
|
||||
gdouble pressure;
|
||||
|
||||
label_atom = gdk_atom_intern_static_string ("Abs Pressure");
|
||||
gdk_device_get_axis_value (gdk_event_get_device ((GdkEvent *) event),
|
||||
event->axes, label_atom, &pressure);
|
||||
|
||||
/* Do something with pressure */
|
||||
...
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
All pointer devices report axes information, master and slave. to
|
||||
achieve this, master pointers modify their list of axes at runtime
|
||||
to reflect those of the currently routed slave, emitting
|
||||
#GdkDevice::changed as the routed slave device changes.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Dealing with slave (or floating) devices</title>
|
||||
|
||||
<para>
|
||||
By default, GTK+ listens to all master devices, and typically
|
||||
all slave devices will be attached to a master device. so
|
||||
gdk_event_get_source_device() is the recommended way to deal
|
||||
with the physical device triggering the event.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In more specialized setups, some devices could be floating
|
||||
(i.e. tablets that don't route events through any virtual
|
||||
pointer, but are expected to interact with drawing applications).
|
||||
In that case, such specialized applications could want to interact
|
||||
directly with the device. To do so, the device must be enabled,
|
||||
and the widget wanting its events needs to add the event mask.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Enabling events for a slave device</title>
|
||||
<programlisting>
|
||||
GdkDevice *device;
|
||||
|
||||
/* Gets the first device found with the given GdkInputSource */
|
||||
device = get_device (gtk_widget_get_display (widget),
|
||||
GDK_SOURCE_PEN);
|
||||
gdk_device_set_mode (device, GDK_MODE_SCREEN);
|
||||
gtk_widget_add_device_events (widget, device,
|
||||
GDK_BUTTON_PRESS_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_POINTER_MOTION_MASK);
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
After these calls, the widget would specifically receive events
|
||||
from the physical device, regardless of it being floating or
|
||||
connected to a master device. In this second case, and if you
|
||||
want exclusive control of the device, you can temporarily detach
|
||||
the stylus device from its master by doing a GDK grab on it.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For events coming directly from slave devices, both
|
||||
gdk_event_get_device() and gdk_event_get_source_device() will
|
||||
return the same device of type %GDK_DEVICE_TYPE_SLAVE or
|
||||
%GDK_DEVICE_TYPE_FLOATING.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
This is less useful than it used to be in GTK+2/XInput1, at least
|
||||
for attached slaves, as there is gdk_event_get_source_device(),
|
||||
and master devices' events provide axes information.
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="gtk-device-patterns-multitouch-widgets">
|
||||
<title>Multitouch in GTK+ widgets</title>
|
||||
|
||||
<para>
|
||||
Since version 3.4, GTK+ offers support for multitouch devices through a new
|
||||
set of events and higher level tools like #GdkTouchCluster and
|
||||
#GtkGesturesInterpreter.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the widget does not have %GDK_TOUCH_MASK set in the event mask, it will
|
||||
only be allowed to interact with the touch emulating pointer events, and will
|
||||
only receive pointer events.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the widget does have %GDK_TOUCH_MASK enabled, it will be able to receive
|
||||
events of type %GDK_TOUCH_PRESS, %GDK_TOUCH_RELEASE and %GDK_TOUCH_MOTION,
|
||||
which will be respectively emitted through the #GtkWidget::button-press-event,
|
||||
#GtkWidget::button-release-event and #GtkWidget::motion-notify-event signals.
|
||||
There may be multiple, simultaneous sequences of events, those will be
|
||||
recognized and referenced by their touch ID. See gdk_event_get_touch_id().
|
||||
</para>
|
||||
|
||||
<para>
|
||||
#GtkWidget<!-- -->s may create GdkTouchCluster<!-- -->s via
|
||||
gdk_window_create_touch_cluster(), those may be used to group
|
||||
touch events together, which are notified through #GdkEventMultitouch,
|
||||
this event will be emitted in #GtkWidget<!-- -->s through the
|
||||
#GtkWidget::multitouch-event signal.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Widgets may also handle gestures being performed on them,
|
||||
gtk_widget_enable_gesture() and gtk_widget_disable_gesture() are
|
||||
provided as a simple API, although widgets may also create a
|
||||
#GtkGesturesInterpreter and feed it events directly.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="gtk-device-patterns-multitouch">
|
||||
<title>Multitouch across a widget hierarchy</title>
|
||||
|
||||
<para>
|
||||
Fully touch driven applications might not want to confine multitouch
|
||||
operations within a single widget, but rather offer simultaneous
|
||||
interaction with multiple widgets.
|
||||
</para>
|
||||
<para>
|
||||
GTK+ is able to provide such experience, although it does not enable
|
||||
%GDK_TOUCH_MASK by default on its stock widgets. If a widget meets the
|
||||
following requirements, it is ready to be used in a multitouch UI:
|
||||
</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
The widget handles #GtkWidget::button-press-event, #GtkWidget::button-release-event
|
||||
and #GtkWidget::motion-notify-event, and does something meaningful while the button 1
|
||||
is pressed. If any explicit check on the event type being %GDK_BUTTON_PRESS,
|
||||
%GDK_BUTTON_RELEASE or %GDK_MOTION_NOTIFY is performed, the event types
|
||||
%GDK_TOUCH_PRESS, %GDK_TOUCH_RELEASE or %GDK_TOUCH_MOTION also need to be handled.
|
||||
</listitem>
|
||||
<listitem>
|
||||
The widget relies on the implicit grab as long as the button press/touch is active,
|
||||
GDK or GTK+ grabs would break the implicit grabs other touch sequences may have on
|
||||
other widgets.
|
||||
</listitem>
|
||||
<listitem>
|
||||
The widget does not require (or opts out) keyboard interaction while a touch is
|
||||
active on it. Touch interaction does not necessarily bring the keyboard focus with it.
|
||||
</listitem>
|
||||
<listitem>
|
||||
If the widget is only meant to interact with one touch sequence at a time (i.e.
|
||||
buttons), it has to be able to discern and reject operations on any later touch
|
||||
sequence as long as the touch it is interacting with remains active.
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>
|
||||
If a widget meets those requirements, enabling %GDK_TOUCH_MASK on it will suffice
|
||||
to make it handle multitouch events in a way that doesn't disrupt other touch
|
||||
operations.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Enabling touch events on a widget</title>
|
||||
<programlisting>
|
||||
gtk_widget_add_events (widget, GDK_TOUCH_MASK);
|
||||
</programlisting>
|
||||
</example>
|
||||
|
||||
<note>
|
||||
Not all GTK+ stock widgets are immediately suitable for handling touch
|
||||
events, there could be even design reasons on some of those which render
|
||||
them unsuitable.
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section id="gtk-device-patterns-recommendations">
|
||||
<title>Recommendations</title>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
Device operations often come up as a result of input events, favor
|
||||
gdk_event_get_device() and gtk_get_current_event_device() before
|
||||
gdk_device_manager_get_client_pointer().
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
Store the devices the widget is currently interacting with, handle
|
||||
GdkEventGrabBroken and #GtkWidget::grab-notify to undo/nullify these.
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -68,6 +68,12 @@
|
||||
<xi:include href="xml/gtkstyle.xml" />
|
||||
</part>
|
||||
|
||||
<part id="multitouch-and-multidevice">
|
||||
<title>Interacting with input devices</title>
|
||||
<xi:include href="xml/device-interaction-patterns.xml" />
|
||||
<xi:include href="xml/gtkgesturesinterpreter.xml" />
|
||||
</part>
|
||||
|
||||
<part id="gtkobjects">
|
||||
<title>GTK+ Widgets and Objects</title>
|
||||
|
||||
@@ -209,18 +215,22 @@
|
||||
|
||||
<chapter id="SelectorWidgets">
|
||||
<title>Selectors (Color/File/Font)</title>
|
||||
<xi:include href="xml/gtkcolorchooser.xml" />
|
||||
<xi:include href="xml/gtkcolorbutton.xml" />
|
||||
<xi:include href="xml/gtkcolorseldlg.xml" />
|
||||
<xi:include href="xml/gtkcolorchooserwidget.xml" />
|
||||
<xi:include href="xml/gtkcolorchooserdialog.xml" />
|
||||
<xi:include href="xml/gtkcolorsel.xml" />
|
||||
<xi:include href="xml/gtkcolorseldlg.xml" />
|
||||
<xi:include href="xml/gtkhsv.xml" />
|
||||
<xi:include href="xml/gtkfilechooser.xml" />
|
||||
<xi:include href="xml/gtkfilechooserbutton.xml" />
|
||||
<xi:include href="xml/gtkfilechooserdialog.xml" />
|
||||
<xi:include href="xml/gtkfilechooserwidget.xml" />
|
||||
<xi:include href="xml/gtkfilefilter.xml" />
|
||||
<xi:include href="xml/gtkfontbutton.xml" />
|
||||
<xi:include href="xml/gtkfontchooser.xml" />
|
||||
<xi:include href="xml/gtkfontchooserdlg.xml" />
|
||||
<xi:include href="xml/gtkfontbutton.xml" />
|
||||
<xi:include href="xml/gtkfontchooserwidget.xml" />
|
||||
<xi:include href="xml/gtkfontchooserdialog.xml" />
|
||||
<xi:include href="xml/gtkfontsel.xml" />
|
||||
<xi:include href="xml/gtkfontseldlg.xml" />
|
||||
</chapter>
|
||||
|
||||
@@ -1535,7 +1535,7 @@ gtk_font_chooser_widget_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkfontchooserdlg</FILE>
|
||||
<FILE>gtkfontchooserdialog</FILE>
|
||||
<TITLE>GtkFontChooserDialog</TITLE>
|
||||
GtkFontChooserDialog
|
||||
gtk_font_chooser_dialog_new
|
||||
@@ -1579,6 +1579,51 @@ GtkFramePrivate
|
||||
gtk_frame_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkgesturesinterpreter</FILE>
|
||||
<TITLE>GtkGesturesInterpreter</TITLE>
|
||||
GtkGesturesInterpreter
|
||||
GtkGestureType
|
||||
gtk_gestures_interpreter_new
|
||||
gtk_gestures_interpreter_add_gesture
|
||||
gtk_gestures_interpreter_remove_gesture
|
||||
gtk_gestures_interpreter_feed_event
|
||||
gtk_gestures_interpreter_finish
|
||||
gtk_gestures_interpreter_get_n_active_strokes
|
||||
|
||||
<SUBSECTION Gestures>
|
||||
GtkGestureStroke
|
||||
gtk_gesture_stroke_new
|
||||
gtk_gesture_stroke_copy
|
||||
gtk_gesture_stroke_free
|
||||
gtk_gesture_stroke_append_vector
|
||||
gtk_gesture_stroke_get_n_vectors
|
||||
gtk_gesture_stroke_get_vector
|
||||
GtkGesture
|
||||
GtkGestureFlags
|
||||
gtk_gesture_new
|
||||
gtk_gesture_copy
|
||||
gtk_gesture_free
|
||||
gtk_gesture_add_stroke
|
||||
gtk_gesture_get_n_strokes
|
||||
gtk_gesture_get_stroke
|
||||
gtk_gesture_get_flags
|
||||
gtk_gesture_register
|
||||
gtk_gesture_register_static
|
||||
gtk_gesture_lookup
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_GESTURES_INTERPRETER
|
||||
GTK_IS_GESTURES_INTERPRETER
|
||||
GTK_TYPE_GESTURES_INTERPRETER
|
||||
GTK_IS_GESTURES_INTERPRETER_CLASS
|
||||
GTK_GESTURES_INTERPRETER_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_gestures_interpreter_get_type
|
||||
gtk_gesture_stroke_get_type
|
||||
gtk_gesture_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkhandlebox</FILE>
|
||||
<TITLE>GtkHandleBox</TITLE>
|
||||
@@ -2939,6 +2984,9 @@ gtk_scrolled_window_get_min_content_width
|
||||
gtk_scrolled_window_set_min_content_width
|
||||
gtk_scrolled_window_get_min_content_height
|
||||
gtk_scrolled_window_set_min_content_height
|
||||
GtkKineticScrollingFlags
|
||||
gtk_scrolled_window_set_kinetic_scrolling
|
||||
gtk_scrolled_window_get_kinetic_scrolling
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_SCROLLED_WINDOW
|
||||
@@ -5028,6 +5076,7 @@ GtkAllocation
|
||||
GtkSelectionData
|
||||
GtkWidgetAuxInfo
|
||||
GtkWidgetHelpType
|
||||
GtkCapturedEventFlags
|
||||
gtk_widget_new
|
||||
gtk_widget_destroy
|
||||
gtk_widget_in_destruction
|
||||
@@ -5213,6 +5262,7 @@ gtk_widget_get_mapped
|
||||
gtk_widget_get_requisition
|
||||
gtk_widget_device_is_shadowed
|
||||
gtk_widget_get_modifier_mask
|
||||
gtk_widget_release_captured_events
|
||||
|
||||
<SUBSECTION>
|
||||
gtk_widget_get_path
|
||||
@@ -5262,6 +5312,10 @@ gtk_widget_set_vexpand_set
|
||||
gtk_widget_queue_compute_expand
|
||||
gtk_widget_compute_expand
|
||||
|
||||
<SUBSECTION Gestures>
|
||||
gtk_widget_enable_gesture
|
||||
gtk_widget_disable_gesture
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_WIDGET
|
||||
GTK_IS_WIDGET
|
||||
@@ -7298,3 +7352,61 @@ GtkOverlayClass
|
||||
gtk_overlay_get_type
|
||||
GtkOverlayPrivate
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkcolorchooser</FILE>
|
||||
<TITLE>GtkColorChooser</TITLE>
|
||||
GtkColorChooser
|
||||
gtk_color_chooser_get_rgba
|
||||
gtk_color_chooser_set_rgba
|
||||
gtk_color_chooser_get_use_alpha
|
||||
gtk_color_chooser_set_use_alpha
|
||||
gtk_color_chooser_add_palette
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_COLOR_CHOOSER
|
||||
GTK_COLOR_CHOOSER
|
||||
GTK_IS_COLOR_CHOOSER
|
||||
GTK_COLOR_CHOOSER_GET_IFACE
|
||||
|
||||
<SUBSECTION Private>
|
||||
gtk_color_chooser_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkcolorchooserwidget</FILE>
|
||||
<TITLE>GtkColorChooserWidget</TITLE>
|
||||
GtkColorChooserWidget
|
||||
gtk_color_chooser_widget_new
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_COLOR_CHOOSER_WIDGET
|
||||
GTK_COLOR_CHOOSER_WIDGET
|
||||
GTK_COLOR_CHOOSER_WIDGET_CLASS
|
||||
GTK_IS_COLOR_CHOOSER_WIDGET
|
||||
GTK_IS_COLOR_CHOOSER_WIDGET_CLASS
|
||||
GTK_COLOR_CHOOSER_WIDGET_GET_CLASS
|
||||
|
||||
<SUBSECTION Private>
|
||||
gtk_color_chooser_widget_get_type
|
||||
GtkColorChooserWidgetPrivate
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkcolorchooserdialog</FILE>
|
||||
<TITLE>GtkColorChooserDialog</TITLE>
|
||||
GtkColorChooserDialog
|
||||
gtk_color_chooser_dialog_new
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_TYPE_COLOR_CHOOSER_DIALOG
|
||||
GTK_COLOR_CHOOSER_DIALOG
|
||||
GTK_COLOR_CHOOSER_DIALOG_CLASS
|
||||
GTK_IS_COLOR_CHOOSER_DIALOG
|
||||
GTK_IS_COLOR_CHOOSER_DIALOG_CLASS
|
||||
GTK_COLOR_CHOOSER_DIALOG_GET_CLASS
|
||||
|
||||
<SUBSECTION Private>
|
||||
GtkColorChooserDialogPrivate
|
||||
gtk_color_chooser_dialog_get_type
|
||||
</SECTION>
|
||||
|
||||
@@ -47,6 +47,9 @@ gtk_check_button_get_type
|
||||
gtk_check_menu_item_get_type
|
||||
gtk_clipboard_get_type
|
||||
gtk_color_button_get_type
|
||||
gtk_color_chooser_get_type
|
||||
gtk_color_chooser_dialog_get_type
|
||||
gtk_color_chooser_widget_get_type
|
||||
gtk_color_selection_dialog_get_type
|
||||
gtk_color_selection_get_type
|
||||
gtk_combo_box_get_type
|
||||
@@ -74,6 +77,7 @@ gtk_font_chooser_widget_get_type
|
||||
gtk_font_selection_dialog_get_type
|
||||
gtk_font_selection_get_type
|
||||
gtk_frame_get_type
|
||||
gtk_gestures_interpreter_get_type
|
||||
gtk_grid_get_type
|
||||
gtk_handle_box_get_type
|
||||
gtk_hbox_get_type
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@@ -135,4 +135,10 @@
|
||||
<link linkend="GtkSwitch">
|
||||
<inlinegraphic fileref="switch.png" format="PNG"></inlinegraphic>
|
||||
</link>
|
||||
<link linkend="GtkColorChooserDialog">
|
||||
<inlinegraphic fileref="colorchooser.png" format="PNG"></inlinegraphic>
|
||||
</link>
|
||||
<link linkend="GtkFontChooserDialog">
|
||||
<inlinegraphic fileref="fontchooser.png" format="PNG"></inlinegraphic>
|
||||
</link>
|
||||
</para>
|
||||
|
||||
@@ -1154,6 +1154,33 @@ create_appchooserdialog (void)
|
||||
return info;
|
||||
}
|
||||
|
||||
static WidgetInfo *
|
||||
create_fontchooserdialog (void)
|
||||
{
|
||||
WidgetInfo *info;
|
||||
GtkWidget *widget;
|
||||
|
||||
widget = gtk_font_chooser_dialog_new ("Font Chooser Dialog", NULL);
|
||||
gtk_window_set_default_size (GTK_WINDOW (widget), 200, 300);
|
||||
info = new_widget_info ("fontchooser", widget, ASIS);
|
||||
info->include_decorations = TRUE;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static WidgetInfo *
|
||||
create_colorchooserdialog (void)
|
||||
{
|
||||
WidgetInfo *info;
|
||||
GtkWidget *widget;
|
||||
|
||||
widget = gtk_color_chooser_dialog_new ("Color Chooser Dialog", NULL);
|
||||
info = new_widget_info ("colorchooser", widget, ASIS);
|
||||
info->include_decorations = TRUE;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
GList *
|
||||
get_all_widgets (void)
|
||||
{
|
||||
@@ -1204,6 +1231,8 @@ get_all_widgets (void)
|
||||
retval = g_list_prepend (retval, create_appchooserbutton ());
|
||||
retval = g_list_prepend (retval, create_appchooserdialog ());
|
||||
retval = g_list_prepend (retval, create_lockbutton ());
|
||||
retval = g_list_prepend (retval, create_fontchooserdialog ());
|
||||
retval = g_list_prepend (retval, create_colorchooserdialog ());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ gdk_public_h_sources = \
|
||||
gdkselection.h \
|
||||
gdktestutils.h \
|
||||
gdkthreads.h \
|
||||
gdktouchcluster.h \
|
||||
gdktypes.h \
|
||||
gdkvisual.h \
|
||||
gdkwindow.h
|
||||
@@ -130,6 +131,7 @@ gdk_c_sources = \
|
||||
gdkrgba.c \
|
||||
gdkscreen.c \
|
||||
gdkselection.c \
|
||||
gdktouchcluster.c \
|
||||
gdkvisual.c \
|
||||
gdkwindow.c \
|
||||
gdkwindowimpl.c
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include <gdk/gdkselection.h>
|
||||
#include <gdk/gdktestutils.h>
|
||||
#include <gdk/gdkthreads.h>
|
||||
#include <gdk/gdktouchcluster.h>
|
||||
#include <gdk/gdktypes.h>
|
||||
#include <gdk/gdkvisual.h>
|
||||
#include <gdk/gdkwindow.h>
|
||||
|
||||
@@ -168,6 +168,7 @@ gdk_event_get_scroll_direction
|
||||
gdk_event_get_source_device
|
||||
gdk_event_get_state
|
||||
gdk_event_get_time
|
||||
gdk_event_get_touch_id
|
||||
gdk_event_get_type
|
||||
gdk_event_handler_set
|
||||
gdk_event_mask_get_type
|
||||
@@ -327,6 +328,11 @@ gdk_threads_enter
|
||||
gdk_threads_init
|
||||
gdk_threads_leave
|
||||
gdk_threads_set_lock_functions
|
||||
gdk_touch_cluster_add_touch
|
||||
gdk_touch_cluster_get_device
|
||||
gdk_touch_cluster_get_type G_GNUC_CONST
|
||||
gdk_touch_cluster_list_touches
|
||||
gdk_touch_cluster_remove_touch
|
||||
gdk_unicode_to_keyval
|
||||
gdk_utf8_to_string_target
|
||||
gdk_visibility_state_get_type
|
||||
|
||||
+3
-1
@@ -61,6 +61,7 @@ typedef enum
|
||||
* of a stylus on a graphics tablet.
|
||||
* @GDK_SOURCE_CURSOR: the device is a graphics tablet "puck" or similar device.
|
||||
* @GDK_SOURCE_KEYBOARD: the device is a keyboard.
|
||||
* @GDK_SOURCE_TOUCH: the device is a touch capable device.
|
||||
*
|
||||
* An enumeration describing the type of an input device in general terms.
|
||||
*/
|
||||
@@ -70,7 +71,8 @@ typedef enum
|
||||
GDK_SOURCE_PEN,
|
||||
GDK_SOURCE_ERASER,
|
||||
GDK_SOURCE_CURSOR,
|
||||
GDK_SOURCE_KEYBOARD
|
||||
GDK_SOURCE_KEYBOARD,
|
||||
GDK_SOURCE_TOUCH
|
||||
} GdkInputSource;
|
||||
|
||||
/**
|
||||
|
||||
+135
-13
@@ -188,6 +188,7 @@ gdk_display_init (GdkDisplay *display)
|
||||
display->double_click_time = 250;
|
||||
display->double_click_distance = 5;
|
||||
|
||||
display->touch_implicit_grabs = g_array_new (FALSE, FALSE, sizeof (GdkTouchGrabInfo));
|
||||
display->device_grabs = g_hash_table_new (NULL, NULL);
|
||||
display->motion_hint_info = g_hash_table_new_full (NULL, NULL, NULL,
|
||||
(GDestroyNotify) g_free);
|
||||
@@ -236,6 +237,8 @@ gdk_display_finalize (GObject *object)
|
||||
NULL);
|
||||
g_hash_table_destroy (display->device_grabs);
|
||||
|
||||
g_array_free (display->touch_implicit_grabs, TRUE);
|
||||
|
||||
g_hash_table_destroy (display->motion_hint_info);
|
||||
g_hash_table_destroy (display->pointers_info);
|
||||
g_hash_table_destroy (display->multiple_click_info);
|
||||
@@ -694,6 +697,81 @@ _gdk_display_add_device_grab (GdkDisplay *display,
|
||||
return info;
|
||||
}
|
||||
|
||||
static void
|
||||
_gdk_display_break_touch_grabs (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
GdkWindow *new_grab_window)
|
||||
{
|
||||
guint i = 0;
|
||||
|
||||
while (i < display->touch_implicit_grabs->len)
|
||||
{
|
||||
GdkTouchGrabInfo *info;
|
||||
|
||||
info = &g_array_index (display->touch_implicit_grabs,
|
||||
GdkTouchGrabInfo, i);
|
||||
|
||||
if (info->device == device &&
|
||||
info->window != new_grab_window)
|
||||
{
|
||||
generate_grab_broken_event (GDK_WINDOW (info->window),
|
||||
device, TRUE, new_grab_window);
|
||||
_gdk_window_finish_touch_id (info->window, device, info->touch_id);
|
||||
g_array_remove_index_fast (display->touch_implicit_grabs, i);
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_display_add_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
guint touch_id,
|
||||
GdkWindow *window,
|
||||
GdkWindow *native_window,
|
||||
GdkEventMask event_mask,
|
||||
unsigned long serial,
|
||||
guint32 time)
|
||||
{
|
||||
GdkTouchGrabInfo info;
|
||||
|
||||
info.device = device;
|
||||
info.touch_id = touch_id;
|
||||
info.window = g_object_ref (window);
|
||||
info.native_window = g_object_ref (native_window);
|
||||
info.serial = serial;
|
||||
info.event_mask = event_mask;
|
||||
info.time = time;
|
||||
|
||||
g_array_append_val (display->touch_implicit_grabs, info);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_display_end_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
guint touch_id)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < display->touch_implicit_grabs->len; i++)
|
||||
{
|
||||
GdkTouchGrabInfo *info;
|
||||
|
||||
info = &g_array_index (display->touch_implicit_grabs,
|
||||
GdkTouchGrabInfo, i);
|
||||
|
||||
if (info->device == device &&
|
||||
info->touch_id == touch_id)
|
||||
{
|
||||
g_array_remove_index_fast (display->touch_implicit_grabs, i);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* _gdk_synthesize_crossing_events only works inside one toplevel.
|
||||
This function splits things into two calls if needed, converting the
|
||||
coordinates to the right toplevel */
|
||||
@@ -897,15 +975,25 @@ switch_to_pointer_grab (GdkDisplay *display,
|
||||
|
||||
if (grab == NULL) /* Ungrabbed, send events */
|
||||
{
|
||||
pointer_window = NULL;
|
||||
if (new_toplevel)
|
||||
{
|
||||
/* Find (possibly virtual) child window */
|
||||
pointer_window =
|
||||
_gdk_window_find_descendant_at (new_toplevel,
|
||||
x, y,
|
||||
NULL, NULL);
|
||||
}
|
||||
/* If the source device is a touch device, do not
|
||||
* propagate any enter event yet, until one is
|
||||
* synthesized when needed.
|
||||
*/
|
||||
if (source_device &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
info->need_touch_press_enter = TRUE;
|
||||
|
||||
pointer_window = NULL;
|
||||
|
||||
if (new_toplevel &&
|
||||
!info->need_touch_press_enter)
|
||||
{
|
||||
/* Find (possibly virtual) child window */
|
||||
pointer_window =
|
||||
_gdk_window_find_descendant_at (new_toplevel,
|
||||
x, y,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
if (pointer_window != last_grab->window)
|
||||
synthesize_crossing_events (display, device, source_device,
|
||||
@@ -964,12 +1052,15 @@ _gdk_display_device_grab_update (GdkDisplay *display,
|
||||
next_grab = NULL; /* Actually its not yet active */
|
||||
}
|
||||
|
||||
if (next_grab)
|
||||
_gdk_display_break_touch_grabs (display, device, next_grab->window);
|
||||
|
||||
if ((next_grab == NULL && current_grab->implicit_ungrab) ||
|
||||
(next_grab != NULL && current_grab->window != next_grab->window))
|
||||
generate_grab_broken_event (GDK_WINDOW (current_grab->window),
|
||||
(next_grab != NULL && current_grab->window != next_grab->window))
|
||||
generate_grab_broken_event (GDK_WINDOW (current_grab->window),
|
||||
device,
|
||||
current_grab->implicit,
|
||||
next_grab? next_grab->window : NULL);
|
||||
current_grab->implicit,
|
||||
next_grab? next_grab->window : NULL);
|
||||
|
||||
/* Remove old grab */
|
||||
grabs = g_list_delete_link (grabs, grabs);
|
||||
@@ -1028,6 +1119,34 @@ _gdk_display_has_device_grab (GdkDisplay *display,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GdkTouchGrabInfo *
|
||||
_gdk_display_has_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
guint touch_id,
|
||||
gulong serial)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < display->touch_implicit_grabs->len; i++)
|
||||
{
|
||||
GdkTouchGrabInfo *info;
|
||||
|
||||
info = &g_array_index (display->touch_implicit_grabs,
|
||||
GdkTouchGrabInfo, i);
|
||||
|
||||
if (info->device == device &&
|
||||
info->touch_id == touch_id)
|
||||
{
|
||||
if (serial >= info->serial)
|
||||
return info;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns true if last grab was ended
|
||||
* If if_child is non-NULL, end the grab only if the grabbed
|
||||
* window is the same as if_child or a descendant of it */
|
||||
@@ -1120,6 +1239,9 @@ _gdk_display_get_pointer_info (GdkDisplay *display,
|
||||
{
|
||||
GdkPointerWindowInfo *info;
|
||||
|
||||
if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
|
||||
device = gdk_device_get_associated_device (device);
|
||||
|
||||
if (G_UNLIKELY (!device))
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -60,6 +60,19 @@ typedef struct
|
||||
guint implicit : 1;
|
||||
} GdkDeviceGrabInfo;
|
||||
|
||||
/* Tracks information about a touch implicit grab on this display */
|
||||
typedef struct
|
||||
{
|
||||
GdkDevice *device;
|
||||
guint touch_id;
|
||||
|
||||
GdkWindow *window;
|
||||
GdkWindow *native_window;
|
||||
gulong serial;
|
||||
guint event_mask;
|
||||
guint32 time;
|
||||
} GdkTouchGrabInfo;
|
||||
|
||||
/* Tracks information about which window and position the pointer last was in.
|
||||
* This is useful when we need to synthesize events later.
|
||||
* Note that we track toplevel_under_pointer using enter/leave events,
|
||||
@@ -75,6 +88,8 @@ typedef struct
|
||||
gdouble toplevel_x, toplevel_y;
|
||||
guint32 state;
|
||||
guint32 button;
|
||||
GdkDevice *last_slave;
|
||||
guint need_touch_press_enter : 1;
|
||||
} GdkPointerWindowInfo;
|
||||
|
||||
typedef struct
|
||||
@@ -103,6 +118,7 @@ struct _GdkDisplay
|
||||
guint closed : 1; /* Whether this display has been closed */
|
||||
guint ignore_core_events : 1; /* Don't send core motion and button event */
|
||||
|
||||
GArray *touch_implicit_grabs;
|
||||
GHashTable *device_grabs;
|
||||
GHashTable *motion_hint_info;
|
||||
GdkDeviceManager *device_manager;
|
||||
@@ -260,6 +276,21 @@ gboolean _gdk_display_end_device_grab (GdkDisplay *display
|
||||
gboolean _gdk_display_check_grab_ownership (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
gulong serial);
|
||||
void _gdk_display_add_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
guint touch_id,
|
||||
GdkWindow *window,
|
||||
GdkWindow *native_window,
|
||||
GdkEventMask event_mask,
|
||||
unsigned long serial_start,
|
||||
guint32 time);
|
||||
GdkTouchGrabInfo * _gdk_display_has_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
guint touch_id,
|
||||
gulong serial);
|
||||
gboolean _gdk_display_end_touch_grab (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
guint touch_id);
|
||||
void _gdk_display_enable_motion_hints (GdkDisplay *display,
|
||||
GdkDevice *device);
|
||||
GdkPointerWindowInfo * _gdk_display_get_pointer_info (GdkDisplay *display,
|
||||
|
||||
+298
-5
@@ -445,6 +445,7 @@ gdk_event_new (GdkEventType type)
|
||||
switch (type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
new_event->motion.x = 0.;
|
||||
new_event->motion.y = 0.;
|
||||
new_event->motion.x_root = 0.;
|
||||
@@ -454,6 +455,8 @@ gdk_event_new (GdkEventType type)
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
new_event->button.x = 0.;
|
||||
new_event->button.y = 0.;
|
||||
new_event->button.x_root = 0.;
|
||||
@@ -464,6 +467,8 @@ gdk_event_new (GdkEventType type)
|
||||
new_event->scroll.y = 0.;
|
||||
new_event->scroll.x_root = 0.;
|
||||
new_event->scroll.y_root = 0.;
|
||||
new_event->scroll.delta_x = 0.;
|
||||
new_event->scroll.delta_y = 0.;
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
@@ -487,7 +492,31 @@ gdk_event_is_allocated (const GdkEvent *event)
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_gdk_event_set_pointer_emulated (GdkEvent *event,
|
||||
gboolean emulated)
|
||||
{
|
||||
if (gdk_event_is_allocated (event))
|
||||
{
|
||||
GdkEventPrivate *private = (GdkEventPrivate *) event;
|
||||
|
||||
if (emulated)
|
||||
private->flags |= GDK_EVENT_POINTER_EMULATED;
|
||||
else
|
||||
private->flags &= ~(GDK_EVENT_POINTER_EMULATED);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_event_get_pointer_emulated (GdkEvent *event)
|
||||
{
|
||||
if (gdk_event_is_allocated (event))
|
||||
return (((GdkEventPrivate *) event)->flags & GDK_EVENT_POINTER_EMULATED) != 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_copy:
|
||||
* @event: a #GdkEvent
|
||||
@@ -558,12 +587,15 @@ gdk_event_copy (const GdkEvent *event)
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
if (event->button.axes)
|
||||
new_event->button.axes = g_memdup (event->button.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (event->button.device));
|
||||
break;
|
||||
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
if (event->motion.axes)
|
||||
new_event->motion.axes = g_memdup (event->motion.axes,
|
||||
sizeof (gdouble) * gdk_device_get_n_axes (event->motion.device));
|
||||
@@ -583,6 +615,22 @@ gdk_event_copy (const GdkEvent *event)
|
||||
g_object_ref (new_event->selection.requestor);
|
||||
break;
|
||||
|
||||
case GDK_MULTITOUCH_ADDED:
|
||||
case GDK_MULTITOUCH_REMOVED:
|
||||
case GDK_MULTITOUCH_UPDATED:
|
||||
{
|
||||
GdkEventMotion **motion_events;
|
||||
guint i;
|
||||
|
||||
motion_events = g_new0 (GdkEventMotion*, event->multitouch.n_events);
|
||||
|
||||
for (i = 0; i < event->multitouch.n_events; i++)
|
||||
motion_events[i] = (GdkEventMotion *) gdk_event_copy ((GdkEvent *) event->multitouch.events[i]);
|
||||
|
||||
new_event->multitouch.events = motion_events;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -639,6 +687,8 @@ gdk_event_free (GdkEvent *event)
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
g_free (event->button.axes);
|
||||
break;
|
||||
|
||||
@@ -649,6 +699,7 @@ gdk_event_free (GdkEvent *event)
|
||||
break;
|
||||
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
g_free (event->motion.axes);
|
||||
break;
|
||||
|
||||
@@ -668,6 +719,20 @@ gdk_event_free (GdkEvent *event)
|
||||
g_object_unref (event->selection.requestor);
|
||||
break;
|
||||
|
||||
case GDK_MULTITOUCH_ADDED:
|
||||
case GDK_MULTITOUCH_REMOVED:
|
||||
case GDK_MULTITOUCH_UPDATED:
|
||||
if (event->multitouch.events)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < event->multitouch.n_events; i++)
|
||||
gdk_event_free ((GdkEvent *) event->multitouch.events[i]);
|
||||
|
||||
g_free (event->multitouch.events);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -696,11 +761,14 @@ gdk_event_get_time (const GdkEvent *event)
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
return event->motion.time;
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
return event->button.time;
|
||||
case GDK_SCROLL:
|
||||
return event->scroll.time;
|
||||
@@ -726,6 +794,10 @@ gdk_event_get_time (const GdkEvent *event)
|
||||
case GDK_DROP_START:
|
||||
case GDK_DROP_FINISHED:
|
||||
return event->dnd.time;
|
||||
case GDK_MULTITOUCH_ADDED:
|
||||
case GDK_MULTITOUCH_REMOVED:
|
||||
case GDK_MULTITOUCH_UPDATED:
|
||||
return event->multitouch.time;
|
||||
case GDK_CLIENT_EVENT:
|
||||
case GDK_VISIBILITY_NOTIFY:
|
||||
case GDK_CONFIGURE:
|
||||
@@ -771,12 +843,15 @@ gdk_event_get_state (const GdkEvent *event,
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
*state = event->motion.state;
|
||||
return TRUE;
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
*state = event->button.state;
|
||||
return TRUE;
|
||||
case GDK_SCROLL:
|
||||
@@ -790,6 +865,11 @@ gdk_event_get_state (const GdkEvent *event,
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
*state = event->crossing.state;
|
||||
return TRUE;
|
||||
case GDK_MULTITOUCH_ADDED:
|
||||
case GDK_MULTITOUCH_REMOVED:
|
||||
case GDK_MULTITOUCH_UPDATED:
|
||||
*state = event->multitouch.state;
|
||||
return TRUE;
|
||||
case GDK_PROPERTY_NOTIFY:
|
||||
case GDK_VISIBILITY_NOTIFY:
|
||||
case GDK_CLIENT_EVENT:
|
||||
@@ -865,10 +945,13 @@ gdk_event_get_coords (const GdkEvent *event,
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
x = event->button.x;
|
||||
y = event->button.y;
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
x = event->motion.x;
|
||||
y = event->motion.y;
|
||||
break;
|
||||
@@ -908,6 +991,7 @@ gdk_event_get_root_coords (const GdkEvent *event,
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
x = event->motion.x_root;
|
||||
y = event->motion.y_root;
|
||||
break;
|
||||
@@ -919,6 +1003,8 @@ gdk_event_get_root_coords (const GdkEvent *event,
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
x = event->button.x_root;
|
||||
y = event->button.y_root;
|
||||
break;
|
||||
@@ -1122,7 +1208,10 @@ gdk_event_get_scroll_direction (const GdkEvent *event,
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_SCROLL:
|
||||
dir = event->scroll.direction;
|
||||
if (event->scroll.direction == GDK_SCROLL_SMOOTH)
|
||||
fetched = FALSE;
|
||||
else
|
||||
dir = event->scroll.direction;
|
||||
break;
|
||||
default:
|
||||
fetched = FALSE;
|
||||
@@ -1135,6 +1224,52 @@ gdk_event_get_scroll_direction (const GdkEvent *event,
|
||||
return fetched;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_get_scroll_deltas:
|
||||
* @event: a #GdkEvent
|
||||
* @delta_x: return location for X delta
|
||||
* @delta_y: return location for Y delta
|
||||
*
|
||||
* Retrieves the scroll deltas from a #GdkEvent
|
||||
*
|
||||
* Returns: %TRUE if the event contains smooth scroll information
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
gboolean
|
||||
gdk_event_get_scroll_deltas (const GdkEvent *event,
|
||||
gdouble *delta_x,
|
||||
gdouble *delta_y)
|
||||
{
|
||||
gboolean fetched = TRUE;
|
||||
gdouble dx = 0.0;
|
||||
gdouble dy = 0.0;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_SCROLL:
|
||||
if (event->scroll.direction == GDK_SCROLL_SMOOTH)
|
||||
{
|
||||
dx = event->scroll.delta_x;
|
||||
dy = event->scroll.delta_y;
|
||||
}
|
||||
else
|
||||
fetched = FALSE;
|
||||
break;
|
||||
default:
|
||||
fetched = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (delta_x)
|
||||
*delta_x = dx;
|
||||
|
||||
if (delta_y)
|
||||
*delta_y = dy;
|
||||
|
||||
return fetched;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_get_axis:
|
||||
* @event: a #GdkEvent
|
||||
@@ -1162,7 +1297,8 @@ gdk_event_get_axis (const GdkEvent *event,
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
x = event->motion.x;
|
||||
y = event->motion.y;
|
||||
break;
|
||||
@@ -1172,6 +1308,8 @@ gdk_event_get_axis (const GdkEvent *event,
|
||||
break;
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
x = event->button.x;
|
||||
y = event->button.y;
|
||||
break;
|
||||
@@ -1193,12 +1331,15 @@ gdk_event_get_axis (const GdkEvent *event,
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->type == GDK_BUTTON_PRESS ||
|
||||
event->type == GDK_BUTTON_RELEASE)
|
||||
event->type == GDK_BUTTON_RELEASE ||
|
||||
event->type == GDK_TOUCH_PRESS ||
|
||||
event->type == GDK_TOUCH_RELEASE)
|
||||
{
|
||||
device = event->button.device;
|
||||
axes = event->button.axes;
|
||||
}
|
||||
else if (event->type == GDK_MOTION_NOTIFY)
|
||||
else if (event->type == GDK_MOTION_NOTIFY ||
|
||||
event->type == GDK_TOUCH_MOTION)
|
||||
{
|
||||
device = event->motion.device;
|
||||
axes = event->motion.axes;
|
||||
@@ -1235,12 +1376,15 @@ gdk_event_set_device (GdkEvent *event,
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
event->motion.device = device;
|
||||
break;
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
event->button.device = device;
|
||||
break;
|
||||
case GDK_SCROLL:
|
||||
@@ -1250,6 +1394,10 @@ gdk_event_set_device (GdkEvent *event,
|
||||
case GDK_PROXIMITY_OUT:
|
||||
event->proximity.device = device;
|
||||
break;
|
||||
case GDK_MULTITOUCH_ADDED:
|
||||
case GDK_MULTITOUCH_REMOVED:
|
||||
case GDK_MULTITOUCH_UPDATED:
|
||||
event->multitouch.device = device;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1282,17 +1430,24 @@ gdk_event_get_device (const GdkEvent *event)
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
return event->motion.device;
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
return event->button.device;
|
||||
case GDK_SCROLL:
|
||||
return event->scroll.device;
|
||||
case GDK_PROXIMITY_IN:
|
||||
case GDK_PROXIMITY_OUT:
|
||||
return event->proximity.device;
|
||||
case GDK_MULTITOUCH_ADDED:
|
||||
case GDK_MULTITOUCH_REMOVED:
|
||||
case GDK_MULTITOUCH_UPDATED:
|
||||
return event->multitouch.device;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1301,10 +1456,13 @@ gdk_event_get_device (const GdkEvent *event)
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
case GDK_FOCUS_CHANGE:
|
||||
@@ -1320,6 +1478,9 @@ gdk_event_get_device (const GdkEvent *event)
|
||||
case GDK_GRAB_BROKEN:
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
case GDK_MULTITOUCH_ADDED:
|
||||
case GDK_MULTITOUCH_REMOVED:
|
||||
case GDK_MULTITOUCH_UPDATED:
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GdkDeviceManager *device_manager;
|
||||
@@ -1686,6 +1847,138 @@ gdk_event_get_screen (const GdkEvent *event)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_get_touch_id:
|
||||
* @event: a #GdkEvent
|
||||
* @touch_id: return location of the touch ID of a touch event
|
||||
*
|
||||
* If @event if of type %GDK_TOUCH_MOTION, %GDK_TOUCH_PRESS or
|
||||
* %GDK_TOUCH_RELEASE, fills in @touch_id and returns %TRUE,
|
||||
* else it returns %FALSE.
|
||||
*
|
||||
* Returns: %TRUE if the touch ID can be extracted from @event.
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
gboolean
|
||||
gdk_event_get_touch_id (const GdkEvent *event,
|
||||
guint *touch_id)
|
||||
{
|
||||
if (!event)
|
||||
return FALSE;
|
||||
|
||||
if (event->type == GDK_TOUCH_MOTION)
|
||||
{
|
||||
if (touch_id)
|
||||
*touch_id = event->motion.touch_id;
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->type == GDK_TOUCH_PRESS ||
|
||||
event->type == GDK_TOUCH_RELEASE)
|
||||
{
|
||||
if (touch_id)
|
||||
*touch_id = event->button.touch_id;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (touch_id)
|
||||
*touch_id = 0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_event_get_touch_area:
|
||||
* @event: a #GdkEvent
|
||||
*
|
||||
* This function takes a #GdkEvent coming from a touch device
|
||||
* (eg. gdk_event_get_source_device() returns a device of type
|
||||
* %GDK_SOURCE_TOUCH), and returns the area covered by the touch
|
||||
* as a #cairo_region_t. or %NULL if the device doesn't provide
|
||||
* this information, or the touch area information couldn't be
|
||||
* extracted from the event.
|
||||
*
|
||||
* <note><warning>Not all touch capable devices provide this
|
||||
* information, so provide fallbacks to this function returning
|
||||
* %NULL, even if the window receiving events is only meant
|
||||
* to react to touch events.</warning></note>
|
||||
*
|
||||
* Returns: (transfer full): the touch region, or %NULL if unavailable
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
cairo_region_t *
|
||||
gdk_event_get_touch_area (GdkEvent *event)
|
||||
{
|
||||
gdouble *axes, minor_axis, major_axis, orientation_axis;
|
||||
GdkAtom major, minor, orientation;
|
||||
GdkDevice *device;
|
||||
|
||||
g_return_val_if_fail (event != NULL, NULL);
|
||||
|
||||
device = gdk_event_get_source_device (event);
|
||||
|
||||
if (!device)
|
||||
return NULL;
|
||||
|
||||
if (event->type == GDK_MOTION_NOTIFY ||
|
||||
event->type == GDK_TOUCH_MOTION)
|
||||
axes = event->motion.axes;
|
||||
else if (event->type == GDK_BUTTON_PRESS ||
|
||||
event->type == GDK_2BUTTON_PRESS ||
|
||||
event->type == GDK_3BUTTON_PRESS ||
|
||||
event->type == GDK_BUTTON_RELEASE)
|
||||
axes = event->button.axes;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
major = gdk_atom_intern_static_string ("Abs MT Touch Major");
|
||||
minor = gdk_atom_intern_static_string ("Abs MT Touch Minor");
|
||||
orientation = gdk_atom_intern_static_string ("Abs MT Orientation");
|
||||
|
||||
if (gdk_device_get_axis_value (device, axes, major, &major_axis) &&
|
||||
gdk_device_get_axis_value (device, axes, minor, &minor_axis) &&
|
||||
gdk_device_get_axis_value (device, axes, orientation, &orientation_axis))
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
GdkScreen *screen;
|
||||
gdouble x, y;
|
||||
|
||||
/* FIXME: We're assuming the device is mapped to a single screen,
|
||||
* could lead to stretched/shrinked shapes in multimonitor, although
|
||||
* that'd be an unusual setup for touchscreens.
|
||||
*/
|
||||
screen = gdk_window_get_screen (event->any.window);
|
||||
gdk_event_get_coords (event, &x, &y);
|
||||
|
||||
if (orientation_axis == 0)
|
||||
{
|
||||
/* Orientation is horizontal */
|
||||
rect.width = (gint) gdk_screen_get_width (screen) * major_axis;
|
||||
rect.height = (gint) gdk_screen_get_height (screen) * minor_axis;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Orientation is vertical */
|
||||
rect.height = (gint) gdk_screen_get_height (screen) * major_axis;
|
||||
rect.width = (gint) gdk_screen_get_width (screen) * minor_axis;
|
||||
}
|
||||
|
||||
/* Something is wrong here */
|
||||
if (rect.width == 0 ||
|
||||
rect.height == 0)
|
||||
return NULL;
|
||||
|
||||
rect.x = x - rect.width / 2;
|
||||
rect.y = y - rect.height / 2;
|
||||
|
||||
return cairo_region_create_rectangle (&rect);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_set_show_events:
|
||||
* @show_events: %TRUE to output event debugging information.
|
||||
|
||||
+114
-5
@@ -35,6 +35,7 @@
|
||||
#include <gdk/gdktypes.h>
|
||||
#include <gdk/gdkdnd.h>
|
||||
#include <gdk/gdkdevice.h>
|
||||
#include <gdk/gdktouchcluster.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -143,6 +144,7 @@ typedef struct _GdkEventDND GdkEventDND;
|
||||
typedef struct _GdkEventWindowState GdkEventWindowState;
|
||||
typedef struct _GdkEventSetting GdkEventSetting;
|
||||
typedef struct _GdkEventGrabBroken GdkEventGrabBroken;
|
||||
typedef struct _GdkEventMultiTouch GdkEventMultiTouch;
|
||||
|
||||
typedef union _GdkEvent GdkEvent;
|
||||
|
||||
@@ -263,6 +265,18 @@ typedef GdkFilterReturn (*GdkFilterFunc) (GdkXEvent *xevent,
|
||||
* was added in 2.8.
|
||||
* @GDK_DAMAGE: the content of the window has been changed. This event type
|
||||
* was added in 2.14.
|
||||
* @GDK_TOUCH_MOTION: A touch device has been updated. This event type was
|
||||
* added in 3.4.
|
||||
* @GDK_TOUCH_PRESS: A new touch stream has just started. This event type was
|
||||
* added in 3.4.
|
||||
* @GDK_TOUCH_RELEASE: A touch stream has finished. This event type was
|
||||
* added in 3.4.
|
||||
* @GDK_MULTITOUCH_ADDED: A touch ID was added to a #GdkTouchCluster. This
|
||||
* event type was added in 3.4.
|
||||
* @GDK_MULTITOUCH_UPDATED: A touch within a #GdkTouchCluster has been updated.
|
||||
* This event type was added in 3.4.
|
||||
* @GDK_MULTITOUCH_REMOVED: A touch ID was removed from a #GdkTouchCluster. This
|
||||
* event type was added in 3.4.
|
||||
* @GDK_EVENT_LAST: marks the end of the GdkEventType enumeration. Added in 2.18
|
||||
*
|
||||
* Specifies the type of the event.
|
||||
@@ -310,6 +324,12 @@ typedef enum
|
||||
GDK_OWNER_CHANGE = 34,
|
||||
GDK_GRAB_BROKEN = 35,
|
||||
GDK_DAMAGE = 36,
|
||||
GDK_TOUCH_MOTION = 37,
|
||||
GDK_TOUCH_PRESS = 38,
|
||||
GDK_TOUCH_RELEASE = 39,
|
||||
GDK_MULTITOUCH_ADDED = 40,
|
||||
GDK_MULTITOUCH_UPDATED = 41,
|
||||
GDK_MULTITOUCH_REMOVED = 42,
|
||||
GDK_EVENT_LAST /* helper variable for decls */
|
||||
} GdkEventType;
|
||||
|
||||
@@ -334,6 +354,8 @@ typedef enum
|
||||
* @GDK_SCROLL_DOWN: the window is scrolled down.
|
||||
* @GDK_SCROLL_LEFT: the window is scrolled to the left.
|
||||
* @GDK_SCROLL_RIGHT: the window is scrolled to the right.
|
||||
* @GDK_SCROLL_SMOOTH: the scrolling is determined by the delta values
|
||||
* in #GdkEventScroll. See gdk_event_get_scroll_deltas().
|
||||
*
|
||||
* Specifies the direction for #GdkEventScroll.
|
||||
*/
|
||||
@@ -342,7 +364,8 @@ typedef enum
|
||||
GDK_SCROLL_UP,
|
||||
GDK_SCROLL_DOWN,
|
||||
GDK_SCROLL_LEFT,
|
||||
GDK_SCROLL_RIGHT
|
||||
GDK_SCROLL_RIGHT,
|
||||
GDK_SCROLL_SMOOTH
|
||||
} GdkScrollDirection;
|
||||
|
||||
/**
|
||||
@@ -385,6 +408,13 @@ typedef enum
|
||||
* @GDK_CROSSING_GTK_UNGRAB: crossing because a GTK+ grab is deactivated.
|
||||
* @GDK_CROSSING_STATE_CHANGED: crossing because a GTK+ widget changed
|
||||
* state (e.g. sensitivity).
|
||||
* @GDK_CROSSING_TOUCH_PRESS: crossing because a touch device was pressed,
|
||||
* this event is synthetic as the pointer might have not left the window.
|
||||
* @GDK_CROSSING_TOUCH_RELEASE: crossing because a touch device was released.
|
||||
* this event is synthetic as the pointer might have not left the window.
|
||||
* @GDK_CROSSING_DEVICE_SWITCH: crossing because of a device switch (i.e.
|
||||
* a mouse taking control of the pointer after a touch device), this event
|
||||
* is synthetic as the pointer didn't leave the window.
|
||||
*
|
||||
* Specifies the crossing mode for #GdkEventCrossing.
|
||||
*/
|
||||
@@ -395,7 +425,10 @@ typedef enum
|
||||
GDK_CROSSING_UNGRAB,
|
||||
GDK_CROSSING_GTK_GRAB,
|
||||
GDK_CROSSING_GTK_UNGRAB,
|
||||
GDK_CROSSING_STATE_CHANGED
|
||||
GDK_CROSSING_STATE_CHANGED,
|
||||
GDK_CROSSING_TOUCH_PRESS,
|
||||
GDK_CROSSING_TOUCH_RELEASE,
|
||||
GDK_CROSSING_DEVICE_SWITCH
|
||||
} GdkCrossingMode;
|
||||
|
||||
/**
|
||||
@@ -552,8 +585,13 @@ struct _GdkEventVisibility
|
||||
* screen.
|
||||
* @y_root: the y coordinate of the pointer relative to the root of the
|
||||
* screen.
|
||||
* @touch_id: touch ID, only meaningful if event is of type %GDK_TOUCH_MOTION.
|
||||
*
|
||||
* Generated when the pointer moves.
|
||||
* Generated when the pointer/touch moves.
|
||||
*
|
||||
* If the event has a type of %GDK_TOUCH_MOTION, this event will
|
||||
* pertain to a sequence identified by gdk_event_get_touch_id().
|
||||
* With multitouch devices, there may be several ongoing sequences.
|
||||
*/
|
||||
struct _GdkEventMotion
|
||||
{
|
||||
@@ -568,12 +606,63 @@ struct _GdkEventMotion
|
||||
gint16 is_hint;
|
||||
GdkDevice *device;
|
||||
gdouble x_root, y_root;
|
||||
guint touch_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* GdkEventMultiTouch:
|
||||
* @type: the type of the event (%GDK_MULTITOUCH_ADDED, %GDK_MULTITOUCH_UPDATED
|
||||
* or %GDK_MULTITOUCH_REMOVED).
|
||||
* @window: the window which received the event.
|
||||
* @send_event: %TRUE if the event was sent explicitly (e.g. using
|
||||
* <function>XSendEvent</function>).
|
||||
* @time: the time of the event in milliseconds.
|
||||
* @state: (type GdkModifierType): a bit-mask representing the state of
|
||||
* the modifier keys (e.g. Control, Shift and Alt) and the pointer
|
||||
* buttons. See #GdkModifierType.
|
||||
* @device: the device where the event originated.
|
||||
* @group: the #GdkTouchCluster containing the touches that generated this event
|
||||
* @events: an array of events of type %GDK_TOUCH_MOTION for the touches in @group
|
||||
* @updated_touch_id: the touch ID that caused this event to be generated
|
||||
* @n_events: the number of events in @events
|
||||
* @n_updated_event: the index in @events of the event corresponding to
|
||||
* @updated_touch_id, or -1 for %GDK_MULTITOUCH_REMOVED events.
|
||||
*
|
||||
* Used for multitouch events. The @type field will be one of
|
||||
* %GDK_MULTITOUCH_ADDED, %GDK_MULTITOUCH_UPDATED or
|
||||
* %GDK_MULTITOUCH_REMOVED.
|
||||
*
|
||||
* Multitouch events group the events from the touches in a
|
||||
* #GdkTouchCluster, so one of these events is generated
|
||||
* whenever a touch ID generates a new event, or a touch ID
|
||||
* is added or removed.
|
||||
*
|
||||
* For any given touch ID, %GDK_MULTITOUCH_ADDED and
|
||||
* %GDK_MULTITOUCH_REMOVED events are always paired,
|
||||
* with any number of %GDK_MULTITOUCH_UPDATED
|
||||
* events in between. The minimum event stream is an
|
||||
* added/removed pair.
|
||||
*/
|
||||
struct _GdkEventMultiTouch
|
||||
{
|
||||
GdkEventType type;
|
||||
GdkWindow *window;
|
||||
gint8 send_event;
|
||||
guint32 time;
|
||||
guint state;
|
||||
GdkDevice *device;
|
||||
GdkTouchCluster *group;
|
||||
GdkEventMotion **events;
|
||||
guint updated_touch_id;
|
||||
gint8 n_events;
|
||||
gint8 n_updated_event;
|
||||
};
|
||||
|
||||
/**
|
||||
* GdkEventButton:
|
||||
* @type: the type of the event (%GDK_BUTTON_PRESS, %GDK_2BUTTON_PRESS,
|
||||
* %GDK_3BUTTON_PRESS or %GDK_BUTTON_RELEASE).
|
||||
* %GDK_3BUTTON_PRESS, %GDK_BUTTON_RELEASE, %GDK_TOUCH_PRESS or
|
||||
* %GDK_TOUCH_RELEASE).
|
||||
* @window: the window which received the event.
|
||||
* @send_event: %TRUE if the event was sent explicitly (e.g. using
|
||||
* <function>XSendEvent</function>).
|
||||
@@ -594,10 +683,13 @@ struct _GdkEventMotion
|
||||
* screen.
|
||||
* @y_root: the y coordinate of the pointer relative to the root of the
|
||||
* screen.
|
||||
* @touch_id: touch ID, only meaningful if event is of type %GDK_TOUCH_PRESS
|
||||
* or %GDK_TOUCH_RELEASE.
|
||||
*
|
||||
* Used for button press and button release events. The
|
||||
* @type field will be one of %GDK_BUTTON_PRESS,
|
||||
* %GDK_2BUTTON_PRESS, %GDK_3BUTTON_PRESS, and %GDK_BUTTON_RELEASE.
|
||||
* %GDK_2BUTTON_PRESS, %GDK_3BUTTON_PRESS, %GDK_BUTTON_RELEASE,
|
||||
* %GDK_TOUCH_PRESS and %GDK_TOUCH_RELEASE.
|
||||
*
|
||||
* Double and triple-clicks result in a sequence of events being received.
|
||||
* For double-clicks the order of events will be:
|
||||
@@ -629,6 +721,11 @@ struct _GdkEventMotion
|
||||
* For a double click to occur, the second button press must occur within
|
||||
* 1/4 of a second of the first. For a triple click to occur, the third
|
||||
* button press must also occur within 1/2 second of the first button press.
|
||||
*
|
||||
* If the event has a type of %GDK_TOUCH_PRESS or %GDK_TOUCH_RELEASE,
|
||||
* this event will pertain to a sequence identified by
|
||||
* gdk_event_get_touch_id(). With multitouch devices, there may be
|
||||
* several ongoing sequences.
|
||||
*/
|
||||
struct _GdkEventButton
|
||||
{
|
||||
@@ -643,6 +740,7 @@ struct _GdkEventButton
|
||||
guint button;
|
||||
GdkDevice *device;
|
||||
gdouble x_root, y_root;
|
||||
guint touch_id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -681,6 +779,8 @@ struct _GdkEventScroll
|
||||
GdkScrollDirection direction;
|
||||
GdkDevice *device;
|
||||
gdouble x_root, y_root;
|
||||
gdouble delta_x;
|
||||
gdouble delta_y;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1086,6 +1186,7 @@ union _GdkEvent
|
||||
GdkEventWindowState window_state;
|
||||
GdkEventSetting setting;
|
||||
GdkEventGrabBroken grab_broken;
|
||||
GdkEventMultiTouch multitouch;
|
||||
};
|
||||
|
||||
GType gdk_event_get_type (void) G_GNUC_CONST;
|
||||
@@ -1119,6 +1220,10 @@ gboolean gdk_event_get_keycode (const GdkEvent *event,
|
||||
guint16 *keycode);
|
||||
gboolean gdk_event_get_scroll_direction (const GdkEvent *event,
|
||||
GdkScrollDirection *direction);
|
||||
gboolean gdk_event_get_scroll_deltas (const GdkEvent *event,
|
||||
gdouble *delta_x,
|
||||
gdouble *delta_y);
|
||||
|
||||
gboolean gdk_event_get_axis (const GdkEvent *event,
|
||||
GdkAxisUse axis_use,
|
||||
gdouble *value);
|
||||
@@ -1150,6 +1255,10 @@ void gdk_event_set_screen (GdkEvent *event,
|
||||
GdkScreen *screen);
|
||||
GdkScreen *gdk_event_get_screen (const GdkEvent *event);
|
||||
|
||||
gboolean gdk_event_get_touch_id (const GdkEvent *event,
|
||||
guint *touch_id);
|
||||
cairo_region_t * gdk_event_get_touch_area (GdkEvent *event);
|
||||
|
||||
void gdk_set_show_events (gboolean show_events);
|
||||
gboolean gdk_get_show_events (void);
|
||||
|
||||
|
||||
+20
-1
@@ -150,7 +150,13 @@ typedef enum
|
||||
/* Following flag is set for events on the event queue during
|
||||
* translation and cleared afterwards.
|
||||
*/
|
||||
GDK_EVENT_PENDING = 1 << 0
|
||||
GDK_EVENT_PENDING = 1 << 0,
|
||||
|
||||
/* The following flag is set for:
|
||||
* 1) touch events emulating pointer events
|
||||
* 2) pointer events being emulated by a touch sequence.
|
||||
*/
|
||||
GDK_EVENT_POINTER_EMULATED = 1 << 1
|
||||
} GdkEventFlags;
|
||||
|
||||
struct _GdkEventPrivate
|
||||
@@ -260,6 +266,12 @@ struct _GdkWindow
|
||||
gulong device_changed_handler_id;
|
||||
|
||||
guint num_offscreen_children;
|
||||
|
||||
/* Store of latest per-touch events, keys are
|
||||
* GdkDevices, values are hashtables of touchID/info
|
||||
*/
|
||||
GHashTable *touch_event_tracker;
|
||||
GList *touch_clusters;
|
||||
};
|
||||
|
||||
#define GDK_WINDOW_TYPE(d) (((GDK_WINDOW (d)))->window_type)
|
||||
@@ -275,6 +287,10 @@ GdkEvent* _gdk_event_unqueue (GdkDisplay *display);
|
||||
void _gdk_event_filter_unref (GdkWindow *window,
|
||||
GdkEventFilter *filter);
|
||||
|
||||
void _gdk_event_set_pointer_emulated (GdkEvent *event,
|
||||
gboolean emulated);
|
||||
gboolean _gdk_event_get_pointer_emulated (GdkEvent *event);
|
||||
|
||||
void _gdk_event_emit (GdkEvent *event);
|
||||
GList* _gdk_event_queue_find_first (GdkDisplay *display);
|
||||
void _gdk_event_queue_remove_link (GdkDisplay *display,
|
||||
@@ -318,6 +334,9 @@ gboolean _gdk_window_update_viewable (GdkWindow *window);
|
||||
|
||||
void _gdk_window_process_updates_recurse (GdkWindow *window,
|
||||
cairo_region_t *expose_region);
|
||||
gboolean _gdk_window_finish_touch_id (GdkWindow *window,
|
||||
GdkDevice *device,
|
||||
guint touch_id);
|
||||
|
||||
void _gdk_screen_close (GdkScreen *screen);
|
||||
|
||||
|
||||
@@ -0,0 +1,448 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2011 Carlos Garnacho <carlosg@gnome.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdktouchcluster.h"
|
||||
#include "gdkintl.h"
|
||||
|
||||
/**
|
||||
* SECTION:touchcluster
|
||||
* @Short_description: Multitouch handling
|
||||
* @Title: Multitouch
|
||||
* @See_also: #GdkEventMultiTouch
|
||||
*
|
||||
* #GdkTouchCluster is an object that gathers touch IDs from a
|
||||
* #GdkDevice, in order to send #GdkEventMultiTouch events
|
||||
* whenever a touch ID that is contained in the cluster sends
|
||||
* an event.
|
||||
*
|
||||
* #GdkTouchCluster<!-- -->s are always associated to a window,
|
||||
* you need to create them through gdk_window_create_touch_cluster(),
|
||||
* and free them through gdk_window_remove_touch_cluster().
|
||||
*
|
||||
* Touch IDs from devices can be obtained from %GDK_TOUCH_PRESS,
|
||||
* %GDK_TOUCH_MOTION or %GDK_TOUCH_RELEASE events through
|
||||
* gdk_event_get_touch_id(), and then be added via
|
||||
* gdk_touch_cluster_add_touch(). Note that touch IDs are
|
||||
* very transient, and they must be dealt with as such.
|
||||
* touch IDs must not be stored after a GDK_TOUCH_RELEASE,
|
||||
* and should always be retrieved from the events being
|
||||
* currently received.
|
||||
*
|
||||
* <example>
|
||||
* <title>Adding touch IDs to a cluster in a GTK+ widget</title>
|
||||
* <programlisting>
|
||||
* static gboolean
|
||||
* widget_button_press (GtkWidget *widget,
|
||||
* GdkEvent *event)
|
||||
* {
|
||||
* guint touch_id;
|
||||
*
|
||||
* if (gdk_event_get_touch_id (event, &touch_id))
|
||||
* {
|
||||
* /<!-- -->* It is a touch event, delegate processing
|
||||
* * to the multitouch event handler
|
||||
* *<!-- -->/
|
||||
* gdk_touch_cluster_add_touch (priv->touch_cluster, touch_id);
|
||||
* return TRUE;
|
||||
* }
|
||||
*
|
||||
* /<!-- -->* Normal button processing *<!-- -->/
|
||||
* ...
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*
|
||||
* Anytime a touch ID is within a cluster, no %GDK_TOUCH_PRESS,
|
||||
* %GDK_TOUCH_MOTION or %GDK_TOUCH_RELEASE events will happen
|
||||
* for the individual touch. The event will be available instead
|
||||
* as part of the #GdkMultitouchEvent that will be emitted. This
|
||||
* will hold true until gdk_touch_cluster_remove_touch() is
|
||||
* called for it. Note that GTK+ will automatically take a
|
||||
* touch ID out of any cluster if %GDK_TOUCH_RELEASE is gotten
|
||||
* internally.
|
||||
*
|
||||
* <example>
|
||||
* <title>Typical multitouch event handler</title>
|
||||
* <programlisting>
|
||||
* static gboolean
|
||||
* widget_multitouch_event (GtkWidget *widget,
|
||||
* GdkEvent *event)
|
||||
* {
|
||||
* if (event->type == GDK_MULTITOUCH_ADDED ||
|
||||
* event->type == GDK_MULTITOUCH_REMOVED)
|
||||
* {
|
||||
* /<!-- -->* Update control mode based
|
||||
* * on the current number of touches
|
||||
* *<!-- -->/
|
||||
* priv->control_mode = update_control_mode (event->multitouch.n_events);
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* /<!-- -->* A touch ID in the cluster has updated
|
||||
* * its coordinates, update widget based on the
|
||||
* * current control mode.
|
||||
* *<!-- -->/
|
||||
* update_view (widget, priv->control_mode,
|
||||
* event->multitouch.events,
|
||||
* event->multitouch.n_events);
|
||||
* }
|
||||
*
|
||||
* return TRUE;
|
||||
* }
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*/
|
||||
|
||||
typedef struct GdkTouchClusterPrivate GdkTouchClusterPrivate;
|
||||
|
||||
struct GdkTouchClusterPrivate
|
||||
{
|
||||
GdkDevice *device;
|
||||
GArray *touches;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DEVICE
|
||||
};
|
||||
|
||||
enum {
|
||||
TOUCH_ADDED,
|
||||
TOUCH_REMOVED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void gdk_touch_cluster_finalize (GObject *object);
|
||||
static void gdk_touch_cluster_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gdk_touch_cluster_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GdkTouchCluster, gdk_touch_cluster, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gdk_touch_cluster_class_init (GdkTouchClusterClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = gdk_touch_cluster_finalize;
|
||||
object_class->get_property = gdk_touch_cluster_get_property;
|
||||
object_class->set_property = gdk_touch_cluster_set_property;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_DEVICE,
|
||||
g_param_spec_object ("device",
|
||||
P_("Device"),
|
||||
P_("Device attached to the cluster"),
|
||||
GDK_TYPE_DEVICE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
signals[TOUCH_ADDED] =
|
||||
g_signal_new (g_intern_static_string ("touch-added"),
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GdkTouchClusterClass, touch_added),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__UINT,
|
||||
G_TYPE_NONE, 1, G_TYPE_UINT);
|
||||
signals[TOUCH_REMOVED] =
|
||||
g_signal_new (g_intern_static_string ("touch-removed"),
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GdkTouchClusterClass, touch_removed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__UINT,
|
||||
G_TYPE_NONE, 1, G_TYPE_UINT);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (GdkTouchClusterPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_touch_cluster_init (GdkTouchCluster *cluster)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
|
||||
priv = cluster->priv = G_TYPE_INSTANCE_GET_PRIVATE (cluster,
|
||||
GDK_TYPE_TOUCH_CLUSTER,
|
||||
GdkTouchClusterPrivate);
|
||||
priv->touches = g_array_new (FALSE, FALSE, sizeof (guint));
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_touch_cluster_finalize (GObject *object)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
|
||||
priv = GDK_TOUCH_CLUSTER (object)->priv;
|
||||
g_array_free (priv->touches, TRUE);
|
||||
|
||||
G_OBJECT_CLASS (gdk_touch_cluster_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_touch_cluster_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEVICE:
|
||||
gdk_touch_cluster_set_device (GDK_TOUCH_CLUSTER (object),
|
||||
g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_touch_cluster_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
|
||||
priv = GDK_TOUCH_CLUSTER (object)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_DEVICE:
|
||||
g_value_set_object (value, priv->device);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_touch_cluster_add_touch:
|
||||
* @cluster: a #GdkTouchCluster
|
||||
* @touch_id: a touch ID from a touch event
|
||||
*
|
||||
* Adds a touch ID to @cluster, so it will generate a
|
||||
* %GDK_MULTITOUCH_ADDED event, followed by %GDK_MULTITOUCH_UPDATED
|
||||
* events whenever this touch ID is updated.
|
||||
*
|
||||
* If @touch_id already pertained to another #GdkTouchCluster, it
|
||||
* will be removed from it, generating a %GDK_MULTITOUCH_REMOVED
|
||||
* for that another cluster.
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
void
|
||||
gdk_touch_cluster_add_touch (GdkTouchCluster *cluster,
|
||||
guint touch_id)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster));
|
||||
|
||||
priv = cluster->priv;
|
||||
|
||||
for (i = 0; i < priv->touches->len; i++)
|
||||
{
|
||||
if (touch_id == g_array_index (priv->touches, guint, i))
|
||||
return;
|
||||
}
|
||||
|
||||
g_array_append_val (priv->touches, touch_id);
|
||||
g_signal_emit (cluster, signals [TOUCH_ADDED], 0, touch_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_touch_cluster_remove_touch:
|
||||
* @cluster: a #GdkTouchCluster
|
||||
* @touch_id: a touch ID from a touch event
|
||||
*
|
||||
* Removes a touch ID from @cluster, generating a %GDK_MULTITOUCH_REMOVED
|
||||
* event for @cluster, and causing any further input from @touch_id
|
||||
* to be reported trough %GDK_TOUCH_MOTION events.
|
||||
*
|
||||
* <note><para>
|
||||
* Note that GTK+ automatically removes a touch ID from any cluster
|
||||
* if a %GDK_TOUCH_RELEASE event is gotten internally.
|
||||
* </para></note>
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
void
|
||||
gdk_touch_cluster_remove_touch (GdkTouchCluster *cluster,
|
||||
guint touch_id)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster));
|
||||
|
||||
priv = cluster->priv;
|
||||
|
||||
for (i = 0; i < priv->touches->len; i++)
|
||||
{
|
||||
if (touch_id == g_array_index (priv->touches, guint, i))
|
||||
{
|
||||
g_array_remove_index_fast (priv->touches, i);
|
||||
g_signal_emit (cluster, signals [TOUCH_REMOVED], 0, touch_id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_touch_cluster_remove_all:
|
||||
* @cluster: a #GdkTouchCluster
|
||||
*
|
||||
* Removes all touch IDs from @cluster.
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
void
|
||||
gdk_touch_cluster_remove_all (GdkTouchCluster *cluster)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
guint touch_id;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster));
|
||||
|
||||
priv = cluster->priv;
|
||||
|
||||
for (i = priv->touches->len - 1; i >= 0; i--)
|
||||
{
|
||||
touch_id = g_array_index (priv->touches, guint, i);
|
||||
g_signal_emit (cluster, signals [TOUCH_REMOVED], 0, touch_id);
|
||||
g_array_remove_index_fast (priv->touches, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gdk_touch_cluster_get_touches:
|
||||
* @cluster: a #GdkTouchCluster
|
||||
* @length: return location for the number of touches returned
|
||||
*
|
||||
* Returns the list of touches as an array of @guint.
|
||||
*
|
||||
* Returns: (transfer full) (array zero-terminated=0 length=length) (element-type uint): A list of touch IDs.
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
guint *
|
||||
gdk_touch_cluster_get_touches (GdkTouchCluster *cluster,
|
||||
gint *len)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_TOUCH_CLUSTER (cluster), NULL);
|
||||
|
||||
priv = cluster->priv;
|
||||
|
||||
if (len)
|
||||
*len = (gint) priv->touches->len;
|
||||
|
||||
return g_memdup (priv->touches->data,
|
||||
sizeof (guint) * priv->touches->len);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_touch_cluster_get_n_touches:
|
||||
* @cluster: a #GdkTouchCluster
|
||||
*
|
||||
* Returns the number of touches contained in @cluster.
|
||||
*
|
||||
* Returns: The number of touches.
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
gint
|
||||
gdk_touch_cluster_get_n_touches (GdkTouchCluster *cluster)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_TOUCH_CLUSTER (cluster), 0);
|
||||
|
||||
priv = cluster->priv;
|
||||
return (gint) priv->touches->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_touch_cluster_set_device:
|
||||
* @cluster: a #GdkTouchCluster
|
||||
* @device: a #GdkDevice
|
||||
*
|
||||
* Sets the current device associated to @cluster, all contained
|
||||
* touch IDs must pertain to this device. As a consequence,
|
||||
* gdk_touch_cluster_remove_all() will be called on @cluster
|
||||
* if the current device changes.
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
void
|
||||
gdk_touch_cluster_set_device (GdkTouchCluster *cluster,
|
||||
GdkDevice *device)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
|
||||
g_return_if_fail (GDK_IS_TOUCH_CLUSTER (cluster));
|
||||
g_return_if_fail (!device || GDK_IS_DEVICE (device));
|
||||
|
||||
priv = cluster->priv;
|
||||
|
||||
if (priv->device != device)
|
||||
gdk_touch_cluster_remove_all (cluster);
|
||||
|
||||
priv->device = device;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_touch_cluster_get_device:
|
||||
* @cluster: a #GdkTouchCluster
|
||||
*
|
||||
* Returns the slave/floating device this touch cluster pertains to,
|
||||
* only touch IDs from this device can be included in @cluster.
|
||||
* the #GdkDevice will typically have the %GDK_SOURCE_TOUCH input source.
|
||||
*
|
||||
* Returns: (transfer none): The #GdkDevice generating the contained touch IDs
|
||||
*
|
||||
* Since: 3.4
|
||||
**/
|
||||
GdkDevice *
|
||||
gdk_touch_cluster_get_device (GdkTouchCluster *cluster)
|
||||
{
|
||||
GdkTouchClusterPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_TOUCH_CLUSTER (cluster), NULL);
|
||||
|
||||
priv = cluster->priv;
|
||||
return priv->device;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2011 Carlos Garnacho <carlosg@gnome.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDK_TOUCH_CLUSTER_H__
|
||||
#define __GDK_TOUCH_CLUSTER_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gdk/gdkdevice.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_TOUCH_CLUSTER (gdk_touch_cluster_get_type ())
|
||||
#define GDK_TOUCH_CLUSTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_TOUCH_CLUSTER, GdkTouchCluster))
|
||||
#define GDK_IS_TOUCH_CLUSTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_TOUCH_CLUSTER))
|
||||
|
||||
typedef struct _GdkTouchCluster GdkTouchCluster;
|
||||
typedef struct _GdkTouchClusterClass GdkTouchClusterClass;
|
||||
|
||||
struct _GdkTouchCluster
|
||||
{
|
||||
GObject parent_instance;
|
||||
gpointer priv;
|
||||
};
|
||||
|
||||
struct _GdkTouchClusterClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* touch_added) (GdkTouchCluster *cluster,
|
||||
guint touch_id);
|
||||
void (* touch_removed) (GdkTouchCluster *cluster,
|
||||
guint touch_id);
|
||||
|
||||
gpointer padding[16];
|
||||
};
|
||||
|
||||
GType gdk_touch_cluster_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void gdk_touch_cluster_add_touch (GdkTouchCluster *cluster,
|
||||
guint touch_id);
|
||||
void gdk_touch_cluster_remove_touch (GdkTouchCluster *cluster,
|
||||
guint touch_id);
|
||||
void gdk_touch_cluster_remove_all (GdkTouchCluster *cluster);
|
||||
|
||||
guint * gdk_touch_cluster_get_touches (GdkTouchCluster *cluster,
|
||||
gint *length);
|
||||
gint gdk_touch_cluster_get_n_touches (GdkTouchCluster *cluster);
|
||||
|
||||
void gdk_touch_cluster_set_device (GdkTouchCluster *cluster,
|
||||
GdkDevice *device);
|
||||
GdkDevice * gdk_touch_cluster_get_device (GdkTouchCluster *cluster);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_TOUCH_CLUSTER_H__ */
|
||||
+12
-1
@@ -350,6 +350,8 @@ typedef enum
|
||||
* @GDK_SUBSTRUCTURE_MASK: receive events about window configuration changes of
|
||||
* child windows
|
||||
* @GDK_SCROLL_MASK: receive scroll events
|
||||
* @GDK_TOUCH_MASK: receive (multi)touch events
|
||||
* @GDK_SMOOTH_SCROLL_MASK: receive smooth scrolling events
|
||||
* @GDK_ALL_EVENTS_MASK: the combination of all the above event masks.
|
||||
*
|
||||
* A set of bit-flags to indicate which events a window is to receive.
|
||||
@@ -365,6 +367,13 @@ typedef enum
|
||||
* some of which are marked as a hint (the is_hint member is %TRUE).
|
||||
* To receive more motion events after a motion hint event, the application
|
||||
* needs to asks for more, by calling gdk_event_request_motions().
|
||||
*
|
||||
* If %GDK_TOUCH_MASK is enabled, the window will receive (multi)touch events
|
||||
* from touch-enabled devices. Those will come as sequences #GdkEventMotion
|
||||
* with type %GDK_TOUCH_MOTION, enclosed by 2 #GdkEventButton events with
|
||||
* type %GDK_TOUCH_PRESS / %GDK_TOUCH_RELEASE. gdk_event_get_touch_id() will
|
||||
* return the touch ID on those events, so different sequences may be
|
||||
* distinguished.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
@@ -389,7 +398,9 @@ typedef enum
|
||||
GDK_PROXIMITY_OUT_MASK = 1 << 19,
|
||||
GDK_SUBSTRUCTURE_MASK = 1 << 20,
|
||||
GDK_SCROLL_MASK = 1 << 21,
|
||||
GDK_ALL_EVENTS_MASK = 0x3FFFFE
|
||||
GDK_TOUCH_MASK = 1 << 22,
|
||||
GDK_SMOOTH_SCROLL_MASK = 1 << 23,
|
||||
GDK_ALL_EVENTS_MASK = 0x7FFFFF
|
||||
} GdkEventMask;
|
||||
|
||||
/**
|
||||
|
||||
+733
-75
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <gdk/gdktypes.h>
|
||||
#include <gdk/gdkevents.h>
|
||||
#include <gdk/gdktouchcluster.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -878,6 +879,12 @@ void gdk_window_set_support_multidevice (GdkWindow *window,
|
||||
gboolean support_multidevice);
|
||||
gboolean gdk_window_get_support_multidevice (GdkWindow *window);
|
||||
|
||||
/* Multitouch support */
|
||||
GdkTouchCluster * gdk_window_create_touch_cluster (GdkWindow *window,
|
||||
GdkDevice *device);
|
||||
void gdk_window_remove_touch_cluster (GdkWindow *window,
|
||||
GdkTouchCluster *cluster);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_WINDOW_H__ */
|
||||
|
||||
@@ -870,6 +870,8 @@ fill_scroll_event (GdkWindow *window,
|
||||
gint y,
|
||||
gint x_root,
|
||||
gint y_root,
|
||||
gdouble delta_x,
|
||||
gdouble delta_y,
|
||||
GdkScrollDirection direction)
|
||||
{
|
||||
NSPoint point;
|
||||
@@ -886,6 +888,8 @@ fill_scroll_event (GdkWindow *window,
|
||||
event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent);
|
||||
event->scroll.direction = direction;
|
||||
event->scroll.device = _gdk_display->core_pointer;
|
||||
event->scroll.delta_x = delta_x;
|
||||
event->scroll.delta_y = delta_y;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1320,28 +1324,64 @@ gdk_event_translate (GdkEvent *event,
|
||||
|
||||
case NSScrollWheel:
|
||||
{
|
||||
float dx = [nsevent deltaX];
|
||||
float dy = [nsevent deltaY];
|
||||
GdkScrollDirection direction;
|
||||
GdkScrollDirection direction;
|
||||
float dx;
|
||||
float dy;
|
||||
|
||||
if (dy != 0)
|
||||
if (gdk_quartz_osx_version() >= GDK_OSX_LION &&
|
||||
[nsevent hasPreciseScrollingDeltas])
|
||||
{
|
||||
dx = [nsevent scrollingDeltaX];
|
||||
dy = [nsevent scrollingDeltaY];
|
||||
direction = GDK_SCROLL_SMOOTH;
|
||||
|
||||
fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
|
||||
-dx, -dy, direction);
|
||||
|
||||
/* Fall through for scroll buttons emulation */
|
||||
}
|
||||
|
||||
dx = [nsevent deltaX];
|
||||
dy = [nsevent deltaY];
|
||||
|
||||
if (dy != 0.0)
|
||||
{
|
||||
if (dy < 0.0)
|
||||
direction = GDK_SCROLL_DOWN;
|
||||
else
|
||||
direction = GDK_SCROLL_UP;
|
||||
|
||||
fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
|
||||
dy = fabs (dy);
|
||||
dx = 0.0;
|
||||
}
|
||||
|
||||
if (dx != 0)
|
||||
else if (dx != 0.0)
|
||||
{
|
||||
if (dx < 0.0)
|
||||
direction = GDK_SCROLL_RIGHT;
|
||||
else
|
||||
direction = GDK_SCROLL_LEFT;
|
||||
|
||||
fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
|
||||
dx = fabs (dx);
|
||||
dy = 0.0;
|
||||
}
|
||||
|
||||
if (dx != 0.0 || dy != 0.0)
|
||||
{
|
||||
if ([nsevent hasPreciseScrollingDeltas])
|
||||
{
|
||||
GdkEvent *emulated_event;
|
||||
|
||||
emulated_event = gdk_event_new (GDK_SCROLL);
|
||||
_gdk_event_set_pointer_emulated (emulated_event, TRUE);
|
||||
fill_scroll_event (window, emulated_event, nsevent,
|
||||
x, y, x_root, y_root,
|
||||
dx, dy, direction);
|
||||
append_event (emulated_event, TRUE);
|
||||
}
|
||||
else
|
||||
fill_scroll_event (window, event, nsevent,
|
||||
x, y, x_root, y_root,
|
||||
dx, dy, direction);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -7,6 +7,8 @@ libgdkx11includedir = $(includedir)/gtk-3.0/gdk/x11
|
||||
AM_CPPFLAGS = \
|
||||
-DG_LOG_DOMAIN=\"Gdk\" \
|
||||
-DGDK_COMPILATION \
|
||||
-DXINPUT2_2_USE_UNSTABLE_PROTOCOL \
|
||||
-DXINPUT2_1_USE_UNSTABLE_PROTOCOL \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/gdk \
|
||||
-I$(top_builddir)/gdk \
|
||||
|
||||
+130
-5
@@ -35,11 +35,21 @@
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct _ScrollValuator ScrollValuator;
|
||||
|
||||
struct _ScrollValuator
|
||||
{
|
||||
guint n_valuator : 4;
|
||||
guint direction : 4;
|
||||
gdouble last_value;
|
||||
};
|
||||
|
||||
struct _GdkX11DeviceXI2
|
||||
{
|
||||
GdkDevice parent_instance;
|
||||
|
||||
gint device_id;
|
||||
GArray *scroll_valuators;
|
||||
};
|
||||
|
||||
struct _GdkX11DeviceXI2Class
|
||||
@@ -51,6 +61,7 @@ G_DEFINE_TYPE (GdkX11DeviceXI2, gdk_x11_device_xi2, GDK_TYPE_DEVICE)
|
||||
|
||||
#ifdef XINPUT_2
|
||||
|
||||
static void gdk_x11_device_xi2_finalize (GObject *object);
|
||||
static void gdk_x11_device_xi2_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
@@ -112,6 +123,7 @@ gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
|
||||
|
||||
object_class->finalize = gdk_x11_device_xi2_finalize;
|
||||
object_class->get_property = gdk_x11_device_xi2_get_property;
|
||||
object_class->set_property = gdk_x11_device_xi2_set_property;
|
||||
|
||||
@@ -136,6 +148,17 @@ gdk_x11_device_xi2_class_init (GdkX11DeviceXI2Class *klass)
|
||||
static void
|
||||
gdk_x11_device_xi2_init (GdkX11DeviceXI2 *device)
|
||||
{
|
||||
device->scroll_valuators = g_array_new (FALSE, FALSE, sizeof (ScrollValuator));
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_device_xi2_finalize (GObject *object)
|
||||
{
|
||||
GdkX11DeviceXI2 *device = GDK_X11_DEVICE_XI2 (object);
|
||||
|
||||
g_array_free (device->scroll_valuators, TRUE);
|
||||
|
||||
G_OBJECT_CLASS (gdk_x11_device_xi2_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -388,6 +411,7 @@ gdk_x11_device_xi2_grab (GdkDevice *device,
|
||||
guint32 time_)
|
||||
{
|
||||
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
|
||||
GdkX11DeviceManagerXI2 *device_manager_xi2;
|
||||
GdkDisplay *display;
|
||||
XIEventMask mask;
|
||||
Window xwindow;
|
||||
@@ -395,6 +419,7 @@ gdk_x11_device_xi2_grab (GdkDevice *device,
|
||||
gint status;
|
||||
|
||||
display = gdk_device_get_display (device);
|
||||
device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
|
||||
|
||||
/* FIXME: confine_to is actually unused */
|
||||
|
||||
@@ -409,7 +434,9 @@ gdk_x11_device_xi2_grab (GdkDevice *device,
|
||||
}
|
||||
|
||||
mask.deviceid = device_xi2->device_id;
|
||||
mask.mask = _gdk_x11_device_xi2_translate_event_mask (event_mask, &mask.mask_len);
|
||||
mask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
|
||||
event_mask,
|
||||
&mask.mask_len);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (_gdk_debug_flags & GDK_DEBUG_NOGRABS)
|
||||
@@ -625,10 +652,17 @@ gdk_x11_device_xi2_select_window_events (GdkDevice *device,
|
||||
GdkEventMask event_mask)
|
||||
{
|
||||
GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
|
||||
GdkX11DeviceManagerXI2 *device_manager_xi2;
|
||||
GdkDisplay *display;
|
||||
XIEventMask evmask;
|
||||
|
||||
display = gdk_device_get_display (device);
|
||||
device_manager_xi2 = GDK_X11_DEVICE_MANAGER_XI2 (gdk_display_get_device_manager (display));
|
||||
|
||||
evmask.deviceid = device_xi2->device_id;
|
||||
evmask.mask = _gdk_x11_device_xi2_translate_event_mask (event_mask, &evmask.mask_len);
|
||||
evmask.mask = _gdk_x11_device_xi2_translate_event_mask (device_manager_xi2,
|
||||
event_mask,
|
||||
&evmask.mask_len);
|
||||
|
||||
XISelectEvents (GDK_WINDOW_XDISPLAY (window),
|
||||
GDK_WINDOW_XID (window),
|
||||
@@ -638,10 +672,14 @@ gdk_x11_device_xi2_select_window_events (GdkDevice *device,
|
||||
}
|
||||
|
||||
guchar *
|
||||
_gdk_x11_device_xi2_translate_event_mask (GdkEventMask event_mask,
|
||||
gint *len)
|
||||
_gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
|
||||
GdkEventMask event_mask,
|
||||
gint *len)
|
||||
{
|
||||
guchar *mask;
|
||||
gint minor;
|
||||
|
||||
g_object_get (device_manager_xi2, "minor", &minor, NULL);
|
||||
|
||||
*len = XIMaskLen (XI_LASTEVENT);
|
||||
mask = g_new0 (guchar, *len);
|
||||
@@ -690,6 +728,17 @@ _gdk_x11_device_xi2_translate_event_mask (GdkEventMask event_mask,
|
||||
XISetMask (mask, XI_FocusOut);
|
||||
}
|
||||
|
||||
#ifdef XINPUT_2_2
|
||||
/* XInput 2.2 includes multitouch support */
|
||||
if (minor >= 2 &&
|
||||
event_mask & GDK_TOUCH_MASK)
|
||||
{
|
||||
XISetMask (mask, XI_TouchBegin);
|
||||
XISetMask (mask, XI_TouchUpdate);
|
||||
XISetMask (mask, XI_TouchEnd);
|
||||
}
|
||||
#endif /* XINPUT_2_2 */
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
@@ -742,7 +791,7 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
|
||||
{
|
||||
gint group;
|
||||
|
||||
group = group_state->base + group_state->latched + group_state->locked;
|
||||
group = group_state->base | group_state->latched | group_state->locked;
|
||||
|
||||
/* FIXME: do we need the XKB complications for this ? */
|
||||
group = CLAMP(group, 0, 3);
|
||||
@@ -753,6 +802,82 @@ _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
|
||||
return state;
|
||||
}
|
||||
|
||||
void
|
||||
_gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2 *device,
|
||||
guint n_valuator,
|
||||
GdkScrollDirection direction,
|
||||
gdouble current_value)
|
||||
{
|
||||
ScrollValuator scroll;
|
||||
|
||||
g_return_if_fail (GDK_IS_X11_DEVICE_XI2 (device));
|
||||
g_return_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)));
|
||||
|
||||
scroll.n_valuator = n_valuator;
|
||||
scroll.direction = direction;
|
||||
scroll.last_value = current_value;
|
||||
|
||||
g_array_append_val (device->scroll_valuators, scroll);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gdk_x11_device_xi2_is_scroll_valuator (GdkX11DeviceXI2 *device,
|
||||
guint n_valuator,
|
||||
GdkScrollDirection *direction)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), FALSE);
|
||||
g_return_val_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)), FALSE);
|
||||
|
||||
for (i = 0; i < device->scroll_valuators->len; i++)
|
||||
{
|
||||
ScrollValuator *scroll;
|
||||
|
||||
scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
|
||||
|
||||
if (scroll->n_valuator == n_valuator)
|
||||
{
|
||||
if (*direction)
|
||||
*direction = scroll->direction;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gdouble
|
||||
_gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2 *device,
|
||||
guint n_valuator,
|
||||
gdouble valuator_value)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_X11_DEVICE_XI2 (device), 0);
|
||||
g_return_val_if_fail (n_valuator < gdk_device_get_n_axes (GDK_DEVICE (device)), 0);
|
||||
|
||||
for (i = 0; i < device->scroll_valuators->len; i++)
|
||||
{
|
||||
ScrollValuator *scroll;
|
||||
|
||||
scroll = &g_array_index (device->scroll_valuators, ScrollValuator, i);
|
||||
|
||||
if (scroll->n_valuator == n_valuator)
|
||||
{
|
||||
gdouble delta;
|
||||
|
||||
delta = valuator_value - scroll->last_value;
|
||||
scroll->last_value = valuator_value;
|
||||
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint
|
||||
_gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device)
|
||||
{
|
||||
|
||||
@@ -471,6 +471,9 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
|
||||
event->scroll.state = (GdkModifierType) xevent->xbutton.state;
|
||||
event->scroll.device = device_manager->core_pointer;
|
||||
|
||||
event->scroll.delta_x = 0;
|
||||
event->scroll.delta_y = 0;
|
||||
|
||||
if (!set_screen_from_root (display, event, xevent->xbutton.root))
|
||||
{
|
||||
return_val = FALSE;
|
||||
|
||||
@@ -54,7 +54,11 @@ _gdk_x11_device_manager_new (GdkDisplay *display)
|
||||
int major, minor;
|
||||
|
||||
major = 2;
|
||||
#ifdef XINPUT_2_2
|
||||
minor = 2;
|
||||
#else
|
||||
minor = 0;
|
||||
#endif /* XINPUT_2_2 */
|
||||
|
||||
if (!_gdk_disable_multidevice &&
|
||||
XIQueryVersion (xdisplay, &major, &minor) != BadRequest)
|
||||
@@ -66,6 +70,8 @@ _gdk_x11_device_manager_new (GdkDisplay *display)
|
||||
device_manager_xi2 = g_object_new (GDK_TYPE_X11_DEVICE_MANAGER_XI2,
|
||||
"display", display,
|
||||
"opcode", opcode,
|
||||
"major", major,
|
||||
"minor", minor,
|
||||
NULL);
|
||||
|
||||
return GDK_DEVICE_MANAGER (device_manager_xi2);
|
||||
|
||||
+266
-63
@@ -29,6 +29,7 @@
|
||||
#include "gdkprivate-x11.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkkeysyms.h"
|
||||
#include "gdkinternals.h"
|
||||
|
||||
#ifdef XINPUT_2
|
||||
|
||||
@@ -49,6 +50,8 @@ struct _GdkX11DeviceManagerXI2
|
||||
GList *devices;
|
||||
|
||||
gint opcode;
|
||||
gint major;
|
||||
gint minor;
|
||||
};
|
||||
|
||||
struct _GdkX11DeviceManagerXI2Class
|
||||
@@ -96,7 +99,9 @@ static GdkWindow * gdk_x11_device_manager_xi2_get_window (GdkEventTra
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_OPCODE
|
||||
PROP_OPCODE,
|
||||
PROP_MAJOR,
|
||||
PROP_MINOR
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -120,6 +125,20 @@ gdk_x11_device_manager_xi2_class_init (GdkX11DeviceManagerXI2Class *klass)
|
||||
P_("Opcode for XInput2 requests"),
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_MAJOR,
|
||||
g_param_spec_int ("major",
|
||||
P_("Major"),
|
||||
P_("Major version number"),
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_MINOR,
|
||||
g_param_spec_int ("minor",
|
||||
P_("Minor"),
|
||||
P_("Minor version number"),
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -148,8 +167,10 @@ _gdk_x11_device_manager_xi2_select_events (GdkDeviceManager *device_manager,
|
||||
static void
|
||||
translate_valuator_class (GdkDisplay *display,
|
||||
GdkDevice *device,
|
||||
XIValuatorClassInfo *info,
|
||||
gint n_valuator)
|
||||
Atom valuator_label,
|
||||
gdouble min,
|
||||
gdouble max,
|
||||
gdouble resolution)
|
||||
{
|
||||
static gboolean initialized = FALSE;
|
||||
static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
|
||||
@@ -170,24 +191,19 @@ translate_valuator_class (GdkDisplay *display,
|
||||
|
||||
for (i = GDK_AXIS_IGNORE; i < GDK_AXIS_LAST; i++)
|
||||
{
|
||||
if (label_atoms[i] == info->label)
|
||||
if (label_atoms[i] == valuator_label)
|
||||
{
|
||||
use = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->label != None)
|
||||
label = gdk_x11_xatom_to_atom_for_display (display, info->label);
|
||||
if (valuator_label != None)
|
||||
label = gdk_x11_xatom_to_atom_for_display (display, valuator_label);
|
||||
else
|
||||
label = GDK_NONE;
|
||||
|
||||
_gdk_device_add_axis (device,
|
||||
label,
|
||||
use,
|
||||
info->min,
|
||||
info->max,
|
||||
info->resolution);
|
||||
_gdk_device_add_axis (device, label, use, min, max, resolution);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -196,7 +212,7 @@ translate_device_classes (GdkDisplay *display,
|
||||
XIAnyClassInfo **classes,
|
||||
guint n_classes)
|
||||
{
|
||||
gint i, n_valuator = 0;
|
||||
gint i;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (device));
|
||||
|
||||
@@ -218,11 +234,41 @@ translate_device_classes (GdkDisplay *display,
|
||||
}
|
||||
break;
|
||||
case XIValuatorClass:
|
||||
translate_valuator_class (display, device,
|
||||
(XIValuatorClassInfo *) class_info,
|
||||
n_valuator);
|
||||
n_valuator++;
|
||||
{
|
||||
XIValuatorClassInfo *valuator_info = (XIValuatorClassInfo *) class_info;
|
||||
translate_valuator_class (display, device,
|
||||
valuator_info->label,
|
||||
valuator_info->min,
|
||||
valuator_info->max,
|
||||
valuator_info->resolution);
|
||||
}
|
||||
break;
|
||||
#ifdef XINPUT_2_2
|
||||
case XIScrollClass:
|
||||
{
|
||||
XIScrollClassInfo *scroll_info = (XIScrollClassInfo *) class_info;
|
||||
XIValuatorClassInfo *scroll_valuator_info = NULL;
|
||||
GdkScrollDirection direction;
|
||||
gint j;
|
||||
|
||||
for (j = 0; j < n_classes; j++)
|
||||
{
|
||||
if (classes[j]->type == XIValuatorClass &&
|
||||
((XIValuatorClassInfo *) classes[j])->number == scroll_info->number)
|
||||
scroll_valuator_info = (XIValuatorClassInfo *) classes[j];
|
||||
}
|
||||
|
||||
if (scroll_info->scroll_type == XIScrollTypeVertical)
|
||||
direction = GDK_SCROLL_DOWN;
|
||||
else
|
||||
direction = GDK_SCROLL_RIGHT;
|
||||
|
||||
_gdk_x11_device_xi2_add_scroll_valuator (GDK_X11_DEVICE_XI2 (device),
|
||||
scroll_info->number,
|
||||
direction,
|
||||
scroll_valuator_info->value);
|
||||
}
|
||||
#endif /* XINPUT_2_2 */
|
||||
default:
|
||||
/* Ignore */
|
||||
break;
|
||||
@@ -232,6 +278,27 @@ translate_device_classes (GdkDisplay *display,
|
||||
g_object_thaw_notify (G_OBJECT (device));
|
||||
}
|
||||
|
||||
static gint
|
||||
count_device_touches (XIAnyClassInfo **classes,
|
||||
guint n_classes)
|
||||
{
|
||||
#ifdef XINPUT_2_2
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < n_classes; i++)
|
||||
{
|
||||
XITouchClassInfo *valuator_info = (XITouchClassInfo *) classes[i];
|
||||
|
||||
if (valuator_info->type != XITouchClass)
|
||||
continue;
|
||||
|
||||
return valuator_info->num_touches;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GdkDevice *
|
||||
create_device (GdkDeviceManager *device_manager,
|
||||
GdkDisplay *display,
|
||||
@@ -244,6 +311,9 @@ create_device (GdkDeviceManager *device_manager,
|
||||
|
||||
if (dev->use == XIMasterKeyboard || dev->use == XISlaveKeyboard)
|
||||
input_source = GDK_SOURCE_KEYBOARD;
|
||||
else if (dev->use == XISlavePointer &&
|
||||
count_device_touches (dev->classes, dev->num_classes) > 0)
|
||||
input_source = GDK_SOURCE_TOUCH;
|
||||
else
|
||||
{
|
||||
gchar *tmp_name;
|
||||
@@ -254,6 +324,10 @@ create_device (GdkDeviceManager *device_manager,
|
||||
input_source = GDK_SOURCE_ERASER;
|
||||
else if (strstr (tmp_name, "cursor"))
|
||||
input_source = GDK_SOURCE_CURSOR;
|
||||
else if (strstr (tmp_name, "finger") ||
|
||||
(strstr (tmp_name, "touch") &&
|
||||
!strstr (tmp_name, "touchpad")))
|
||||
input_source = GDK_SOURCE_TOUCH;
|
||||
else if (strstr (tmp_name, "wacom") ||
|
||||
strstr (tmp_name, "pen"))
|
||||
input_source = GDK_SOURCE_PEN;
|
||||
@@ -408,6 +482,8 @@ gdk_x11_device_manager_xi2_constructed (GObject *object)
|
||||
display = gdk_device_manager_get_display (GDK_DEVICE_MANAGER (object));
|
||||
xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
||||
|
||||
g_assert (device_manager->major == 2);
|
||||
|
||||
masters = g_hash_table_new (NULL, NULL);
|
||||
slaves = g_hash_table_new (NULL, NULL);
|
||||
|
||||
@@ -533,6 +609,12 @@ gdk_x11_device_manager_xi2_set_property (GObject *object,
|
||||
case PROP_OPCODE:
|
||||
device_manager->opcode = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_MAJOR:
|
||||
device_manager->major = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_MINOR:
|
||||
device_manager->minor = g_value_get_int (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -554,6 +636,12 @@ gdk_x11_device_manager_xi2_get_property (GObject *object,
|
||||
case PROP_OPCODE:
|
||||
g_value_set_int (value, device_manager->opcode);
|
||||
break;
|
||||
case PROP_MAJOR:
|
||||
g_value_set_int (value, device_manager->major);
|
||||
break;
|
||||
case PROP_MINOR:
|
||||
g_value_set_int (value, device_manager->minor);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -823,6 +911,11 @@ get_event_window (GdkEventTranslator *translator,
|
||||
case XI_ButtonPress:
|
||||
case XI_ButtonRelease:
|
||||
case XI_Motion:
|
||||
#ifdef XINPUT_2_2
|
||||
case XI_TouchUpdate:
|
||||
case XI_TouchBegin:
|
||||
case XI_TouchEnd:
|
||||
#endif /* XINPUT_2_2 */
|
||||
{
|
||||
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
|
||||
|
||||
@@ -941,6 +1034,47 @@ gdk_x11_device_manager_xi2_translate_core_event (GdkEventTranslator *translator,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
scroll_valuators_changed (GdkX11DeviceXI2 *device,
|
||||
XIValuatorState *valuators,
|
||||
gdouble *dx,
|
||||
gdouble *dy)
|
||||
{
|
||||
gdouble has_scroll_valuators = FALSE;
|
||||
GdkScrollDirection direction;
|
||||
guint n_axes, i, n_val;
|
||||
gdouble *vals;
|
||||
|
||||
n_axes = gdk_device_get_n_axes (GDK_DEVICE (device));
|
||||
vals = valuators->values;
|
||||
*dx = *dy = 0;
|
||||
n_val = 0;
|
||||
|
||||
for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++)
|
||||
{
|
||||
if (!XIMaskIsSet (valuators->mask, i))
|
||||
continue;
|
||||
|
||||
if (_gdk_x11_device_xi2_is_scroll_valuator (device, i, &direction))
|
||||
{
|
||||
gdouble delta;
|
||||
|
||||
has_scroll_valuators = TRUE;
|
||||
delta = _gdk_x11_device_xi2_get_scroll_delta (device, i, vals[n_val]);
|
||||
|
||||
if (direction == GDK_SCROLL_UP ||
|
||||
direction == GDK_SCROLL_DOWN)
|
||||
*dy = delta;
|
||||
else
|
||||
*dx = delta;
|
||||
}
|
||||
|
||||
n_val++;
|
||||
}
|
||||
|
||||
return has_scroll_valuators;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
GdkDisplay *display,
|
||||
@@ -1043,56 +1177,60 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
break;
|
||||
case XI_ButtonPress:
|
||||
case XI_ButtonRelease:
|
||||
#ifdef XINPUT_2_2
|
||||
case XI_TouchBegin:
|
||||
case XI_TouchEnd:
|
||||
#endif /* XINPUT_2_2 */
|
||||
{
|
||||
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
|
||||
GdkDevice *source_device;
|
||||
|
||||
switch (xev->detail)
|
||||
if (ev->evtype == XI_ButtonPress &&
|
||||
(xev->detail >= 4 && xev->detail <= 7))
|
||||
{
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
/* Button presses of button 4-7 are scroll events */
|
||||
if (ev->evtype == XI_ButtonPress)
|
||||
{
|
||||
event->scroll.type = GDK_SCROLL;
|
||||
/* Button presses of button 4-7 are scroll events */
|
||||
event->scroll.type = GDK_SCROLL;
|
||||
|
||||
if (xev->detail == 4)
|
||||
event->scroll.direction = GDK_SCROLL_UP;
|
||||
else if (xev->detail == 5)
|
||||
event->scroll.direction = GDK_SCROLL_DOWN;
|
||||
else if (xev->detail == 6)
|
||||
event->scroll.direction = GDK_SCROLL_LEFT;
|
||||
else
|
||||
event->scroll.direction = GDK_SCROLL_RIGHT;
|
||||
if (xev->detail == 4)
|
||||
event->scroll.direction = GDK_SCROLL_UP;
|
||||
else if (xev->detail == 5)
|
||||
event->scroll.direction = GDK_SCROLL_DOWN;
|
||||
else if (xev->detail == 6)
|
||||
event->scroll.direction = GDK_SCROLL_LEFT;
|
||||
else
|
||||
event->scroll.direction = GDK_SCROLL_RIGHT;
|
||||
|
||||
event->scroll.window = window;
|
||||
event->scroll.time = xev->time;
|
||||
event->scroll.x = (gdouble) xev->event_x;
|
||||
event->scroll.y = (gdouble) xev->event_y;
|
||||
event->scroll.x_root = (gdouble) xev->root_x;
|
||||
event->scroll.y_root = (gdouble) xev->root_y;
|
||||
event->scroll.window = window;
|
||||
event->scroll.time = xev->time;
|
||||
event->scroll.x = (gdouble) xev->event_x;
|
||||
event->scroll.y = (gdouble) xev->event_y;
|
||||
event->scroll.x_root = (gdouble) xev->root_x;
|
||||
event->scroll.y_root = (gdouble) xev->root_y;
|
||||
event->scroll.delta_x = 0;
|
||||
event->scroll.delta_y = 0;
|
||||
|
||||
event->scroll.device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->deviceid));
|
||||
event->scroll.device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->deviceid));
|
||||
|
||||
source_device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->sourceid));
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
source_device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->sourceid));
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
|
||||
event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
break;
|
||||
}
|
||||
/* Button presses of button 4-7 are scroll events, so ignore the release */
|
||||
else if (ev->evtype == XI_ButtonRelease)
|
||||
{
|
||||
return_val = FALSE;
|
||||
break;
|
||||
}
|
||||
/* else (XI_ButtonRelease) fall thru */
|
||||
default:
|
||||
event->button.type = (ev->evtype == XI_ButtonPress) ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
|
||||
event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
|
||||
if (xev->flags & XIPointerEmulated)
|
||||
_gdk_event_set_pointer_emulated (event, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef XINPUT_2_2
|
||||
if (ev->evtype == XI_TouchBegin)
|
||||
event->button.type = GDK_TOUCH_PRESS;
|
||||
else if (ev->evtype == XI_TouchEnd)
|
||||
event->button.type = GDK_TOUCH_RELEASE;
|
||||
else
|
||||
#endif /* XINPUT_2_2 */
|
||||
event->button.type = (ev->evtype == XI_ButtonPress) ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
|
||||
|
||||
event->button.window = window;
|
||||
event->button.time = xev->time;
|
||||
@@ -1124,9 +1262,25 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
}
|
||||
|
||||
event->button.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
event->button.button = xev->detail;
|
||||
|
||||
if (ev->evtype == XI_TouchBegin)
|
||||
event->button.state |= GDK_BUTTON1_MASK;
|
||||
|
||||
#ifdef XINPUT_2_2
|
||||
if (ev->evtype == XI_TouchBegin ||
|
||||
ev->evtype == XI_TouchEnd)
|
||||
{
|
||||
event->button.button = 1;
|
||||
event->button.touch_id = xev->detail;
|
||||
}
|
||||
else
|
||||
#endif /* XINPUT_2_2 */
|
||||
event->button.button = xev->detail;
|
||||
}
|
||||
|
||||
if (xev->flags & (XIPointerEmulated | XITouchEmulatingPointer))
|
||||
_gdk_event_set_pointer_emulated (event, TRUE);
|
||||
|
||||
if (return_val == FALSE)
|
||||
break;
|
||||
|
||||
@@ -1142,11 +1296,53 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
break;
|
||||
}
|
||||
case XI_Motion:
|
||||
#ifdef XINPUT_2_2
|
||||
case XI_TouchUpdate:
|
||||
#endif /* XINPUT_2_2 */
|
||||
{
|
||||
XIDeviceEvent *xev = (XIDeviceEvent *) ev;
|
||||
GdkDevice *source_device;
|
||||
gdouble delta_x, delta_y;
|
||||
|
||||
event->motion.type = GDK_MOTION_NOTIFY;
|
||||
source_device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->sourceid));
|
||||
|
||||
if (scroll_valuators_changed (GDK_X11_DEVICE_XI2 (source_device),
|
||||
&xev->valuators, &delta_x, &delta_y))
|
||||
{
|
||||
event->scroll.type = GDK_SCROLL;
|
||||
event->scroll.direction = GDK_SCROLL_SMOOTH;
|
||||
|
||||
event->scroll.window = window;
|
||||
event->scroll.time = xev->time;
|
||||
event->scroll.x = (gdouble) xev->event_x;
|
||||
event->scroll.y = (gdouble) xev->event_y;
|
||||
event->scroll.x_root = (gdouble) xev->root_x;
|
||||
event->scroll.y_root = (gdouble) xev->root_y;
|
||||
event->scroll.delta_x = delta_x;
|
||||
event->scroll.delta_y = delta_y;
|
||||
|
||||
event->scroll.device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->deviceid));
|
||||
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
|
||||
event->scroll.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ev->evtype == XI_Motion)
|
||||
{
|
||||
event->motion.touch_id = 0;
|
||||
event->motion.type = GDK_MOTION_NOTIFY;
|
||||
}
|
||||
#ifdef XINPUT_2_2
|
||||
else
|
||||
{
|
||||
event->motion.touch_id = xev->detail;
|
||||
event->motion.type = GDK_TOUCH_MOTION;
|
||||
}
|
||||
#endif
|
||||
|
||||
event->motion.window = window;
|
||||
|
||||
@@ -1159,12 +1355,16 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
event->motion.device = g_hash_table_lookup (device_manager->id_table,
|
||||
GINT_TO_POINTER (xev->deviceid));
|
||||
|
||||
source_device = g_hash_table_lookup (device_manager->id_table,
|
||||
GUINT_TO_POINTER (xev->sourceid));
|
||||
gdk_event_set_source_device (event, source_device);
|
||||
|
||||
event->motion.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
|
||||
|
||||
if (ev->evtype == XI_TouchUpdate)
|
||||
event->motion.state |= GDK_BUTTON1_MASK;
|
||||
|
||||
if (xev->flags & (XIPointerEmulated | XITouchEmulatingPointer))
|
||||
_gdk_event_set_pointer_emulated (event, TRUE);
|
||||
|
||||
/* There doesn't seem to be motion hints in XI */
|
||||
event->motion.is_hint = FALSE;
|
||||
|
||||
@@ -1280,7 +1480,8 @@ gdk_x11_device_manager_xi2_get_handled_events (GdkEventTranslator *translator)
|
||||
GDK_BUTTON2_MOTION_MASK |
|
||||
GDK_BUTTON3_MOTION_MASK |
|
||||
GDK_BUTTON_MOTION_MASK |
|
||||
GDK_FOCUS_CHANGE_MASK);
|
||||
GDK_FOCUS_CHANGE_MASK |
|
||||
GDK_TOUCH_MASK);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1294,7 +1495,9 @@ gdk_x11_device_manager_xi2_select_window_events (GdkEventTranslator *translator,
|
||||
device_manager = GDK_DEVICE_MANAGER (translator);
|
||||
|
||||
event_mask.deviceid = XIAllMasterDevices;
|
||||
event_mask.mask = _gdk_x11_device_xi2_translate_event_mask (evmask, &event_mask.mask_len);
|
||||
event_mask.mask = _gdk_x11_device_xi2_translate_event_mask (GDK_X11_DEVICE_MANAGER_XI2 (device_manager),
|
||||
evmask,
|
||||
&event_mask.mask_len);
|
||||
|
||||
_gdk_x11_device_manager_xi2_select_events (device_manager, window, &event_mask);
|
||||
g_free (event_mask.mask);
|
||||
|
||||
@@ -1579,9 +1579,12 @@ device_grab_update_callback (GdkDisplay *display,
|
||||
gpointer data,
|
||||
gulong serial)
|
||||
{
|
||||
GdkPointerWindowInfo *pointer_info;
|
||||
GdkDevice *device = data;
|
||||
|
||||
_gdk_display_device_grab_update (display, device, NULL, serial);
|
||||
pointer_info = _gdk_display_get_pointer_info (display, device);
|
||||
_gdk_display_device_grab_update (display, device,
|
||||
pointer_info->last_slave, serial);
|
||||
}
|
||||
|
||||
#define XSERVER_TIME_IS_LATER(time1, time2) \
|
||||
|
||||
@@ -247,8 +247,9 @@ void _gdk_x11_device_xi_translate_axes (GdkDevice *device,
|
||||
#endif
|
||||
|
||||
#ifdef XINPUT_2
|
||||
guchar * _gdk_x11_device_xi2_translate_event_mask (GdkEventMask event_mask,
|
||||
gint *len);
|
||||
guchar * _gdk_x11_device_xi2_translate_event_mask (GdkX11DeviceManagerXI2 *device_manager_xi2,
|
||||
GdkEventMask event_mask,
|
||||
gint *len);
|
||||
guint _gdk_x11_device_xi2_translate_state (XIModifierState *mods_state,
|
||||
XIButtonState *buttons_state,
|
||||
XIGroupState *group_state);
|
||||
@@ -256,6 +257,16 @@ gint _gdk_x11_device_xi2_get_id (GdkX11DeviceXI2 *device);
|
||||
|
||||
GdkDevice * _gdk_x11_device_manager_xi2_lookup (GdkX11DeviceManagerXI2 *device_manager_xi2,
|
||||
gint device_id);
|
||||
void _gdk_x11_device_xi2_add_scroll_valuator (GdkX11DeviceXI2 *device,
|
||||
guint n_valuator,
|
||||
GdkScrollDirection direction,
|
||||
gdouble current_value);
|
||||
gboolean _gdk_x11_device_xi2_is_scroll_valuator (GdkX11DeviceXI2 *device,
|
||||
guint n_valuator,
|
||||
GdkScrollDirection *direction);
|
||||
gdouble _gdk_x11_device_xi2_get_scroll_delta (GdkX11DeviceXI2 *device,
|
||||
guint n_valuator,
|
||||
gdouble valuator_value);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+29
-9
@@ -145,6 +145,8 @@ endif
|
||||
# by configure)
|
||||
|
||||
deprecated_h_sources = \
|
||||
deprecated/gtkcolorsel.h \
|
||||
deprecated/gtkcolorseldialog.h \
|
||||
deprecated/gtkfontsel.h \
|
||||
deprecated/gtkhandlebox.h \
|
||||
deprecated/gtkhbbox.h \
|
||||
@@ -153,6 +155,7 @@ deprecated_h_sources = \
|
||||
deprecated/gtkhscale.h \
|
||||
deprecated/gtkhscrollbar.h \
|
||||
deprecated/gtkhseparator.h \
|
||||
deprecated/gtkhsv.h \
|
||||
deprecated/gtkstyle.h \
|
||||
deprecated/gtkrc.h \
|
||||
deprecated/gtktable.h \
|
||||
@@ -215,8 +218,10 @@ gtk_public_h_sources = \
|
||||
gtkcheckmenuitem.h \
|
||||
gtkclipboard.h \
|
||||
gtkcolorbutton.h \
|
||||
gtkcolorsel.h \
|
||||
gtkcolorseldialog.h \
|
||||
gtkcolorchooser.h \
|
||||
gtkcolorchooserwidget.h \
|
||||
gtkcolorchooserdialog.h \
|
||||
gtkcolorutils.h \
|
||||
gtkcombobox.h \
|
||||
gtkcomboboxtext.h \
|
||||
gtkcontainer.h \
|
||||
@@ -244,9 +249,9 @@ gtk_public_h_sources = \
|
||||
gtkfontchooserdialog.h \
|
||||
gtkfontchooserwidget.h \
|
||||
gtkframe.h \
|
||||
gtkgesturesinterpreter.h \
|
||||
gtkgradient.h \
|
||||
gtkgrid.h \
|
||||
gtkhsv.h \
|
||||
gtkiconfactory.h \
|
||||
gtkicontheme.h \
|
||||
gtkiconview.h \
|
||||
@@ -410,6 +415,11 @@ gtk_private_h_sources = \
|
||||
gtkbuilderprivate.h \
|
||||
gtkbuttonprivate.h \
|
||||
gtkcellareaboxcontextprivate.h \
|
||||
gtkcolorswatchprivate.h \
|
||||
gtkcoloreditorprivate.h \
|
||||
gtkcolorplaneprivate.h \
|
||||
gtkcolorscaleprivate.h \
|
||||
gtkcolorchooserprivate.h \
|
||||
gtkcontainerprivate.h \
|
||||
gtkcsscomputedvaluesprivate.h \
|
||||
gtkcsscustompropertyprivate.h \
|
||||
@@ -506,6 +516,8 @@ gtk_private_h_sources = \
|
||||
|
||||
# GTK+ C sources to build the library from
|
||||
deprecated_c_sources = \
|
||||
deprecated/gtkcolorsel.c \
|
||||
deprecated/gtkcolorseldialog.c \
|
||||
deprecated/gtkfontsel.c \
|
||||
deprecated/gtkhandlebox.c \
|
||||
deprecated/gtkhbbox.c \
|
||||
@@ -514,6 +526,7 @@ deprecated_c_sources = \
|
||||
deprecated/gtkhscale.c \
|
||||
deprecated/gtkhscrollbar.c \
|
||||
deprecated/gtkhseparator.c \
|
||||
deprecated/gtkhsv.c \
|
||||
deprecated/gtkrc.c \
|
||||
deprecated/gtkstyle.c \
|
||||
deprecated/gtktable.c \
|
||||
@@ -590,8 +603,14 @@ gtk_base_c_sources = \
|
||||
gtkcheckbutton.c \
|
||||
gtkcheckmenuitem.c \
|
||||
gtkcolorbutton.c \
|
||||
gtkcolorsel.c \
|
||||
gtkcolorseldialog.c \
|
||||
gtkcolorchooser.c \
|
||||
gtkcolorchooserwidget.c \
|
||||
gtkcolorchooserdialog.c \
|
||||
gtkcoloreditor.c \
|
||||
gtkcolorplane.c \
|
||||
gtkcolorscale.c \
|
||||
gtkcolorswatch.c \
|
||||
gtkcolorutils.c \
|
||||
gtkcombobox.c \
|
||||
gtkcomboboxtext.c \
|
||||
gtkcontainer.c \
|
||||
@@ -639,9 +658,9 @@ gtk_base_c_sources = \
|
||||
gtkfontchooserutils.c \
|
||||
gtkfontchooserwidget.c \
|
||||
gtkframe.c \
|
||||
gtkgesturesinterpreter.c \
|
||||
gtkgradient.c \
|
||||
gtkgrid.c \
|
||||
gtkhsv.c \
|
||||
gtkiconcache.c \
|
||||
gtkiconcachevalidator.c \
|
||||
gtkiconfactory.c \
|
||||
@@ -1549,7 +1568,6 @@ EXTRA_DIST += \
|
||||
gtkprint-win32.h \
|
||||
gtkprint-win32.c \
|
||||
gtksearchenginequartz.h \
|
||||
gtk.css.raleigh \
|
||||
gtk.gresource.xml \
|
||||
gtk-default.css \
|
||||
gtk-keys.css.default \
|
||||
@@ -1562,10 +1580,12 @@ EXTRA_DIST += \
|
||||
gtktypebuiltins.h.template \
|
||||
gtkprivatetypebuiltins.c.template \
|
||||
gtkprivatetypebuiltins.h.template \
|
||||
org.gtk.Settings.FileChooser.gschema.xml
|
||||
org.gtk.Settings.FileChooser.gschema.xml \
|
||||
org.gtk.Settings.ColorChooser.gschema.xml
|
||||
|
||||
gsettings_SCHEMAS = \
|
||||
org.gtk.Settings.FileChooser.gschema.xml
|
||||
org.gtk.Settings.FileChooser.gschema.xml \
|
||||
org.gtk.Settings.ColorChooser.gschema.xml
|
||||
|
||||
@GSETTINGS_RULES@
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ gail_c_sources = \
|
||||
gtkcellaccessible.c \
|
||||
gtkcellaccessibleparent.c \
|
||||
gtkcheckmenuitemaccessible.c \
|
||||
gtkcolorswatchaccessible.c \
|
||||
gtkcomboboxaccessible.c \
|
||||
gtkcontaineraccessible.c \
|
||||
gtkcontainercellaccessible.c \
|
||||
@@ -59,6 +60,7 @@ gail_private_h_sources = \
|
||||
gtkcellaccessible.h \
|
||||
gtkcellaccessibleparent.h \
|
||||
gtkcheckmenuitemaccessible.h \
|
||||
gtkcolorswatchaccessible.h \
|
||||
gtkcomboboxaccessible.h \
|
||||
gtkcontaineraccessible.h \
|
||||
gtkcontainercellaccessible.h \
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2012 Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtkcolorswatchaccessible.h"
|
||||
|
||||
static void atk_action_interface_init (AtkActionIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkColorSwatchAccessible, _gtk_color_swatch_accessible, GTK_TYPE_WIDGET_ACCESSIBLE,
|
||||
G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init))
|
||||
|
||||
static void
|
||||
_gtk_color_swatch_accessible_class_init (GtkColorSwatchAccessibleClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_gtk_color_swatch_accessible_init (GtkColorSwatchAccessible *scale)
|
||||
{
|
||||
}
|
||||
|
||||
static gint
|
||||
gtk_color_swatch_accessible_get_n_actions (AtkAction *action)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
gtk_color_swatch_accessible_get_keybinding (AtkAction *action,
|
||||
gint i)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
gtk_color_swatch_accessible_get_name (AtkAction *action,
|
||||
gint i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: return "select";
|
||||
case 1: return "activate";
|
||||
case 2: return "customize";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_color_swatch_accessible_do_action (AtkAction *action,
|
||||
gint i)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
|
||||
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (action));
|
||||
if (widget == NULL)
|
||||
return FALSE;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
g_signal_emit_by_name (widget, "activate");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
g_signal_emit_by_name (widget, "customize");
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
atk_action_interface_init (AtkActionIface *iface)
|
||||
{
|
||||
iface->do_action = gtk_color_swatch_accessible_do_action;
|
||||
iface->get_n_actions = gtk_color_swatch_accessible_get_n_actions;
|
||||
iface->get_keybinding = gtk_color_swatch_accessible_get_keybinding;
|
||||
iface->get_name = gtk_color_swatch_accessible_get_name;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2012, Red Hat, Inc
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_COLOR_SWATCH_ACCESSIBLE_H__
|
||||
#define __GTK_COLOR_SWATCH_ACCESSIBLE_H__
|
||||
|
||||
#include "gtkwidgetaccessible.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_COLOR_SWATCH_ACCESSIBLE (_gtk_color_swatch_accessible_get_type ())
|
||||
#define GTK_COLOR_SWATCH_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE, GtkColorSwatchAccessible))
|
||||
#define GTK_COLOR_SWATCH_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE, GtkColorSwatchAccessibleClass))
|
||||
#define GTK_IS_COLOR_SWATCH_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE))
|
||||
#define GTK_IS_COLOR_SWATCH_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE))
|
||||
#define GTK_COLOR_SWATCH_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_SWATCH_ACCESSIBLE, GtkColorSwatchAccessibleClass))
|
||||
|
||||
typedef struct _GtkColorSwatchAccessible GtkColorSwatchAccessible;
|
||||
typedef struct _GtkColorSwatchAccessibleClass GtkColorSwatchAccessibleClass;
|
||||
|
||||
struct _GtkColorSwatchAccessible
|
||||
{
|
||||
GtkWidgetAccessible parent;
|
||||
};
|
||||
|
||||
struct _GtkColorSwatchAccessibleClass
|
||||
{
|
||||
GtkWidgetAccessibleClass parent_class;
|
||||
};
|
||||
|
||||
GType _gtk_color_swatch_accessible_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLOR_SWATCH_ACCESSIBLE_H__ */
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define GDK_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include "gtkcolorsel.h"
|
||||
|
||||
#include <math.h>
|
||||
@@ -37,6 +39,7 @@
|
||||
#include "gtkhsv.h"
|
||||
#include "gtkwindow.h"
|
||||
#include "gtkselection.h"
|
||||
#include "gtkcolorutils.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdrawingarea.h"
|
||||
#include "gtkframe.h"
|
||||
@@ -62,7 +65,7 @@
|
||||
|
||||
/**
|
||||
* SECTION:gtkcolorsel
|
||||
* @Short_description: A widget used to select a color
|
||||
* @Short_description: Deprecated widget used to select a color
|
||||
* @Title: GtkColorSelection
|
||||
*
|
||||
* The #GtkColorSelection is a widget that is used to select
|
||||
@@ -3068,7 +3071,7 @@ gtk_color_selection_palette_to_string (const GdkColor *colors,
|
||||
* tries to modify the palette in a color selection.
|
||||
*
|
||||
* This function should save the new palette contents, and update
|
||||
* the #GtkSettings::gtk-color-palette GtkSettings property so all
|
||||
* the #GtkSettings:gtk-color-palette GtkSettings property so all
|
||||
* GtkColorSelection widgets will be modified.
|
||||
*
|
||||
* Return value: the previous change palette hook (that was replaced)
|
||||
@@ -89,51 +89,67 @@ struct _GtkColorSelectionClass
|
||||
/* ColorSelection */
|
||||
|
||||
GType gtk_color_selection_get_type (void) G_GNUC_CONST;
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_widget_new)
|
||||
GtkWidget *gtk_color_selection_new (void);
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_get_use_alpha)
|
||||
gboolean gtk_color_selection_get_has_opacity_control (GtkColorSelection *colorsel);
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_set_use_alpha)
|
||||
void gtk_color_selection_set_has_opacity_control (GtkColorSelection *colorsel,
|
||||
gboolean has_opacity);
|
||||
GDK_DEPRECATED
|
||||
gboolean gtk_color_selection_get_has_palette (GtkColorSelection *colorsel);
|
||||
GDK_DEPRECATED
|
||||
void gtk_color_selection_set_has_palette (GtkColorSelection *colorsel,
|
||||
gboolean has_palette);
|
||||
|
||||
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_set_rgba)
|
||||
void gtk_color_selection_set_current_alpha (GtkColorSelection *colorsel,
|
||||
guint16 alpha);
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_get_rgba)
|
||||
guint16 gtk_color_selection_get_current_alpha (GtkColorSelection *colorsel);
|
||||
GDK_DEPRECATED
|
||||
void gtk_color_selection_set_previous_alpha (GtkColorSelection *colorsel,
|
||||
guint16 alpha);
|
||||
GDK_DEPRECATED
|
||||
guint16 gtk_color_selection_get_previous_alpha (GtkColorSelection *colorsel);
|
||||
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_set_rgba)
|
||||
void gtk_color_selection_set_current_rgba (GtkColorSelection *colorsel,
|
||||
const GdkRGBA *rgba);
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_get_rgba)
|
||||
void gtk_color_selection_get_current_rgba (GtkColorSelection *colorsel,
|
||||
GdkRGBA *rgba);
|
||||
GDK_DEPRECATED
|
||||
void gtk_color_selection_set_previous_rgba (GtkColorSelection *colorsel,
|
||||
const GdkRGBA *rgba);
|
||||
GDK_DEPRECATED
|
||||
void gtk_color_selection_get_previous_rgba (GtkColorSelection *colorsel,
|
||||
GdkRGBA *rgba);
|
||||
|
||||
GDK_DEPRECATED
|
||||
gboolean gtk_color_selection_is_adjusting (GtkColorSelection *colorsel);
|
||||
|
||||
GDK_DEPRECATED
|
||||
gboolean gtk_color_selection_palette_from_string (const gchar *str,
|
||||
GdkColor **colors,
|
||||
gint *n_colors);
|
||||
GDK_DEPRECATED
|
||||
gchar* gtk_color_selection_palette_to_string (const GdkColor *colors,
|
||||
gint n_colors);
|
||||
|
||||
GtkColorSelectionChangePaletteWithScreenFunc gtk_color_selection_set_change_palette_with_screen_hook (GtkColorSelectionChangePaletteWithScreenFunc func);
|
||||
|
||||
GDK_DEPRECATED_FOR(gtk_color_selection_set_current_rgba)
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_set_rgba)
|
||||
void gtk_color_selection_set_current_color (GtkColorSelection *colorsel,
|
||||
const GdkColor *color);
|
||||
GDK_DEPRECATED_FOR(gtk_color_selection_get_current_rgba)
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_get_rgba)
|
||||
void gtk_color_selection_get_current_color (GtkColorSelection *colorsel,
|
||||
GdkColor *color);
|
||||
GDK_DEPRECATED_FOR(gtk_color_selection_set_previous_rgba)
|
||||
GDK_DEPRECATED
|
||||
void gtk_color_selection_set_previous_color (GtkColorSelection *colorsel,
|
||||
const GdkColor *color);
|
||||
GDK_DEPRECATED_FOR(gtk_color_selection_get_previous_rgba)
|
||||
GDK_DEPRECATED
|
||||
void gtk_color_selection_get_previous_color (GtkColorSelection *colorsel,
|
||||
GdkColor *color);
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#define GDK_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include "gtkcolorseldialog.h"
|
||||
@@ -36,7 +40,7 @@
|
||||
|
||||
/**
|
||||
* SECTION:gtkcolorseldlg
|
||||
* @Short_description: A standard dialog box for selecting a color
|
||||
* @Short_description: Deprecated dialog box for selecting a color
|
||||
* @Title: GtkColorSelectionDialog
|
||||
*
|
||||
* The #GtkColorSelectionDialog provides a standard dialog which
|
||||
@@ -32,7 +32,7 @@
|
||||
#define __GTK_COLOR_SELECTION_DIALOG_H__
|
||||
|
||||
#include <gtk/gtkdialog.h>
|
||||
#include <gtk/gtkcolorsel.h>
|
||||
#include <gtk/deprecated/gtkcolorsel.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -71,7 +71,9 @@ struct _GtkColorSelectionDialogClass
|
||||
|
||||
/* ColorSelectionDialog */
|
||||
GType gtk_color_selection_dialog_get_type (void) G_GNUC_CONST;
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_dialog_new)
|
||||
GtkWidget* gtk_color_selection_dialog_new (const gchar *title);
|
||||
GDK_DEPRECATED_FOR(GtkColorChooser)
|
||||
GtkWidget* gtk_color_selection_dialog_get_color_selection (GtkColorSelectionDialog *colorsel);
|
||||
|
||||
|
||||
@@ -1635,7 +1635,7 @@ gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
|
||||
|
||||
/**
|
||||
* SECTION:gtkfontseldlg
|
||||
* @Short_description: A dialog box for selecting fonts
|
||||
* @Short_description: Deprecated dialog box for selecting fonts
|
||||
* @Title: GtkFontSelectionDialog
|
||||
* @See_also: #GtkFontSelection, #GtkDialog, #GtkFontChooserDialog
|
||||
*
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
* very quick and easy change. If you have derived your own classes from
|
||||
* GtkHBox, you can simply change the inheritance to derive directly
|
||||
* from #GtkBox. No further changes are needed, since the default
|
||||
* value of the #GtkOrientable::orientation property is
|
||||
* value of the #GtkOrientable:orientation property is
|
||||
* %GTK_ORIENTATION_HORIZONTAL.
|
||||
* If you want your code to be future-proof, the recommendation is to
|
||||
* switch to #GtkGrid, since #GtkBox is going to be deprecated in favor
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define GDK_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -52,6 +54,9 @@
|
||||
* intuitive way. Moving the selection around the outer ring changes the hue,
|
||||
* and moving the selection point inside the inner triangle changes value and
|
||||
* saturation.
|
||||
*
|
||||
* #GtkHSV has been deprecated together with #GtkColorSelection, where
|
||||
* it was used.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1454,84 +1459,6 @@ gtk_hsv_is_adjusting (GtkHSV *hsv)
|
||||
return priv->mode != DRAG_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_hsv_to_rgb:
|
||||
* @h: Hue
|
||||
* @s: Saturation
|
||||
* @v: Value
|
||||
* @r: (out): Return value for the red component
|
||||
* @g: (out): Return value for the green component
|
||||
* @b: (out): Return value for the blue component
|
||||
*
|
||||
* Converts a color from HSV space to RGB.
|
||||
* Input values must be in the [0.0, 1.0] range;
|
||||
* output values will be in the same range.
|
||||
*
|
||||
* Since: 2.14
|
||||
*/
|
||||
void
|
||||
gtk_hsv_to_rgb (gdouble h,
|
||||
gdouble s,
|
||||
gdouble v,
|
||||
gdouble *r,
|
||||
gdouble *g,
|
||||
gdouble *b)
|
||||
{
|
||||
g_return_if_fail (h >= 0.0 && h <= 1.0);
|
||||
g_return_if_fail (s >= 0.0 && s <= 1.0);
|
||||
g_return_if_fail (v >= 0.0 && v <= 1.0);
|
||||
|
||||
hsv_to_rgb (&h, &s, &v);
|
||||
|
||||
if (r)
|
||||
*r = h;
|
||||
|
||||
if (g)
|
||||
*g = s;
|
||||
|
||||
if (b)
|
||||
*b = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_rgb_to_hsv:
|
||||
* @r: Red
|
||||
* @g: Green
|
||||
* @b: Blue
|
||||
* @h: (out): Return value for the hue component
|
||||
* @s: (out): Return value for the saturation component
|
||||
* @v: (out): Return value for the value component
|
||||
*
|
||||
* Converts a color from RGB space to HSV.
|
||||
* Input values must be in the [0.0, 1.0] range;
|
||||
* output values will be in the same range.
|
||||
*
|
||||
* Since: 2.14
|
||||
*/
|
||||
void
|
||||
gtk_rgb_to_hsv (gdouble r,
|
||||
gdouble g,
|
||||
gdouble b,
|
||||
gdouble *h,
|
||||
gdouble *s,
|
||||
gdouble *v)
|
||||
{
|
||||
g_return_if_fail (r >= 0.0 && r <= 1.0);
|
||||
g_return_if_fail (g >= 0.0 && g <= 1.0);
|
||||
g_return_if_fail (b >= 0.0 && b <= 1.0);
|
||||
|
||||
rgb_to_hsv (&r, &g, &b);
|
||||
|
||||
if (h)
|
||||
*h = r;
|
||||
|
||||
if (s)
|
||||
*s = g;
|
||||
|
||||
if (v)
|
||||
*v = b;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_hsv_move (GtkHSV *hsv,
|
||||
GtkDirectionType dir)
|
||||
@@ -80,37 +80,29 @@ struct _GtkHSVClass
|
||||
|
||||
|
||||
GType gtk_hsv_get_type (void) G_GNUC_CONST;
|
||||
GDK_DEPRECATED
|
||||
GtkWidget* gtk_hsv_new (void);
|
||||
GDK_DEPRECATED
|
||||
void gtk_hsv_set_color (GtkHSV *hsv,
|
||||
double h,
|
||||
double s,
|
||||
double v);
|
||||
GDK_DEPRECATED
|
||||
void gtk_hsv_get_color (GtkHSV *hsv,
|
||||
gdouble *h,
|
||||
gdouble *s,
|
||||
gdouble *v);
|
||||
GDK_DEPRECATED
|
||||
void gtk_hsv_set_metrics (GtkHSV *hsv,
|
||||
gint size,
|
||||
gint ring_width);
|
||||
GDK_DEPRECATED
|
||||
void gtk_hsv_get_metrics (GtkHSV *hsv,
|
||||
gint *size,
|
||||
gint *ring_width);
|
||||
GDK_DEPRECATED
|
||||
gboolean gtk_hsv_is_adjusting (GtkHSV *hsv);
|
||||
|
||||
/* Convert colors between the RGB and HSV color spaces */
|
||||
void gtk_hsv_to_rgb (gdouble h,
|
||||
gdouble s,
|
||||
gdouble v,
|
||||
gdouble *r,
|
||||
gdouble *g,
|
||||
gdouble *b);
|
||||
void gtk_rgb_to_hsv (gdouble r,
|
||||
gdouble g,
|
||||
gdouble b,
|
||||
gdouble *h,
|
||||
gdouble *s,
|
||||
gdouble *v);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_HSV_H__ */
|
||||
@@ -49,7 +49,7 @@
|
||||
* GtkVBox has been deprecated. You can use #GtkBox instead, which is a
|
||||
* very quick and easy change. If you have derived your own classes from
|
||||
* GtkVBox, you can simply change the inheritance to derive directly
|
||||
* from #GtkBox, and set the #GtkOrientable::orientation property to
|
||||
* from #GtkBox, and set the #GtkOrientable:orientation property to
|
||||
* %GTK_ORIENTATION_VERTICAL in your instance init function, with a
|
||||
* call like:
|
||||
* |[
|
||||
|
||||
@@ -362,3 +362,9 @@ GtkCalendar.button:hover {
|
||||
border-width: 0;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.press-and-hold {
|
||||
background-color: alpha (@bg_color, 0.5);
|
||||
color: alpha (lighter (@selected_bg_color), 0.8);
|
||||
border-width: 10;
|
||||
}
|
||||
|
||||
+2
-1
@@ -12,7 +12,8 @@
|
||||
@define-color error_fg_color rgb (166, 38, 38);
|
||||
@define-color error_bg_color rgb (237, 54, 54);
|
||||
|
||||
GtkWindow {
|
||||
GtkWindow,
|
||||
GtkViewport {
|
||||
background-color: @bg_color;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,8 +78,10 @@
|
||||
#include <gtk/gtkcheckmenuitem.h>
|
||||
#include <gtk/gtkclipboard.h>
|
||||
#include <gtk/gtkcolorbutton.h>
|
||||
#include <gtk/gtkcolorsel.h>
|
||||
#include <gtk/gtkcolorseldialog.h>
|
||||
#include <gtk/gtkcolorchooser.h>
|
||||
#include <gtk/gtkcolorchooserdialog.h>
|
||||
#include <gtk/gtkcolorchooserwidget.h>
|
||||
#include <gtk/gtkcolorutils.h>
|
||||
#include <gtk/gtkcombobox.h>
|
||||
#include <gtk/gtkcomboboxtext.h>
|
||||
#include <gtk/gtkcontainer.h>
|
||||
@@ -107,9 +109,9 @@
|
||||
#include <gtk/gtkfontchooserdialog.h>
|
||||
#include <gtk/gtkfontchooserwidget.h>
|
||||
#include <gtk/gtkframe.h>
|
||||
#include <gtk/gtkgesturesinterpreter.h>
|
||||
#include <gtk/gtkgradient.h>
|
||||
#include <gtk/gtkgrid.h>
|
||||
#include <gtk/gtkhsv.h>
|
||||
#include <gtk/gtkiconfactory.h>
|
||||
#include <gtk/gtkicontheme.h>
|
||||
#include <gtk/gtkiconview.h>
|
||||
@@ -223,11 +225,14 @@
|
||||
#include <gtk/gtkwidgetpath.h>
|
||||
#include <gtk/gtkwindow.h>
|
||||
|
||||
#include <gtk/deprecated/gtkcolorsel.h>
|
||||
#include <gtk/deprecated/gtkcolorseldialog.h>
|
||||
#include <gtk/deprecated/gtkfontsel.h>
|
||||
#include <gtk/deprecated/gtkhandlebox.h>
|
||||
#include <gtk/deprecated/gtkhbbox.h>
|
||||
#include <gtk/deprecated/gtkhbox.h>
|
||||
#include <gtk/deprecated/gtkhpaned.h>
|
||||
#include <gtk/deprecated/gtkhsv.h>
|
||||
#include <gtk/deprecated/gtkhscale.h>
|
||||
#include <gtk/deprecated/gtkhscrollbar.h>
|
||||
#include <gtk/deprecated/gtkhseparator.h>
|
||||
|
||||
@@ -605,6 +605,15 @@ gtk_color_button_set_color
|
||||
gtk_color_button_set_rgba
|
||||
gtk_color_button_set_title
|
||||
gtk_color_button_set_use_alpha
|
||||
gtk_color_chooser_dialog_get_type
|
||||
gtk_color_chooser_dialog_new
|
||||
gtk_color_chooser_get_color
|
||||
gtk_color_chooser_get_show_alpha
|
||||
gtk_color_chooser_get_type
|
||||
gtk_color_chooser_set_color
|
||||
gtk_color_chooser_set_show_alpha
|
||||
gtk_color_chooser_widget_get_type
|
||||
gtk_color_chooser_widget_new
|
||||
gtk_color_selection_dialog_get_color_selection
|
||||
gtk_color_selection_dialog_get_type
|
||||
gtk_color_selection_dialog_new
|
||||
|
||||
@@ -2380,7 +2380,7 @@ create_credits_page (GtkAboutDialog *about)
|
||||
priv->credits_page = gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), page_vbox, NULL);
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_NEVER,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
@@ -2389,7 +2389,7 @@ create_credits_page (GtkAboutDialog *about)
|
||||
grid = gtk_grid_new ();
|
||||
gtk_container_set_border_width (GTK_CONTAINER (grid), 5);
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 2);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 8);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
|
||||
gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (grid, GTK_ALIGN_START);
|
||||
@@ -2455,7 +2455,6 @@ create_license_page (GtkAboutDialog *about)
|
||||
priv->license_page = gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), page_vbox, NULL);
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (sw), 5);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
|
||||
@@ -340,9 +340,9 @@ gtk_activatable_update (GtkActivatable *activatable,
|
||||
* @action: (allow-none): the related #GtkAction or %NULL
|
||||
*
|
||||
* This is called to update the activatable completely, this is called
|
||||
* internally when the #GtkActivatable::related-action property is set
|
||||
* internally when the #GtkActivatable:related-action property is set
|
||||
* or unset and by the implementing class when
|
||||
* #GtkActivatable::use-action-appearance changes.
|
||||
* #GtkActivatable:use-action-appearance changes.
|
||||
*
|
||||
* Since: 2.16
|
||||
**/
|
||||
|
||||
@@ -45,8 +45,8 @@ typedef struct _GtkActivatableIface GtkActivatableIface;
|
||||
* You must check the #GtkActivatable:use-action-appearance property only apply action
|
||||
* properties that are meant to effect the appearance accordingly.
|
||||
* @sync_action_properties: Called to update the activatable completely, this is called internally when
|
||||
* #GtkActivatable::related-action property is set or unset and by the implementor when
|
||||
* #GtkActivatable::use-action-appearance changes.<note><para>This method can be called
|
||||
* #GtkActivatable:related-action property is set or unset and by the implementor when
|
||||
* #GtkActivatable:use-action-appearance changes.<note><para>This method can be called
|
||||
* with a %NULL action at times</para></note>
|
||||
*
|
||||
* Since: 2.16
|
||||
|
||||
@@ -31,14 +31,14 @@
|
||||
*
|
||||
* Initially, a #GtkAppChooserButton selects the first application
|
||||
* in its list, which will either be the most-recently used application
|
||||
* or, if #GtkAppChooserButton::show-default-item is %TRUE, the
|
||||
* or, if #GtkAppChooserButton:show-default-item is %TRUE, the
|
||||
* default application.
|
||||
*
|
||||
* The list of applications shown in a #GtkAppChooserButton includes
|
||||
* the recommended applications for the given content type. When
|
||||
* #GtkAppChooserButton::show-default-item is set, the default application
|
||||
* #GtkAppChooserButton:show-default-item is set, the default application
|
||||
* is also included. To let the user chooser other applications,
|
||||
* you can set the #GtkAppChooserButton::show-dialog-item property,
|
||||
* you can set the #GtkAppChooserButton:show-dialog-item property,
|
||||
* which allows to open a full #GtkAppChooserDialog.
|
||||
*
|
||||
* It is possible to add custom items to the list, using
|
||||
|
||||
+2
-2
@@ -42,10 +42,10 @@
|
||||
* same size. GtkButtonBox gives all children the same size, but it does allow
|
||||
* 'outliers' to keep their own larger size. To force all children to be
|
||||
* strictly the same size without exceptions, you can set the
|
||||
* #GtkButtonBox::homogeneous property to %TRUE.
|
||||
* #GtkButtonBox:homogeneous property to %TRUE.
|
||||
*
|
||||
* To excempt individual children from homogeneous sizing regardless of their
|
||||
* 'outlier' status, you can set the #GtkButtonBox::non-homogeneous child
|
||||
* 'outlier' status, you can set the #GtkButtonBox:non-homogeneous child
|
||||
* property.
|
||||
*/
|
||||
|
||||
|
||||
+38
-2
@@ -1813,7 +1813,8 @@ gtk_button_button_press (GtkWidget *widget,
|
||||
GtkButton *button;
|
||||
GtkButtonPrivate *priv;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS)
|
||||
if (event->type == GDK_BUTTON_PRESS ||
|
||||
event->type == GDK_TOUCH_PRESS)
|
||||
{
|
||||
button = GTK_BUTTON (widget);
|
||||
priv = button->priv;
|
||||
@@ -1932,6 +1933,40 @@ gtk_real_button_pressed (GtkButton *button)
|
||||
gtk_button_update_state (button);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
touch_release_in_button (GtkButton *button)
|
||||
{
|
||||
GtkButtonPrivate *priv;
|
||||
gint width, height;
|
||||
GdkEvent *event;
|
||||
gdouble x, y;
|
||||
|
||||
priv = button->priv;
|
||||
event = gtk_get_current_event ();
|
||||
|
||||
if (!event)
|
||||
return FALSE;
|
||||
|
||||
if (event->type != GDK_TOUCH_RELEASE ||
|
||||
event->button.window != priv->event_window)
|
||||
{
|
||||
gdk_event_free (event);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gdk_event_get_coords (event, &x, &y);
|
||||
width = gdk_window_get_width (priv->event_window);
|
||||
height = gdk_window_get_height (priv->event_window);
|
||||
|
||||
gdk_event_free (event);
|
||||
|
||||
if (x >= 0 && x <= width &&
|
||||
y >= 0 && y <= height)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_real_button_released (GtkButton *button)
|
||||
{
|
||||
@@ -1944,7 +1979,8 @@ gtk_real_button_released (GtkButton *button)
|
||||
if (priv->activate_timeout)
|
||||
return;
|
||||
|
||||
if (priv->in_button)
|
||||
if (priv->in_button ||
|
||||
touch_release_in_button (button))
|
||||
gtk_button_clicked (button);
|
||||
|
||||
gtk_button_update_state (button);
|
||||
|
||||
+239
-256
@@ -28,18 +28,18 @@
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#define GDK_DISABLE_DEPRECATION_WARNINGS
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcolorbutton.h"
|
||||
|
||||
#include "gtkbutton.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkalignment.h"
|
||||
#include "gtkcolorsel.h"
|
||||
#include "gtkcolorseldialog.h"
|
||||
#include "gtkcolorchooser.h"
|
||||
#include "gtkcolorchooserprivate.h"
|
||||
#include "gtkcolorchooserdialog.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkdrawingarea.h"
|
||||
#include "gtkframe.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
@@ -62,6 +62,7 @@
|
||||
#define CHECK_DARK (1.0 / 3.0)
|
||||
#define CHECK_LIGHT (2.0 / 3.0)
|
||||
|
||||
#define COLOR_SAMPLE_MARGIN 1
|
||||
|
||||
struct _GtkColorButtonPrivate
|
||||
{
|
||||
@@ -119,7 +120,7 @@ static void gtk_color_button_drag_data_get (GtkWidget *widget,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint time,
|
||||
GtkColorButton *color_button);
|
||||
GtkColorButton *button);
|
||||
|
||||
/* target side drag signals */
|
||||
static void gtk_color_button_drag_data_received (GtkWidget *widget,
|
||||
@@ -129,14 +130,18 @@ static void gtk_color_button_drag_data_received (GtkWidget *widget,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint32 time,
|
||||
GtkColorButton *color_button);
|
||||
GtkColorButton *button);
|
||||
|
||||
|
||||
static guint color_button_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static const GtkTargetEntry drop_types[] = { { "application/x-color", 0, 0 } };
|
||||
|
||||
G_DEFINE_TYPE (GtkColorButton, gtk_color_button, GTK_TYPE_BUTTON)
|
||||
static void gtk_color_button_iface_init (GtkColorChooserInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkColorButton, gtk_color_button, GTK_TYPE_BUTTON,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
|
||||
gtk_color_button_iface_init))
|
||||
|
||||
static void
|
||||
gtk_color_button_class_init (GtkColorButtonClass *klass)
|
||||
@@ -159,9 +164,9 @@ gtk_color_button_class_init (GtkColorButtonClass *klass)
|
||||
/**
|
||||
* GtkColorButton:use-alpha:
|
||||
*
|
||||
* If this property is set to %TRUE, the color swatch on the button is rendered against a
|
||||
* checkerboard background to show its opacity and the opacity slider is displayed in the
|
||||
* color selection dialog.
|
||||
* If this property is set to %TRUE, the color swatch on the button is
|
||||
* rendered against a checkerboard background to show its opacity and
|
||||
* the opacity slider is displayed in the color selection dialog.
|
||||
*
|
||||
* Since: 2.4
|
||||
*/
|
||||
@@ -262,33 +267,9 @@ gtk_color_button_class_init (GtkColorButtonClass *klass)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_color_button_has_alpha (GtkColorButton *color_button)
|
||||
gtk_color_button_has_alpha (GtkColorButton *button)
|
||||
{
|
||||
return color_button->priv->use_alpha &&
|
||||
color_button->priv->rgba.alpha < 1;
|
||||
}
|
||||
|
||||
static cairo_pattern_t *
|
||||
gtk_color_button_get_checkered (void)
|
||||
{
|
||||
/* need to respect pixman's stride being a multiple of 4 */
|
||||
static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00 };
|
||||
static cairo_surface_t *checkered = NULL;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
if (checkered == NULL)
|
||||
{
|
||||
checkered = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_A8,
|
||||
2, 2, 4);
|
||||
}
|
||||
|
||||
pattern = cairo_pattern_create_for_surface (checkered);
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
|
||||
cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
|
||||
|
||||
return pattern;
|
||||
return button->priv->use_alpha && button->priv->rgba.alpha < 1;
|
||||
}
|
||||
|
||||
/* Handle exposure events for the color picker's drawing area */
|
||||
@@ -297,10 +278,10 @@ gtk_color_button_draw_cb (GtkWidget *widget,
|
||||
cairo_t *cr,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
|
||||
GtkColorButton *button = GTK_COLOR_BUTTON (data);
|
||||
cairo_pattern_t *checkered;
|
||||
|
||||
if (gtk_color_button_has_alpha (color_button))
|
||||
if (gtk_color_button_has_alpha (button))
|
||||
{
|
||||
cairo_set_source_rgb (cr, CHECK_DARK, CHECK_DARK, CHECK_DARK);
|
||||
cairo_paint (cr);
|
||||
@@ -308,23 +289,23 @@ gtk_color_button_draw_cb (GtkWidget *widget,
|
||||
cairo_set_source_rgb (cr, CHECK_LIGHT, CHECK_LIGHT, CHECK_LIGHT);
|
||||
cairo_scale (cr, CHECK_SIZE, CHECK_SIZE);
|
||||
|
||||
checkered = gtk_color_button_get_checkered ();
|
||||
checkered = _gtk_color_chooser_get_checkered_pattern ();
|
||||
cairo_mask (cr, checkered);
|
||||
cairo_pattern_destroy (checkered);
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &color_button->priv->rgba);
|
||||
gdk_cairo_set_source_rgba (cr, &button->priv->rgba);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_set_source_rgb (cr,
|
||||
color_button->priv->rgba.red,
|
||||
color_button->priv->rgba.green,
|
||||
color_button->priv->rgba.blue);
|
||||
button->priv->rgba.red,
|
||||
button->priv->rgba.green,
|
||||
button->priv->rgba.blue);
|
||||
}
|
||||
|
||||
cairo_paint (cr);
|
||||
|
||||
if (!gtk_widget_is_sensitive (GTK_WIDGET (color_button)))
|
||||
if (!gtk_widget_is_sensitive (GTK_WIDGET (button)))
|
||||
{
|
||||
GtkStyleContext *context;
|
||||
GdkRGBA color;
|
||||
@@ -333,7 +314,7 @@ gtk_color_button_draw_cb (GtkWidget *widget,
|
||||
gtk_style_context_get_background_color (context, GTK_STATE_FLAG_INSENSITIVE, &color);
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &color);
|
||||
checkered = gtk_color_button_get_checkered ();
|
||||
checkered = _gtk_color_chooser_get_checkered_pattern ();
|
||||
cairo_mask (cr, checkered);
|
||||
cairo_pattern_destroy (checkered);
|
||||
}
|
||||
@@ -356,7 +337,7 @@ gtk_color_button_drag_data_received (GtkWidget *widget,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint32 time,
|
||||
GtkColorButton *color_button)
|
||||
GtkColorButton *button)
|
||||
{
|
||||
gint length;
|
||||
guint16 *dropped;
|
||||
@@ -378,20 +359,20 @@ gtk_color_button_drag_data_received (GtkWidget *widget,
|
||||
|
||||
dropped = (guint16 *) gtk_selection_data_get_data (selection_data);
|
||||
|
||||
color_button->priv->rgba.red = dropped[0] / 65535.;
|
||||
color_button->priv->rgba.green = dropped[1] / 65535.;
|
||||
color_button->priv->rgba.blue = dropped[2] / 65535.;
|
||||
color_button->priv->rgba.alpha = dropped[3] / 65535.;
|
||||
button->priv->rgba.red = dropped[0] / 65535.;
|
||||
button->priv->rgba.green = dropped[1] / 65535.;
|
||||
button->priv->rgba.blue = dropped[2] / 65535.;
|
||||
button->priv->rgba.alpha = dropped[3] / 65535.;
|
||||
|
||||
gtk_widget_queue_draw (color_button->priv->draw_area);
|
||||
gtk_widget_queue_draw (button->priv->draw_area);
|
||||
|
||||
g_signal_emit (color_button, color_button_signals[COLOR_SET], 0);
|
||||
g_signal_emit (button, color_button_signals[COLOR_SET], 0);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (color_button));
|
||||
g_object_notify (G_OBJECT (color_button), "color");
|
||||
g_object_notify (G_OBJECT (color_button), "alpha");
|
||||
g_object_notify (G_OBJECT (color_button), "rgba");
|
||||
g_object_thaw_notify (G_OBJECT (color_button));
|
||||
g_object_freeze_notify (G_OBJECT (button));
|
||||
g_object_notify (G_OBJECT (button), "color");
|
||||
g_object_notify (G_OBJECT (button), "alpha");
|
||||
g_object_notify (G_OBJECT (button), "rgba");
|
||||
g_object_thaw_notify (G_OBJECT (button));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -419,9 +400,9 @@ gtk_color_button_drag_begin (GtkWidget *widget,
|
||||
GdkDragContext *context,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColorButton *color_button = data;
|
||||
GtkColorButton *button = data;
|
||||
|
||||
set_color_icon (context, &color_button->priv->rgba);
|
||||
set_color_icon (context, &button->priv->rgba);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -430,14 +411,14 @@ gtk_color_button_drag_data_get (GtkWidget *widget,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint time,
|
||||
GtkColorButton *color_button)
|
||||
GtkColorButton *button)
|
||||
{
|
||||
guint16 dropped[4];
|
||||
|
||||
dropped[0] = (guint16) (color_button->priv->rgba.red * 65535);
|
||||
dropped[1] = (guint16) (color_button->priv->rgba.green * 65535);
|
||||
dropped[2] = (guint16) (color_button->priv->rgba.blue * 65535);
|
||||
dropped[3] = (guint16) (color_button->priv->rgba.alpha * 65535);
|
||||
dropped[0] = (guint16) (button->priv->rgba.red * 65535);
|
||||
dropped[1] = (guint16) (button->priv->rgba.green * 65535);
|
||||
dropped[2] = (guint16) (button->priv->rgba.blue * 65535);
|
||||
dropped[3] = (guint16) (button->priv->rgba.alpha * 65535);
|
||||
|
||||
gtk_selection_data_set (selection_data,
|
||||
gtk_selection_data_get_target (selection_data),
|
||||
@@ -445,68 +426,62 @@ gtk_color_button_drag_data_get (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_button_init (GtkColorButton *color_button)
|
||||
gtk_color_button_init (GtkColorButton *button)
|
||||
{
|
||||
GtkWidget *alignment;
|
||||
GtkWidget *frame;
|
||||
PangoLayout *layout;
|
||||
PangoRectangle rect;
|
||||
|
||||
/* Create the widgets */
|
||||
color_button->priv = G_TYPE_INSTANCE_GET_PRIVATE (color_button,
|
||||
GTK_TYPE_COLOR_BUTTON,
|
||||
GtkColorButtonPrivate);
|
||||
button->priv = G_TYPE_INSTANCE_GET_PRIVATE (button,
|
||||
GTK_TYPE_COLOR_BUTTON,
|
||||
GtkColorButtonPrivate);
|
||||
|
||||
gtk_widget_push_composite_child ();
|
||||
|
||||
alignment = gtk_alignment_new (0.5, 0.5, 0.5, 1.0);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (alignment), 1);
|
||||
gtk_container_add (GTK_CONTAINER (color_button), alignment);
|
||||
gtk_widget_show (alignment);
|
||||
button->priv->draw_area = gtk_drawing_area_new ();
|
||||
g_object_set (button->priv->draw_area,
|
||||
"margin-top", COLOR_SAMPLE_MARGIN,
|
||||
"margin-bottom", COLOR_SAMPLE_MARGIN,
|
||||
"margin-left", 16,
|
||||
"margin-right", 16,
|
||||
NULL);
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
|
||||
gtk_container_add (GTK_CONTAINER (alignment), frame);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
/* Just some widget we can hook to expose-event on */
|
||||
color_button->priv->draw_area = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (GTK_WIDGET (color_button), "Black");
|
||||
layout = gtk_widget_create_pango_layout (GTK_WIDGET (button), "Black");
|
||||
pango_layout_get_pixel_extents (layout, NULL, &rect);
|
||||
g_object_unref (layout);
|
||||
|
||||
gtk_widget_set_size_request (color_button->priv->draw_area, rect.width - 2, rect.height - 2);
|
||||
g_signal_connect (color_button->priv->draw_area, "draw",
|
||||
G_CALLBACK (gtk_color_button_draw_cb), color_button);
|
||||
gtk_container_add (GTK_CONTAINER (frame), color_button->priv->draw_area);
|
||||
gtk_widget_show (color_button->priv->draw_area);
|
||||
gtk_widget_set_size_request (button->priv->draw_area,
|
||||
rect.width, rect.height - 2 * COLOR_SAMPLE_MARGIN);
|
||||
|
||||
color_button->priv->title = g_strdup (_("Pick a Color")); /* default title */
|
||||
g_signal_connect (button->priv->draw_area, "draw",
|
||||
G_CALLBACK (gtk_color_button_draw_cb), button);
|
||||
gtk_container_add (GTK_CONTAINER (button), button->priv->draw_area);
|
||||
gtk_widget_show (button->priv->draw_area);
|
||||
|
||||
button->priv->title = g_strdup (_("Pick a Color")); /* default title */
|
||||
|
||||
/* Start with opaque black, alpha disabled */
|
||||
button->priv->rgba.red = 0;
|
||||
button->priv->rgba.green = 0;
|
||||
button->priv->rgba.blue = 0;
|
||||
button->priv->rgba.alpha = 1;
|
||||
button->priv->use_alpha = FALSE;
|
||||
|
||||
color_button->priv->rgba.red = 0;
|
||||
color_button->priv->rgba.green = 0;
|
||||
color_button->priv->rgba.blue = 0;
|
||||
color_button->priv->rgba.alpha = 1;
|
||||
color_button->priv->use_alpha = FALSE;
|
||||
|
||||
gtk_drag_dest_set (GTK_WIDGET (color_button),
|
||||
gtk_drag_dest_set (GTK_WIDGET (button),
|
||||
GTK_DEST_DEFAULT_MOTION |
|
||||
GTK_DEST_DEFAULT_HIGHLIGHT |
|
||||
GTK_DEST_DEFAULT_DROP,
|
||||
drop_types, 1, GDK_ACTION_COPY);
|
||||
gtk_drag_source_set (GTK_WIDGET(color_button),
|
||||
gtk_drag_source_set (GTK_WIDGET (button),
|
||||
GDK_BUTTON1_MASK|GDK_BUTTON3_MASK,
|
||||
drop_types, 1,
|
||||
GDK_ACTION_COPY);
|
||||
g_signal_connect (color_button, "drag-begin",
|
||||
G_CALLBACK (gtk_color_button_drag_begin), color_button);
|
||||
g_signal_connect (color_button, "drag-data-received",
|
||||
G_CALLBACK (gtk_color_button_drag_data_received), color_button);
|
||||
g_signal_connect (color_button, "drag-data-get",
|
||||
G_CALLBACK (gtk_color_button_drag_data_get), color_button);
|
||||
g_signal_connect (button, "drag-begin",
|
||||
G_CALLBACK (gtk_color_button_drag_begin), button);
|
||||
g_signal_connect (button, "drag-data-received",
|
||||
G_CALLBACK (gtk_color_button_drag_data_received), button);
|
||||
g_signal_connect (button, "drag-data-get",
|
||||
G_CALLBACK (gtk_color_button_drag_data_get), button);
|
||||
|
||||
gtk_widget_pop_composite_child ();
|
||||
}
|
||||
@@ -514,14 +489,14 @@ gtk_color_button_init (GtkColorButton *color_button)
|
||||
static void
|
||||
gtk_color_button_finalize (GObject *object)
|
||||
{
|
||||
GtkColorButton *color_button = GTK_COLOR_BUTTON (object);
|
||||
GtkColorButton *button = GTK_COLOR_BUTTON (object);
|
||||
|
||||
if (color_button->priv->cs_dialog != NULL)
|
||||
gtk_widget_destroy (color_button->priv->cs_dialog);
|
||||
color_button->priv->cs_dialog = NULL;
|
||||
if (button->priv->cs_dialog != NULL)
|
||||
gtk_widget_destroy (button->priv->cs_dialog);
|
||||
button->priv->cs_dialog = NULL;
|
||||
|
||||
g_free (color_button->priv->title);
|
||||
color_button->priv->title = NULL;
|
||||
g_free (button->priv->title);
|
||||
button->priv->title = NULL;
|
||||
|
||||
G_OBJECT_CLASS (gtk_color_button_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -582,296 +557,278 @@ gtk_color_button_new_with_rgba (const GdkRGBA *rgba)
|
||||
return g_object_new (GTK_TYPE_COLOR_BUTTON, "rgba", rgba, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dialog_ok_clicked (GtkWidget *widget,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
|
||||
GtkColorSelection *color_selection;
|
||||
GtkColorSelectionDialog *selection_dialog;
|
||||
|
||||
selection_dialog = GTK_COLOR_SELECTION_DIALOG (color_button->priv->cs_dialog);
|
||||
color_selection = GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (selection_dialog));
|
||||
|
||||
gtk_color_selection_get_current_rgba (color_selection, &color_button->priv->rgba);
|
||||
|
||||
gtk_widget_hide (color_button->priv->cs_dialog);
|
||||
|
||||
gtk_widget_queue_draw (color_button->priv->draw_area);
|
||||
|
||||
g_signal_emit (color_button, color_button_signals[COLOR_SET], 0);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (color_button));
|
||||
g_object_notify (G_OBJECT (color_button), "color");
|
||||
g_object_notify (G_OBJECT (color_button), "alpha");
|
||||
g_object_notify (G_OBJECT (color_button), "rgba");
|
||||
g_object_thaw_notify (G_OBJECT (color_button));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dialog_destroy (GtkWidget *widget,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
|
||||
GtkColorButton *button = GTK_COLOR_BUTTON (data);
|
||||
|
||||
color_button->priv->cs_dialog = NULL;
|
||||
button->priv->cs_dialog = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
dialog_cancel_clicked (GtkWidget *widget,
|
||||
gpointer data)
|
||||
dialog_response (GtkDialog *dialog,
|
||||
gint response,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
|
||||
if (response == GTK_RESPONSE_CANCEL)
|
||||
gtk_widget_hide (GTK_WIDGET (dialog));
|
||||
else if (response == GTK_RESPONSE_OK)
|
||||
{
|
||||
GtkColorButton *button = GTK_COLOR_BUTTON (data);
|
||||
|
||||
gtk_widget_hide (color_button->priv->cs_dialog);
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog),
|
||||
&button->priv->rgba);
|
||||
|
||||
gtk_widget_hide (GTK_WIDGET (dialog));
|
||||
|
||||
gtk_widget_queue_draw (button->priv->draw_area);
|
||||
|
||||
g_signal_emit (button, color_button_signals[COLOR_SET], 0);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (button));
|
||||
g_object_notify (G_OBJECT (button), "color");
|
||||
g_object_notify (G_OBJECT (button), "alpha");
|
||||
g_object_notify (G_OBJECT (button), "rgba");
|
||||
g_object_thaw_notify (G_OBJECT (button));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_button_clicked (GtkButton *button)
|
||||
gtk_color_button_clicked (GtkButton *b)
|
||||
{
|
||||
GtkColorButton *color_button = GTK_COLOR_BUTTON (button);
|
||||
GtkColorSelection *color_selection;
|
||||
GtkColorSelectionDialog *color_dialog;
|
||||
GtkColorButton *button = GTK_COLOR_BUTTON (b);
|
||||
GtkWidget *dialog;
|
||||
|
||||
/* if dialog already exists, make sure it's shown and raised */
|
||||
if (!color_button->priv->cs_dialog)
|
||||
if (!button->priv->cs_dialog)
|
||||
{
|
||||
/* Create the dialog and connects its buttons */
|
||||
GtkWidget *parent;
|
||||
GtkWidget *ok_button, *cancel_button;
|
||||
|
||||
parent = gtk_widget_get_toplevel (GTK_WIDGET (color_button));
|
||||
parent = gtk_widget_get_toplevel (GTK_WIDGET (button));
|
||||
|
||||
color_button->priv->cs_dialog = gtk_color_selection_dialog_new (color_button->priv->title);
|
||||
|
||||
color_dialog = GTK_COLOR_SELECTION_DIALOG (color_button->priv->cs_dialog);
|
||||
button->priv->cs_dialog = dialog = gtk_color_chooser_dialog_new (button->priv->title, NULL);
|
||||
|
||||
if (gtk_widget_is_toplevel (parent) && GTK_IS_WINDOW (parent))
|
||||
{
|
||||
if (GTK_WINDOW (parent) != gtk_window_get_transient_for (GTK_WINDOW (color_dialog)))
|
||||
gtk_window_set_transient_for (GTK_WINDOW (color_dialog), GTK_WINDOW (parent));
|
||||
if (GTK_WINDOW (parent) != gtk_window_get_transient_for (GTK_WINDOW (dialog)))
|
||||
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));
|
||||
|
||||
gtk_window_set_modal (GTK_WINDOW (color_dialog),
|
||||
gtk_window_set_modal (GTK_WINDOW (dialog),
|
||||
gtk_window_get_modal (GTK_WINDOW (parent)));
|
||||
}
|
||||
|
||||
g_object_get (color_dialog,
|
||||
"ok-button", &ok_button,
|
||||
"cancel-button", &cancel_button,
|
||||
NULL);
|
||||
|
||||
g_signal_connect (ok_button, "clicked",
|
||||
G_CALLBACK (dialog_ok_clicked), color_button);
|
||||
g_signal_connect (cancel_button, "clicked",
|
||||
G_CALLBACK (dialog_cancel_clicked), color_button);
|
||||
g_signal_connect (color_dialog, "destroy",
|
||||
G_CALLBACK (dialog_destroy), color_button);
|
||||
|
||||
g_object_unref (ok_button);
|
||||
g_object_unref (cancel_button);
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (dialog_response), button);
|
||||
g_signal_connect (dialog, "destroy",
|
||||
G_CALLBACK (dialog_destroy), button);
|
||||
}
|
||||
|
||||
color_dialog = GTK_COLOR_SELECTION_DIALOG (color_button->priv->cs_dialog);
|
||||
color_selection = GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (color_dialog));
|
||||
gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (button->priv->cs_dialog),
|
||||
button->priv->use_alpha);
|
||||
|
||||
gtk_color_selection_set_has_opacity_control (color_selection,
|
||||
color_button->priv->use_alpha);
|
||||
|
||||
gtk_color_selection_set_previous_rgba (color_selection,
|
||||
&color_button->priv->rgba);
|
||||
gtk_color_selection_set_current_rgba (color_selection,
|
||||
&color_button->priv->rgba);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (color_button->priv->cs_dialog));
|
||||
gtk_window_present (GTK_WINDOW (button->priv->cs_dialog));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_button_set_color:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
* @color: A #GdkColor to set the current color with
|
||||
*
|
||||
* Sets the current color to be @color.
|
||||
*
|
||||
* Since: 2.4
|
||||
*
|
||||
* Deprecated: Use gtk_color_button_set_rgba() instead.
|
||||
* Deprecated: Use gtk_color_chooser_set_rgba() instead.
|
||||
*/
|
||||
void
|
||||
gtk_color_button_set_color (GtkColorButton *color_button,
|
||||
gtk_color_button_set_color (GtkColorButton *button,
|
||||
const GdkColor *color)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
|
||||
g_return_if_fail (color != NULL);
|
||||
|
||||
color_button->priv->rgba.red = color->red / 65535.;
|
||||
color_button->priv->rgba.green = color->green / 65535.;
|
||||
color_button->priv->rgba.blue = color->blue / 65535.;
|
||||
button->priv->rgba.red = color->red / 65535.;
|
||||
button->priv->rgba.green = color->green / 65535.;
|
||||
button->priv->rgba.blue = color->blue / 65535.;
|
||||
|
||||
gtk_widget_queue_draw (color_button->priv->draw_area);
|
||||
gtk_widget_queue_draw (button->priv->draw_area);
|
||||
|
||||
g_object_notify (G_OBJECT (color_button), "color");
|
||||
g_object_notify (G_OBJECT (color_button), "rgba");
|
||||
g_object_notify (G_OBJECT (button), "color");
|
||||
g_object_notify (G_OBJECT (button), "rgba");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gtk_color_button_set_alpha:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
* @alpha: an integer between 0 and 65535
|
||||
*
|
||||
* Sets the current opacity to be @alpha.
|
||||
*
|
||||
* Since: 2.4
|
||||
*
|
||||
* Deprecated: 3.4: Use gtk_color_chooser_set_rgba() instead.
|
||||
*/
|
||||
void
|
||||
gtk_color_button_set_alpha (GtkColorButton *color_button,
|
||||
gtk_color_button_set_alpha (GtkColorButton *button,
|
||||
guint16 alpha)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
|
||||
|
||||
color_button->priv->rgba.alpha = alpha / 65535.;
|
||||
button->priv->rgba.alpha = alpha / 65535.;
|
||||
|
||||
gtk_widget_queue_draw (color_button->priv->draw_area);
|
||||
gtk_widget_queue_draw (button->priv->draw_area);
|
||||
|
||||
g_object_notify (G_OBJECT (color_button), "alpha");
|
||||
g_object_notify (G_OBJECT (color_button), "rgba");
|
||||
g_object_notify (G_OBJECT (button), "alpha");
|
||||
g_object_notify (G_OBJECT (button), "rgba");
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_button_get_color:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
* @color: (out): a #GdkColor to fill in with the current color
|
||||
*
|
||||
* Sets @color to be the current color in the #GtkColorButton widget.
|
||||
*
|
||||
* Since: 2.4
|
||||
*
|
||||
* Deprecated: 3.4: Use gtk_color_button_get_rgba() instead.
|
||||
* Deprecated: 3.4: Use gtk_color_chooser_get_rgba() instead.
|
||||
*/
|
||||
void
|
||||
gtk_color_button_get_color (GtkColorButton *color_button,
|
||||
gtk_color_button_get_color (GtkColorButton *button,
|
||||
GdkColor *color)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
|
||||
|
||||
color->red = (guint16) (color_button->priv->rgba.red * 65535);
|
||||
color->green = (guint16) (color_button->priv->rgba.green * 65535);
|
||||
color->blue = (guint16) (color_button->priv->rgba.blue * 65535);
|
||||
color->red = (guint16) (button->priv->rgba.red * 65535);
|
||||
color->green = (guint16) (button->priv->rgba.green * 65535);
|
||||
color->blue = (guint16) (button->priv->rgba.blue * 65535);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_button_get_alpha:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
*
|
||||
* Returns the current alpha value.
|
||||
*
|
||||
* Return value: an integer between 0 and 65535
|
||||
*
|
||||
* Since: 2.4
|
||||
*
|
||||
* Deprecated: 3.4: Use gtk_color_chooser_get_rgba() instead.
|
||||
*/
|
||||
guint16
|
||||
gtk_color_button_get_alpha (GtkColorButton *color_button)
|
||||
gtk_color_button_get_alpha (GtkColorButton *button)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (color_button), 0);
|
||||
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (button), 0);
|
||||
|
||||
return (guint16) (color_button->priv->rgba.alpha * 65535);
|
||||
return (guint16) (button->priv->rgba.alpha * 65535);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_button_set_rgba:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
* @rgba: a #GdkRGBA to set the current color with
|
||||
*
|
||||
* Sets the current color to be @rgba.
|
||||
*
|
||||
* Since: 3.0
|
||||
*
|
||||
* Deprecated: 3.4: Use gtk_color_chooser_set_rgba() instead.
|
||||
*/
|
||||
void
|
||||
gtk_color_button_set_rgba (GtkColorButton *color_button,
|
||||
gtk_color_button_set_rgba (GtkColorButton *button,
|
||||
const GdkRGBA *rgba)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
|
||||
g_return_if_fail (rgba != NULL);
|
||||
|
||||
color_button->priv->rgba = *rgba;
|
||||
button->priv->rgba = *rgba;
|
||||
gtk_widget_queue_draw (button->priv->draw_area);
|
||||
|
||||
gtk_widget_queue_draw (color_button->priv->draw_area);
|
||||
|
||||
g_object_notify (G_OBJECT (color_button), "color");
|
||||
g_object_notify (G_OBJECT (color_button), "alpha");
|
||||
g_object_notify (G_OBJECT (color_button), "rgba");
|
||||
g_object_notify (G_OBJECT (button), "color");
|
||||
g_object_notify (G_OBJECT (button), "alpha");
|
||||
g_object_notify (G_OBJECT (button), "rgba");
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_button_get_rgba:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
* @rgba: (out): a #GdkRGBA to fill in with the current color
|
||||
*
|
||||
* Sets @rgba to be the current color in the #GtkColorButton widget.
|
||||
*
|
||||
* Since: 3.0
|
||||
*
|
||||
* Deprecated: 3.4: Use gtk_color_chooser_get_rgba() instead.
|
||||
*/
|
||||
void
|
||||
gtk_color_button_get_rgba (GtkColorButton *color_button,
|
||||
gtk_color_button_get_rgba (GtkColorButton *button,
|
||||
GdkRGBA *rgba)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
|
||||
g_return_if_fail (rgba != NULL);
|
||||
|
||||
*rgba = color_button->priv->rgba;
|
||||
*rgba = button->priv->rgba;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_button_set_use_alpha:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
* @use_alpha: %TRUE if color button should use alpha channel, %FALSE if not
|
||||
*
|
||||
* Sets whether or not the color button should use the alpha channel.
|
||||
*
|
||||
* Since: 2.4
|
||||
*
|
||||
* Deprecated: 3.4: Use gtk_color_chooser_set_use_alpha() instead.
|
||||
*/
|
||||
void
|
||||
gtk_color_button_set_use_alpha (GtkColorButton *color_button,
|
||||
gtk_color_button_set_use_alpha (GtkColorButton *button,
|
||||
gboolean use_alpha)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
|
||||
|
||||
use_alpha = (use_alpha != FALSE);
|
||||
|
||||
if (color_button->priv->use_alpha != use_alpha)
|
||||
if (button->priv->use_alpha != use_alpha)
|
||||
{
|
||||
color_button->priv->use_alpha = use_alpha;
|
||||
button->priv->use_alpha = use_alpha;
|
||||
|
||||
gtk_widget_queue_draw (color_button->priv->draw_area);
|
||||
gtk_widget_queue_draw (button->priv->draw_area);
|
||||
|
||||
g_object_notify (G_OBJECT (color_button), "use-alpha");
|
||||
g_object_notify (G_OBJECT (button), "use-alpha");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_button_get_use_alpha:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
*
|
||||
* Does the color selection dialog use the alpha channel ?
|
||||
*
|
||||
* Returns: %TRUE if the color sample uses alpha channel, %FALSE if not
|
||||
*
|
||||
* Since: 2.4
|
||||
*
|
||||
* Deprecated: 3.4: Use gtk_color_chooser_get_use_alpha() instead.
|
||||
*/
|
||||
gboolean
|
||||
gtk_color_button_get_use_alpha (GtkColorButton *color_button)
|
||||
gtk_color_button_get_use_alpha (GtkColorButton *button)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (color_button), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (button), FALSE);
|
||||
|
||||
return color_button->priv->use_alpha;
|
||||
return button->priv->use_alpha;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gtk_color_button_set_title:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
* @title: String containing new window title
|
||||
*
|
||||
* Sets the title for the color selection dialog.
|
||||
@@ -879,27 +836,27 @@ gtk_color_button_get_use_alpha (GtkColorButton *color_button)
|
||||
* Since: 2.4
|
||||
*/
|
||||
void
|
||||
gtk_color_button_set_title (GtkColorButton *color_button,
|
||||
gtk_color_button_set_title (GtkColorButton *button,
|
||||
const gchar *title)
|
||||
{
|
||||
gchar *old_title;
|
||||
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
|
||||
g_return_if_fail (GTK_IS_COLOR_BUTTON (button));
|
||||
|
||||
old_title = color_button->priv->title;
|
||||
color_button->priv->title = g_strdup (title);
|
||||
old_title = button->priv->title;
|
||||
button->priv->title = g_strdup (title);
|
||||
g_free (old_title);
|
||||
|
||||
if (color_button->priv->cs_dialog)
|
||||
gtk_window_set_title (GTK_WINDOW (color_button->priv->cs_dialog),
|
||||
color_button->priv->title);
|
||||
if (button->priv->cs_dialog)
|
||||
gtk_window_set_title (GTK_WINDOW (button->priv->cs_dialog),
|
||||
button->priv->title);
|
||||
|
||||
g_object_notify (G_OBJECT (color_button), "title");
|
||||
g_object_notify (G_OBJECT (button), "title");
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_button_get_title:
|
||||
* @color_button: a #GtkColorButton
|
||||
* @button: a #GtkColorButton
|
||||
*
|
||||
* Gets the title of the color selection dialog.
|
||||
*
|
||||
@@ -908,11 +865,11 @@ gtk_color_button_set_title (GtkColorButton *color_button,
|
||||
* Since: 2.4
|
||||
*/
|
||||
const gchar *
|
||||
gtk_color_button_get_title (GtkColorButton *color_button)
|
||||
gtk_color_button_get_title (GtkColorButton *button)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (color_button), NULL);
|
||||
g_return_val_if_fail (GTK_IS_COLOR_BUTTON (button), NULL);
|
||||
|
||||
return color_button->priv->title;
|
||||
return button->priv->title;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -921,15 +878,15 @@ gtk_color_button_set_property (GObject *object,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorButton *color_button = GTK_COLOR_BUTTON (object);
|
||||
GtkColorButton *button = GTK_COLOR_BUTTON (object);
|
||||
|
||||
switch (param_id)
|
||||
{
|
||||
case PROP_USE_ALPHA:
|
||||
gtk_color_button_set_use_alpha (color_button, g_value_get_boolean (value));
|
||||
gtk_color_button_set_use_alpha (button, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_TITLE:
|
||||
gtk_color_button_set_title (color_button, g_value_get_string (value));
|
||||
gtk_color_button_set_title (button, g_value_get_string (value));
|
||||
break;
|
||||
case PROP_COLOR:
|
||||
{
|
||||
@@ -943,14 +900,14 @@ gtk_color_button_set_property (GObject *object,
|
||||
rgba.blue = color->blue / 65535.0;
|
||||
rgba.alpha = 1.0;
|
||||
|
||||
gtk_color_button_set_rgba (color_button, &rgba);
|
||||
gtk_color_button_set_rgba (button, &rgba);
|
||||
}
|
||||
break;
|
||||
case PROP_ALPHA:
|
||||
gtk_color_button_set_alpha (color_button, g_value_get_uint (value));
|
||||
gtk_color_button_set_alpha (button, g_value_get_uint (value));
|
||||
break;
|
||||
case PROP_RGBA:
|
||||
gtk_color_button_set_rgba (color_button, g_value_get_boxed (value));
|
||||
gtk_color_button_set_rgba (button, g_value_get_boxed (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
|
||||
@@ -964,22 +921,22 @@ gtk_color_button_get_property (GObject *object,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorButton *color_button = GTK_COLOR_BUTTON (object);
|
||||
GtkColorButton *button = GTK_COLOR_BUTTON (object);
|
||||
|
||||
switch (param_id)
|
||||
{
|
||||
case PROP_USE_ALPHA:
|
||||
g_value_set_boolean (value, gtk_color_button_get_use_alpha (color_button));
|
||||
g_value_set_boolean (value, gtk_color_button_get_use_alpha (button));
|
||||
break;
|
||||
case PROP_TITLE:
|
||||
g_value_set_string (value, gtk_color_button_get_title (color_button));
|
||||
g_value_set_string (value, gtk_color_button_get_title (button));
|
||||
break;
|
||||
case PROP_COLOR:
|
||||
{
|
||||
GdkColor color;
|
||||
GdkRGBA rgba;
|
||||
|
||||
gtk_color_button_get_rgba (color_button, &rgba);
|
||||
gtk_color_button_get_rgba (button, &rgba);
|
||||
|
||||
color.red = (guint16) (rgba.red * 65535 + 0.5);
|
||||
color.green = (guint16) (rgba.green * 65535 + 0.5);
|
||||
@@ -989,13 +946,13 @@ gtk_color_button_get_property (GObject *object,
|
||||
}
|
||||
break;
|
||||
case PROP_ALPHA:
|
||||
g_value_set_uint (value, gtk_color_button_get_alpha (color_button));
|
||||
g_value_set_uint (value, gtk_color_button_get_alpha (button));
|
||||
break;
|
||||
case PROP_RGBA:
|
||||
{
|
||||
GdkRGBA rgba;
|
||||
|
||||
gtk_color_button_get_rgba (color_button, &rgba);
|
||||
gtk_color_button_get_rgba (button, &rgba);
|
||||
g_value_set_boxed (value, &rgba);
|
||||
}
|
||||
break;
|
||||
@@ -1004,3 +961,29 @@ gtk_color_button_get_property (GObject *object,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_button_add_palette (GtkColorChooser *chooser,
|
||||
gboolean horizontal,
|
||||
gint colors_per_line,
|
||||
gint n_colors,
|
||||
GdkRGBA *colors)
|
||||
{
|
||||
GtkColorButton *button = GTK_COLOR_BUTTON (chooser);
|
||||
|
||||
if (button->priv->cs_dialog)
|
||||
gtk_color_chooser_add_palette (GTK_COLOR_CHOOSER (button->priv->cs_dialog),
|
||||
horizontal, colors_per_line, n_colors, colors);
|
||||
}
|
||||
|
||||
typedef void (* get_rgba) (GtkColorChooser *, GdkRGBA *);
|
||||
typedef void (* set_rgba) (GtkColorChooser *, const GdkRGBA *);
|
||||
|
||||
static void
|
||||
gtk_color_button_iface_init (GtkColorChooserInterface *iface)
|
||||
{
|
||||
iface->get_rgba = (get_rgba)gtk_color_button_get_rgba;
|
||||
iface->set_rgba = (set_rgba)gtk_color_button_set_rgba;
|
||||
iface->add_palette = gtk_color_button_add_palette;
|
||||
}
|
||||
|
||||
|
||||
+24
-19
@@ -73,32 +73,37 @@ struct _GtkColorButtonClass {
|
||||
};
|
||||
|
||||
|
||||
GType gtk_color_button_get_type (void) G_GNUC_CONST;
|
||||
GtkWidget *gtk_color_button_new (void);
|
||||
GtkWidget *gtk_color_button_new_with_rgba (const GdkRGBA *rgba);
|
||||
void gtk_color_button_set_alpha (GtkColorButton *color_button,
|
||||
guint16 alpha);
|
||||
guint16 gtk_color_button_get_alpha (GtkColorButton *color_button);
|
||||
void gtk_color_button_set_use_alpha (GtkColorButton *color_button,
|
||||
gboolean use_alpha);
|
||||
gboolean gtk_color_button_get_use_alpha (GtkColorButton *color_button);
|
||||
void gtk_color_button_set_rgba (GtkColorButton *color_button,
|
||||
const GdkRGBA *rgba);
|
||||
void gtk_color_button_get_rgba (GtkColorButton *color_button,
|
||||
GdkRGBA *rgba);
|
||||
void gtk_color_button_set_title (GtkColorButton *color_button,
|
||||
const gchar *title);
|
||||
const gchar *gtk_color_button_get_title (GtkColorButton *color_button);
|
||||
GType gtk_color_button_get_type (void) G_GNUC_CONST;
|
||||
GtkWidget * gtk_color_button_new (void);
|
||||
GtkWidget * gtk_color_button_new_with_rgba (const GdkRGBA *rgba);
|
||||
void gtk_color_button_set_title (GtkColorButton *button,
|
||||
const gchar *title);
|
||||
const gchar *gtk_color_button_get_title (GtkColorButton *button);
|
||||
|
||||
GDK_DEPRECATED_FOR(gtk_color_button_new_with_rgba)
|
||||
GtkWidget *gtk_color_button_new_with_color (const GdkColor *color);
|
||||
GDK_DEPRECATED_FOR(gtk_color_button_set_rgba)
|
||||
void gtk_color_button_set_color (GtkColorButton *color_button,
|
||||
void gtk_color_button_set_color (GtkColorButton *button,
|
||||
const GdkColor *color);
|
||||
GDK_DEPRECATED_FOR(gtk_color_button_get_rgba)
|
||||
void gtk_color_button_get_color (GtkColorButton *color_button,
|
||||
void gtk_color_button_get_color (GtkColorButton *button,
|
||||
GdkColor *color);
|
||||
|
||||
GDK_DEPRECATED_FOR(gtk_color_button_set_rgba)
|
||||
void gtk_color_button_set_alpha (GtkColorButton *button,
|
||||
guint16 alpha);
|
||||
GDK_DEPRECATED_FOR(gtk_color_button_get_rgba)
|
||||
guint16 gtk_color_button_get_alpha (GtkColorButton *button);
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_set_use_alpha)
|
||||
void gtk_color_button_set_use_alpha (GtkColorButton *button,
|
||||
gboolean use_alpha);
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_get_use_alpha)
|
||||
gboolean gtk_color_button_get_use_alpha (GtkColorButton *button);
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_set_rgba)
|
||||
void gtk_color_button_set_rgba (GtkColorButton *button,
|
||||
const GdkRGBA *rgba);
|
||||
GDK_DEPRECATED_FOR(gtk_color_chooser_get_rgba)
|
||||
void gtk_color_button_get_rgba (GtkColorButton *button,
|
||||
GdkRGBA *rgba);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
*
|
||||
* Copyright (C) 2012, Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcolorchooser.h"
|
||||
#include "gtkcolorchooserprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkcolorchooser
|
||||
* @Short_description: Interface implemented by widgets for choosing colors
|
||||
* @Title: GtkColorChooser
|
||||
* @See_also: #GtkColorChooserDialog, #GtkColorChooserWidget, #GtkColorButton
|
||||
*
|
||||
* #GtkColorChooser is an interface that is implemented by widgets
|
||||
* for choosing colors. Depending on the situation, colors may be
|
||||
* allowed to have alpha (translucency).
|
||||
*
|
||||
* In GTK+, the main widgets that implement this interface are
|
||||
* #GtkColorChooserWidget, #GtkColorChooserDialog and #GtkColorButton.
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
COLOR_ACTIVATED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
G_DEFINE_INTERFACE (GtkColorChooser, gtk_color_chooser, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
gtk_color_chooser_default_init (GtkColorChooserInterface *iface)
|
||||
{
|
||||
/**
|
||||
* GtkColorChooser:rgba:
|
||||
*
|
||||
* The ::rgba property contains the currently selected color,
|
||||
* as a #GdkRGBA struct. The property can be set to change
|
||||
* the current selection programmatically.
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_boxed ("rgba",
|
||||
P_("Color"),
|
||||
P_("Current color, as a GdkRGBA"),
|
||||
GDK_TYPE_RGBA,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* GtkColorChooser:use-alpha:
|
||||
*
|
||||
* When ::use-alpha is %TRUE, colors may have alpha (translucency)
|
||||
* information. When it is %FALSE, the #GdkRGBA struct obtained
|
||||
* via the #GtkColorChooser:rgba property will be forced to have
|
||||
* alpha == 1.
|
||||
*
|
||||
* Implementations are expected to show alpha by rendering the color
|
||||
* over a non-uniform background (like a checkerboard pattern).
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_boolean ("use-alpha",
|
||||
P_("Use alpha"),
|
||||
P_("Whether alpha should be shown"),
|
||||
TRUE,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* GtkColorChooser::color-activated:
|
||||
* @chooser: the object which received the signal
|
||||
* @color: the color
|
||||
*
|
||||
* Emitted when a color is activated from the color chooser.
|
||||
* This usually happens when the user clicks a color swatch,
|
||||
* or a color is selected and the user presses one of the keys
|
||||
* Space, Shift+Space, Return or Enter.
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
signals[COLOR_ACTIVATED] =
|
||||
g_signal_new ("color-activated",
|
||||
GTK_TYPE_COLOR_CHOOSER,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (GtkColorChooserInterface, color_activated),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE,
|
||||
1, G_TYPE_STRING);
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_color_chooser_color_activated (GtkColorChooser *chooser,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
g_signal_emit (chooser, signals[COLOR_ACTIVATED], 0, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_chooser_get_rgba:
|
||||
* @chooser: a #GtkColorChooser
|
||||
* @color: return location for the color
|
||||
*
|
||||
* Gets the currently-selected color.
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
void
|
||||
gtk_color_chooser_get_rgba (GtkColorChooser *chooser,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLOR_CHOOSER (chooser));
|
||||
|
||||
GTK_COLOR_CHOOSER_GET_IFACE (chooser)->get_rgba (chooser, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_chooser_set_rgba:
|
||||
* @chooser: a #GtkColorChooser
|
||||
* @color: the new color
|
||||
*
|
||||
* Sets the color.
|
||||
*/
|
||||
void
|
||||
gtk_color_chooser_set_rgba (GtkColorChooser *chooser,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLOR_CHOOSER (chooser));
|
||||
g_return_if_fail (color != NULL);
|
||||
|
||||
GTK_COLOR_CHOOSER_GET_IFACE (chooser)->set_rgba (chooser, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_chooser_get_use_alpha:
|
||||
* @chooser: a #GtkColorChooser
|
||||
*
|
||||
* Returns whether the color chooser shows the alpha channel.
|
||||
*
|
||||
* Returns: %TRUE if the color chooser uses the alpha channel,
|
||||
* %FALSE if not
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
gboolean
|
||||
gtk_color_chooser_get_use_alpha (GtkColorChooser *chooser)
|
||||
{
|
||||
gboolean use_alpha;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_COLOR_CHOOSER (chooser), TRUE);
|
||||
|
||||
g_object_get (chooser, "use-alpha", &use_alpha, NULL);
|
||||
|
||||
return use_alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_chooser_set_use_alpha:
|
||||
* @chooser: a #GtkColorChooser
|
||||
* @use_alpha: %TRUE if color chooser should use alpha channel, %FALSE if not
|
||||
*
|
||||
* Sets whether or not the color chooser should use the alpha channel.
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
void
|
||||
gtk_color_chooser_set_use_alpha (GtkColorChooser *chooser,
|
||||
gboolean use_alpha)
|
||||
{
|
||||
|
||||
g_return_if_fail (GTK_IS_COLOR_CHOOSER (chooser));
|
||||
|
||||
g_object_set (chooser, "use-alpha", use_alpha, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_chooser_add_palette:
|
||||
* @chooser: a #GtkColorChooser
|
||||
* @horizontal: %TRUE if the palette should be displayed in rows,
|
||||
* %FALSE for columns
|
||||
* @colors_per_line: the number of colors to show in each row/column
|
||||
* @n_colors: the total number of elements in @colors
|
||||
* @colors: (array length=n_colors): the colors of the palette
|
||||
*
|
||||
* Adds a palette to the color chooser. If @horizontal is %TRUE,
|
||||
* the colors are grouped in rows, with @colors_per_line colors
|
||||
* in each row. If @horizontal is %FALSE, the colors are grouped
|
||||
* in columns instead.
|
||||
*
|
||||
* The default color palette of #GtkColorChooserWidget has
|
||||
* 27 colors, organized in columns of 3 colors. The default gray
|
||||
* palette has 9 grays in a single row.
|
||||
*
|
||||
* The layout of the color chooser widget works best when the
|
||||
* palettes have 9-10 columns.
|
||||
*
|
||||
* Calling this function is called for the first time has the
|
||||
* side effect of removing the default color and gray palettes
|
||||
* from the color chooser.
|
||||
*/
|
||||
void
|
||||
gtk_color_chooser_add_palette (GtkColorChooser *chooser,
|
||||
gboolean horizontal,
|
||||
gint colors_per_line,
|
||||
gint n_colors,
|
||||
GdkRGBA *colors)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLOR_CHOOSER (chooser));
|
||||
|
||||
if (GTK_COLOR_CHOOSER_GET_IFACE (chooser)->add_palette)
|
||||
GTK_COLOR_CHOOSER_GET_IFACE (chooser)->add_palette (chooser, horizontal, colors_per_line, n_colors, colors);
|
||||
}
|
||||
|
||||
cairo_pattern_t *
|
||||
_gtk_color_chooser_get_checkered_pattern (void)
|
||||
{
|
||||
/* need to respect pixman's stride being a multiple of 4 */
|
||||
static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00 };
|
||||
static cairo_surface_t *checkered = NULL;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
if (checkered == NULL)
|
||||
checkered = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_A8,
|
||||
2, 2, 4);
|
||||
|
||||
pattern = cairo_pattern_create_for_surface (checkered);
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
|
||||
cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __GTK_COLOR_CHOOSER_H__
|
||||
#define __GTK_COLOR_CHOOSER_H__
|
||||
|
||||
#include <gtk/gtkwidget.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_COLOR_CHOOSER (gtk_color_chooser_get_type ())
|
||||
#define GTK_COLOR_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_CHOOSER, GtkColorChooser))
|
||||
#define GTK_IS_COLOR_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_CHOOSER))
|
||||
#define GTK_COLOR_CHOOSER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_COLOR_CHOOSER, GtkColorChooserInterface))
|
||||
|
||||
typedef struct _GtkColorChooser GtkColorChooser;
|
||||
typedef struct _GtkColorChooserInterface GtkColorChooserInterface;
|
||||
|
||||
struct _GtkColorChooserInterface
|
||||
{
|
||||
GTypeInterface base_interface;
|
||||
|
||||
/* Methods */
|
||||
void (* get_rgba) (GtkColorChooser *chooser,
|
||||
GdkRGBA *color);
|
||||
void (* set_rgba) (GtkColorChooser *chooser,
|
||||
const GdkRGBA *color);
|
||||
|
||||
void (* add_palette) (GtkColorChooser *chooser,
|
||||
gboolean horizontal,
|
||||
gint colors_per_line,
|
||||
gint n_colors,
|
||||
GdkRGBA *colors);
|
||||
|
||||
/* Signals */
|
||||
void (* color_activated) (GtkColorChooser *chooser,
|
||||
const GdkRGBA *color);
|
||||
|
||||
/* Padding */
|
||||
gpointer padding[12];
|
||||
};
|
||||
|
||||
GType gtk_color_chooser_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void gtk_color_chooser_get_rgba (GtkColorChooser *chooser,
|
||||
GdkRGBA *color);
|
||||
void gtk_color_chooser_set_rgba (GtkColorChooser *chooser,
|
||||
const GdkRGBA *color);
|
||||
gboolean gtk_color_chooser_get_use_alpha (GtkColorChooser *chooser);
|
||||
void gtk_color_chooser_set_use_alpha (GtkColorChooser *chooser,
|
||||
gboolean use_alpha);
|
||||
|
||||
void gtk_color_chooser_add_palette (GtkColorChooser *chooser,
|
||||
gboolean horizontal,
|
||||
gint colors_per_line,
|
||||
gint n_colors,
|
||||
GdkRGBA *colors);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLOR_CHOOSER_H__ */
|
||||
@@ -0,0 +1,303 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkdialog.h"
|
||||
#include "gtkstock.h"
|
||||
#include "gtkbox.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
#include "gtkcolorchooserprivate.h"
|
||||
#include "gtkcolorchooserdialog.h"
|
||||
#include "gtkcolorchooserwidget.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkcolorchooserdialog
|
||||
* @Short_description: A dialog for choosing colors
|
||||
* @Title: GtkColorChooserDialog
|
||||
* @See_also: #GtkColorChooser, #GtkDialog
|
||||
*
|
||||
* The #GtkColorChooserDialog widget is a dialog for choosing
|
||||
* a color. It implements the #GtkColorChooser interface.
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
|
||||
struct _GtkColorChooserDialogPrivate
|
||||
{
|
||||
GtkWidget *chooser;
|
||||
|
||||
GtkWidget *select_button;
|
||||
GtkWidget *cancel_button;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_ZERO,
|
||||
PROP_RGBA,
|
||||
PROP_USE_ALPHA,
|
||||
PROP_SHOW_EDITOR
|
||||
};
|
||||
|
||||
static void gtk_color_chooser_dialog_iface_init (GtkColorChooserInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkColorChooserDialog, gtk_color_chooser_dialog, GTK_TYPE_DIALOG,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
|
||||
gtk_color_chooser_dialog_iface_init))
|
||||
|
||||
static void
|
||||
propagate_notify (GObject *o,
|
||||
GParamSpec *pspec,
|
||||
GtkColorChooserDialog *cc)
|
||||
{
|
||||
g_object_notify (G_OBJECT (cc), pspec->name);
|
||||
}
|
||||
|
||||
static void
|
||||
color_activated_cb (GtkColorChooser *chooser,
|
||||
GdkRGBA *color,
|
||||
GtkDialog *dialog)
|
||||
{
|
||||
gtk_dialog_response (dialog, GTK_RESPONSE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_dialog_init (GtkColorChooserDialog *cc)
|
||||
{
|
||||
GtkColorChooserDialogPrivate *priv;
|
||||
GtkDialog *dialog = GTK_DIALOG (cc);
|
||||
GtkWidget *action_area, *content_area;
|
||||
|
||||
cc->priv = G_TYPE_INSTANCE_GET_PRIVATE (cc,
|
||||
GTK_TYPE_COLOR_CHOOSER_DIALOG,
|
||||
GtkColorChooserDialogPrivate);
|
||||
priv = cc->priv;
|
||||
|
||||
content_area = gtk_dialog_get_content_area (dialog);
|
||||
action_area = gtk_dialog_get_action_area (dialog);
|
||||
|
||||
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
|
||||
gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
|
||||
gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
|
||||
gtk_box_set_spacing (GTK_BOX (action_area), 6);
|
||||
|
||||
gtk_widget_push_composite_child ();
|
||||
|
||||
gtk_window_set_resizable (GTK_WINDOW (cc), FALSE);
|
||||
|
||||
/* Create the content area */
|
||||
priv->chooser = gtk_color_chooser_widget_new ();
|
||||
gtk_container_set_border_width (GTK_CONTAINER (priv->chooser), 5);
|
||||
gtk_widget_show (priv->chooser);
|
||||
gtk_box_pack_start (GTK_BOX (content_area),
|
||||
priv->chooser, TRUE, TRUE, 0);
|
||||
|
||||
g_signal_connect (priv->chooser, "notify::rgba",
|
||||
G_CALLBACK (propagate_notify), cc);
|
||||
|
||||
g_signal_connect (priv->chooser, "notify::show-editor",
|
||||
G_CALLBACK (propagate_notify), cc);
|
||||
|
||||
g_signal_connect (priv->chooser, "color-activated",
|
||||
G_CALLBACK (color_activated_cb), cc);
|
||||
|
||||
/* Create the action area */
|
||||
priv->cancel_button = gtk_dialog_add_button (dialog,
|
||||
GTK_STOCK_CANCEL,
|
||||
GTK_RESPONSE_CANCEL);
|
||||
priv->select_button = gtk_dialog_add_button (dialog,
|
||||
_("_Select"),
|
||||
GTK_RESPONSE_OK);
|
||||
gtk_widget_grab_default (priv->select_button);
|
||||
|
||||
gtk_dialog_set_alternative_button_order (dialog,
|
||||
GTK_RESPONSE_OK,
|
||||
GTK_RESPONSE_CANCEL,
|
||||
-1);
|
||||
|
||||
gtk_window_set_title (GTK_WINDOW (cc), _("Select a Color"));
|
||||
|
||||
gtk_widget_pop_composite_child ();
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_dialog_response (GtkDialog *dialog,
|
||||
gint response_id)
|
||||
{
|
||||
if (response_id == GTK_RESPONSE_OK)
|
||||
{
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &color);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &color);
|
||||
}
|
||||
|
||||
g_object_set (GTK_COLOR_CHOOSER_DIALOG (dialog)->priv->chooser,
|
||||
"show-editor", FALSE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_dialog_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorChooserDialog *cd = GTK_COLOR_CHOOSER_DIALOG (object);
|
||||
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_RGBA:
|
||||
{
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_chooser_get_rgba (cc, &color);
|
||||
g_value_set_boxed (value, &color);
|
||||
}
|
||||
break;
|
||||
case PROP_USE_ALPHA:
|
||||
g_value_set_boolean (value, gtk_color_chooser_get_use_alpha (GTK_COLOR_CHOOSER (cd->priv->chooser)));
|
||||
break;
|
||||
case PROP_SHOW_EDITOR:
|
||||
{
|
||||
gboolean show_editor;
|
||||
g_object_get (cd->priv->chooser, "show-editor", &show_editor, NULL);
|
||||
g_value_set_boolean (value, show_editor);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_dialog_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorChooserDialog *cd = GTK_COLOR_CHOOSER_DIALOG (object);
|
||||
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_RGBA:
|
||||
gtk_color_chooser_set_rgba (cc, g_value_get_boxed (value));
|
||||
break;
|
||||
case PROP_USE_ALPHA:
|
||||
gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (cd->priv->chooser), g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_SHOW_EDITOR:
|
||||
g_object_set (cd->priv->chooser,
|
||||
"show-editor", g_value_get_boolean (value),
|
||||
NULL);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_dialog_class_init (GtkColorChooserDialogClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (class);
|
||||
|
||||
object_class->get_property = gtk_color_chooser_dialog_get_property;
|
||||
object_class->set_property = gtk_color_chooser_dialog_set_property;
|
||||
|
||||
dialog_class->response = gtk_color_chooser_dialog_response;
|
||||
|
||||
g_object_class_override_property (object_class, PROP_RGBA, "rgba");
|
||||
g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
|
||||
g_object_class_install_property (object_class, PROP_SHOW_EDITOR,
|
||||
g_param_spec_boolean ("show-editor", P_("Show editor"), P_("Show editor"),
|
||||
FALSE, GTK_PARAM_READWRITE));
|
||||
|
||||
|
||||
g_type_class_add_private (class, sizeof (GtkColorChooserDialogPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_dialog_get_rgba (GtkColorChooser *chooser,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
GtkColorChooserDialog *cc = GTK_COLOR_CHOOSER_DIALOG (chooser);
|
||||
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (cc->priv->chooser), color);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_dialog_set_rgba (GtkColorChooser *chooser,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
GtkColorChooserDialog *cc = GTK_COLOR_CHOOSER_DIALOG (chooser);
|
||||
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->chooser), color);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_dialog_add_palette (GtkColorChooser *chooser,
|
||||
gboolean horizontal,
|
||||
gint colors_per_line,
|
||||
gint n_colors,
|
||||
GdkRGBA *colors)
|
||||
{
|
||||
GtkColorChooserDialog *cc = GTK_COLOR_CHOOSER_DIALOG (chooser);
|
||||
|
||||
gtk_color_chooser_add_palette (GTK_COLOR_CHOOSER (cc->priv->chooser),
|
||||
horizontal, colors_per_line, n_colors, colors);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_dialog_iface_init (GtkColorChooserInterface *iface)
|
||||
{
|
||||
iface->get_rgba = gtk_color_chooser_dialog_get_rgba;
|
||||
iface->set_rgba = gtk_color_chooser_dialog_set_rgba;
|
||||
iface->add_palette = gtk_color_chooser_dialog_add_palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_color_chooser_dialog_new:
|
||||
* @title: (allow-none): Title of the dialog, or %NULL
|
||||
* @parent: (allow-none): Transient parent of the dialog, or %NULL
|
||||
*
|
||||
* Creates a new #GtkColorChooserDialog.
|
||||
*
|
||||
* Return value: a new #GtkColorChooserDialog
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_color_chooser_dialog_new (const gchar *title,
|
||||
GtkWindow *parent)
|
||||
{
|
||||
GtkColorChooserDialog *dialog;
|
||||
|
||||
dialog = g_object_new (GTK_TYPE_COLOR_CHOOSER_DIALOG,
|
||||
"title", title,
|
||||
"transient-for", parent,
|
||||
NULL);
|
||||
|
||||
return GTK_WIDGET (dialog);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __GTK_COLOR_CHOOSER_DIALOG_H__
|
||||
#define __GTK_COLOR_CHOOSER_DIALOG_H__
|
||||
|
||||
#include <gtk/gtkdialog.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_COLOR_CHOOSER_DIALOG (gtk_color_chooser_dialog_get_type ())
|
||||
#define GTK_COLOR_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_CHOOSER_DIALOG, GtkColorChooserDialog))
|
||||
#define GTK_COLOR_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_CHOOSER_DIALOG, GtkColorChooserDialogClass))
|
||||
#define GTK_IS_COLOR_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_CHOOSER_DIALOG))
|
||||
#define GTK_IS_COLOR_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_CHOOSER_DIALOG))
|
||||
#define GTK_COLOR_CHOOSER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_CHOOSER_DIALOG, GtkColorChooserDialogClass))
|
||||
|
||||
typedef struct _GtkColorChooserDialog GtkColorChooserDialog;
|
||||
typedef struct _GtkColorChooserDialogPrivate GtkColorChooserDialogPrivate;
|
||||
typedef struct _GtkColorChooserDialogClass GtkColorChooserDialogClass;
|
||||
|
||||
struct _GtkColorChooserDialog
|
||||
{
|
||||
GtkDialog parent_instance;
|
||||
|
||||
/*< private >*/
|
||||
GtkColorChooserDialogPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GtkColorChooserDialogClass
|
||||
{
|
||||
GtkDialogClass parent_class;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
};
|
||||
|
||||
GType gtk_color_chooser_dialog_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget * gtk_color_chooser_dialog_new (const gchar *title,
|
||||
GtkWindow *parent);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLOR_CHOOSER_DIALOG_H__ */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_COLOR_CHOOSER_PRIVATE_H__
|
||||
#define __GTK_COLOR_CHOOSER_PRIVATE_H__
|
||||
|
||||
#include "gtkcolorchooser.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void _gtk_color_chooser_color_activated (GtkColorChooser *chooser,
|
||||
const GdkRGBA *color);
|
||||
|
||||
cairo_pattern_t * _gtk_color_chooser_get_checkered_pattern (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* ! __GTK_COLOR_CHOOSER_PRIVATE_H__ */
|
||||
@@ -0,0 +1,803 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcolorchooserprivate.h"
|
||||
#include "gtkcolorchooserwidget.h"
|
||||
#include "gtkcoloreditorprivate.h"
|
||||
#include "gtkcolorswatchprivate.h"
|
||||
#include "gtkbox.h"
|
||||
#include "gtkgrid.h"
|
||||
#include "gtklabel.h"
|
||||
#include "gtkorientable.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtksizegroup.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/**
|
||||
* SECTION:gtkcolorchooserwidget
|
||||
* @Short_description: A widget for choosing colors
|
||||
* @Title: GtkColorChooserWidget
|
||||
* @See_also: #GtkColorChooserDialog
|
||||
*
|
||||
* The #GtkColorChooserWidget widget lets the user select a
|
||||
* color. By default, the chooser presents a prefined palette
|
||||
* of colors, plus a small number of settable custom colors.
|
||||
* It is also possible to select a different color with the
|
||||
* single-color editor. To enter the single-color editing mode,
|
||||
* use the context menu of any color of the palette, or use the
|
||||
* '+' button to add a new custom color.
|
||||
*
|
||||
* The chooser automatically remembers the last selection, as well
|
||||
* as custom colors.
|
||||
*
|
||||
* To change the initially selected color, use gtk_color_chooser_set_rgba().
|
||||
* To get the selected font use gtk_color_chooser_get_rgba().
|
||||
*
|
||||
* The #GtkColorChooserWidget is used in the #GtkColorChooserDialog
|
||||
* to provide a dialog for selecting colors.
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
|
||||
struct _GtkColorChooserWidgetPrivate
|
||||
{
|
||||
GtkWidget *palette;
|
||||
GtkWidget *editor;
|
||||
GtkSizeGroup *size_group;
|
||||
|
||||
GtkWidget *custom_label;
|
||||
GtkWidget *custom;
|
||||
|
||||
GtkWidget *button;
|
||||
GtkColorSwatch *current;
|
||||
|
||||
gboolean use_alpha;
|
||||
gboolean has_default_palette;
|
||||
|
||||
GSettings *settings;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_ZERO,
|
||||
PROP_RGBA,
|
||||
PROP_USE_ALPHA,
|
||||
PROP_SHOW_EDITOR
|
||||
};
|
||||
|
||||
static void gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkColorChooserWidget, gtk_color_chooser_widget, GTK_TYPE_BOX,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
|
||||
gtk_color_chooser_widget_iface_init))
|
||||
|
||||
static void
|
||||
select_swatch (GtkColorChooserWidget *cc,
|
||||
GtkColorSwatch *swatch)
|
||||
{
|
||||
GdkRGBA color;
|
||||
|
||||
if (cc->priv->current == swatch)
|
||||
return;
|
||||
|
||||
if (cc->priv->current != NULL)
|
||||
gtk_widget_unset_state_flags (GTK_WIDGET (cc->priv->current), GTK_STATE_FLAG_SELECTED);
|
||||
gtk_widget_set_state_flags (GTK_WIDGET (swatch), GTK_STATE_FLAG_SELECTED, FALSE);
|
||||
cc->priv->current = swatch;
|
||||
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
g_settings_set (cc->priv->settings, "selected-color", "(bdddd)",
|
||||
TRUE, color.red, color.green, color.blue, color.alpha);
|
||||
|
||||
g_object_notify (G_OBJECT (cc), "rgba");
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_activate (GtkColorSwatch *swatch,
|
||||
GtkColorChooserWidget *cc)
|
||||
{
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
_gtk_color_chooser_color_activated (GTK_COLOR_CHOOSER (cc), &color);
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_customize (GtkColorSwatch *swatch,
|
||||
GtkColorChooserWidget *cc)
|
||||
{
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
|
||||
|
||||
gtk_widget_hide (cc->priv->palette);
|
||||
gtk_widget_show (cc->priv->editor);
|
||||
g_object_notify (G_OBJECT (cc), "show-editor");
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_selected (GtkColorSwatch *swatch,
|
||||
GtkStateFlags previous,
|
||||
GtkColorChooserWidget *cc)
|
||||
{
|
||||
GtkStateFlags flags;
|
||||
|
||||
flags = gtk_widget_get_state_flags (GTK_WIDGET (swatch));
|
||||
if ((flags & GTK_STATE_FLAG_SELECTED) != (previous & GTK_STATE_FLAG_SELECTED) &&
|
||||
(flags & GTK_STATE_FLAG_SELECTED) != 0)
|
||||
select_swatch (cc, swatch);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_swatch_signals (GtkWidget *p,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_connect (p, "activate", G_CALLBACK (swatch_activate), data);
|
||||
g_signal_connect (p, "customize", G_CALLBACK (swatch_customize), data);
|
||||
g_signal_connect (p, "state-flags-changed", G_CALLBACK (swatch_selected), data);
|
||||
}
|
||||
|
||||
static void
|
||||
button_activate (GtkColorSwatch *swatch,
|
||||
GtkColorChooserWidget *cc)
|
||||
{
|
||||
/* somewhat random, makes the hairline nicely visible */
|
||||
GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };
|
||||
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
|
||||
|
||||
gtk_widget_hide (cc->priv->palette);
|
||||
gtk_widget_show (cc->priv->editor);
|
||||
g_object_notify (G_OBJECT (cc), "show-editor");
|
||||
}
|
||||
|
||||
static void
|
||||
connect_button_signals (GtkWidget *p,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_connect (p, "activate", G_CALLBACK (button_activate), data);
|
||||
}
|
||||
|
||||
static void
|
||||
save_custom_colors (GtkColorChooserWidget *cc)
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
GVariant *variant;
|
||||
GdkRGBA color;
|
||||
GList *children, *l;
|
||||
GtkWidget *child;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(dddd)"));
|
||||
|
||||
children = gtk_container_get_children (GTK_CONTAINER (cc->priv->custom));
|
||||
for (l = g_list_nth (children, 1); l != NULL; l = l->next)
|
||||
{
|
||||
child = l->data;
|
||||
if (gtk_color_swatch_get_rgba (GTK_COLOR_SWATCH (child), &color))
|
||||
g_variant_builder_add (&builder, "(dddd)",
|
||||
color.red, color.green, color.blue, color.alpha);
|
||||
}
|
||||
|
||||
variant = g_variant_builder_end (&builder);
|
||||
g_settings_set_value (cc->priv->settings, "custom-colors", variant);
|
||||
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_custom_signals (GtkWidget *p,
|
||||
gpointer data)
|
||||
{
|
||||
connect_swatch_signals (p, data);
|
||||
g_signal_connect_swapped (p, "notify::rgba",
|
||||
G_CALLBACK (save_custom_colors), data);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_set_use_alpha (GtkColorChooserWidget *cc,
|
||||
gboolean use_alpha)
|
||||
{
|
||||
GList *children, *l;
|
||||
GList *palettes, *p;
|
||||
GtkWidget *swatch;
|
||||
GtkWidget *grid;
|
||||
|
||||
cc->priv->use_alpha = use_alpha;
|
||||
gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (cc->priv->editor), use_alpha);
|
||||
|
||||
palettes = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
|
||||
for (p = palettes; p; p = p->next)
|
||||
{
|
||||
grid = p->data;
|
||||
|
||||
if (!GTK_IS_CONTAINER (grid))
|
||||
continue;
|
||||
|
||||
children = gtk_container_get_children (GTK_CONTAINER (grid));
|
||||
for (l = children; l; l = l->next)
|
||||
{
|
||||
swatch = l->data;
|
||||
gtk_color_swatch_set_use_alpha (GTK_COLOR_SWATCH (swatch), use_alpha);
|
||||
}
|
||||
g_list_free (children);
|
||||
}
|
||||
g_list_free (palettes);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (cc));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_set_show_editor (GtkColorChooserWidget *cc,
|
||||
gboolean show_editor)
|
||||
{
|
||||
if (show_editor)
|
||||
{
|
||||
GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };
|
||||
|
||||
if (cc->priv->current)
|
||||
gtk_color_swatch_get_rgba (cc->priv->current, &color);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
|
||||
}
|
||||
|
||||
gtk_widget_set_visible (cc->priv->editor, show_editor);
|
||||
gtk_widget_set_visible (cc->priv->palette, !show_editor);
|
||||
}
|
||||
|
||||
/* UI construction {{{1 */
|
||||
|
||||
static guint
|
||||
scale_round (gdouble value, gdouble scale)
|
||||
{
|
||||
value = floor (value * scale + 0.5);
|
||||
value = MAX (value, 0);
|
||||
value = MIN (value, scale);
|
||||
return (guint)value;
|
||||
}
|
||||
|
||||
gchar *
|
||||
accessible_color_name (GdkRGBA *color)
|
||||
{
|
||||
if (color->alpha < 1.0)
|
||||
return g_strdup_printf (_("Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"),
|
||||
scale_round (color->red, 100),
|
||||
scale_round (color->green, 100),
|
||||
scale_round (color->blue, 100),
|
||||
scale_round (color->alpha, 100));
|
||||
else
|
||||
return g_strdup_printf (_("Red %d%%, Green %d%%, Blue %d%%"),
|
||||
scale_round (color->red, 100),
|
||||
scale_round (color->green, 100),
|
||||
scale_round (color->blue, 100));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_palette (GtkColorChooserWidget *cc,
|
||||
gboolean horizontal,
|
||||
gint colors_per_line,
|
||||
gint n_colors,
|
||||
GdkRGBA *colors,
|
||||
const gchar **names)
|
||||
{
|
||||
GtkWidget *grid;
|
||||
GtkWidget *p;
|
||||
AtkObject *atk_obj;
|
||||
gint line, pos;
|
||||
gint i;
|
||||
gint left, right;
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_widget_set_margin_bottom (grid, 12);
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 2);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
|
||||
gtk_container_add (GTK_CONTAINER (cc->priv->palette), grid);
|
||||
|
||||
left = 0;
|
||||
right = colors_per_line - 1;
|
||||
if (gtk_widget_get_direction (GTK_WIDGET (cc)) == GTK_TEXT_DIR_RTL)
|
||||
{
|
||||
i = left;
|
||||
left = right;
|
||||
right = i;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_colors; i++)
|
||||
{
|
||||
p = gtk_color_swatch_new ();
|
||||
atk_obj = gtk_widget_get_accessible (p);
|
||||
if (names)
|
||||
{
|
||||
atk_object_set_description (atk_obj,
|
||||
g_dpgettext2 (GETTEXT_PACKAGE, "Color name", names[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *text, *name;
|
||||
|
||||
name = accessible_color_name (&colors[i]);
|
||||
text = g_strdup_printf (_("Color: %s"), name);
|
||||
atk_object_set_description (atk_obj, text);
|
||||
g_free (text);
|
||||
g_free (name);
|
||||
}
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), &colors[i]);
|
||||
connect_swatch_signals (p, cc);
|
||||
|
||||
line = i / colors_per_line;
|
||||
pos = i % colors_per_line;
|
||||
|
||||
if (horizontal)
|
||||
{
|
||||
if (pos == left)
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_LEFT);
|
||||
else if (pos == right)
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_RIGHT);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), p, pos, line, 1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos == 0)
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_TOP);
|
||||
else if (pos == colors_per_line - 1)
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (p), GTK_STYLE_CLASS_BOTTOM);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), p, line, pos, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_show_all (grid);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_default_palette (GtkColorChooserWidget *cc)
|
||||
{
|
||||
GList *children, *l;
|
||||
GtkWidget *widget;
|
||||
|
||||
if (!cc->priv->has_default_palette)
|
||||
return;
|
||||
|
||||
children = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
|
||||
for (l = children; l; l = l->next)
|
||||
{
|
||||
widget = l->data;
|
||||
if (widget == cc->priv->custom_label || widget == cc->priv->custom)
|
||||
continue;
|
||||
gtk_container_remove (GTK_CONTAINER (cc->priv->palette), widget);
|
||||
}
|
||||
g_list_free (children);
|
||||
|
||||
cc->priv->has_default_palette = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
add_default_palette (GtkColorChooserWidget *cc)
|
||||
{
|
||||
const gchar *default_colors[9][3] = {
|
||||
{ "#ef2929", "#cc0000", "#a40000" }, /* Scarlet Red */
|
||||
{ "#fcaf3e", "#f57900", "#ce5c00" }, /* Orange */
|
||||
{ "#fce94f", "#edd400", "#c4a000" }, /* Butter */
|
||||
{ "#8ae234", "#73d216", "#4e9a06" }, /* Chameleon */
|
||||
{ "#729fcf", "#3465a4", "#204a87" }, /* Sky Blue */
|
||||
{ "#ad7fa8", "#75507b", "#5c3566" }, /* Plum */
|
||||
{ "#e9b96e", "#c17d11", "#8f5902" }, /* Chocolate */
|
||||
{ "#888a85", "#555753", "#2e3436" }, /* Aluminum 1 */
|
||||
{ "#eeeeec", "#d3d7cf", "#babdb6" } /* Aluminum 2 */
|
||||
};
|
||||
const gchar *color_names[] = {
|
||||
NC_("Color name", "Light Scarlet Red"),
|
||||
NC_("Color name", "Scarlet Red"),
|
||||
NC_("Color name", "Dark Scarlet Red"),
|
||||
NC_("Color name", "Light Orange"),
|
||||
NC_("Color name", "Orange"),
|
||||
NC_("Color name", "Dark Orange"),
|
||||
NC_("Color name", "Light Butter"),
|
||||
NC_("Color name", "Butter"),
|
||||
NC_("Color name", "Dark Butter"),
|
||||
NC_("Color name", "Light Chameleon"),
|
||||
NC_("Color name", "Chameleon"),
|
||||
NC_("Color name", "Dark Chameleon"),
|
||||
NC_("Color name", "Light Sky Blue"),
|
||||
NC_("Color name", "Sky Blue"),
|
||||
NC_("Color name", "Dark Sky Blue"),
|
||||
NC_("Color name", "Light Plum"),
|
||||
NC_("Color name", "Plum"),
|
||||
NC_("Color name", "Dark Plum"),
|
||||
NC_("Color name", "Light Chocolate"),
|
||||
NC_("Color name", "Chocolate"),
|
||||
NC_("Color name", "Dark Chocolate"),
|
||||
NC_("Color name", "Light Aluminum 1"),
|
||||
NC_("Color name", "Aluminum 1"),
|
||||
NC_("Color name", "Dark Aluminum 1"),
|
||||
NC_("Color name", "Light Aluminum 2"),
|
||||
NC_("Color name", "Aluminum 2"),
|
||||
NC_("Color name", "Dark Aluminum 2")
|
||||
};
|
||||
const gchar *default_grays[9] = {
|
||||
"#000000", /* black */
|
||||
"#2e3436", /* very dark gray */
|
||||
"#555753", /* darker gray */
|
||||
"#888a85", /* dark gray */
|
||||
"#babdb6", /* medium gray */
|
||||
"#d3d7cf", /* light gray */
|
||||
"#eeeeec", /* lighter gray */
|
||||
"#f3f3f3", /* very light gray */
|
||||
"#ffffff" /* white */
|
||||
};
|
||||
const gchar *gray_names[] = {
|
||||
NC_("Color name", "Black"),
|
||||
NC_("Color name", "Very Dark Gray"),
|
||||
NC_("Color name", "Darker Gray"),
|
||||
NC_("Color name", "Dark Gray"),
|
||||
NC_("Color name", "Medium Gray"),
|
||||
NC_("Color name", "Light Gray"),
|
||||
NC_("Color name", "Lighter Gray"),
|
||||
NC_("Color name", "Very Light Gray"),
|
||||
NC_("Color name", "White")
|
||||
};
|
||||
GdkRGBA colors[9*3];
|
||||
gint i, j;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
for (j = 0; j < 3; j++)
|
||||
gdk_rgba_parse (&colors[i*3 + j], default_colors[i][j]);
|
||||
|
||||
add_palette (cc, FALSE, 3, 9*3, colors, color_names);
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
gdk_rgba_parse (&colors[i], default_grays[i]);
|
||||
|
||||
add_palette (cc, TRUE, 9, 9, colors, gray_names);
|
||||
|
||||
cc->priv->has_default_palette = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_init (GtkColorChooserWidget *cc)
|
||||
{
|
||||
GtkWidget *box;
|
||||
GtkWidget *p;
|
||||
GtkWidget *button;
|
||||
GtkWidget *label;
|
||||
gint i;
|
||||
GdkRGBA color;
|
||||
GVariant *variant;
|
||||
GVariantIter iter;
|
||||
gboolean selected;
|
||||
AtkObject *atk_obj;
|
||||
gchar *text, *name;
|
||||
|
||||
cc->priv = G_TYPE_INSTANCE_GET_PRIVATE (cc, GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidgetPrivate);
|
||||
|
||||
cc->priv->use_alpha = TRUE;
|
||||
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (cc), GTK_ORIENTATION_VERTICAL);
|
||||
cc->priv->palette = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (cc), cc->priv->palette);
|
||||
|
||||
add_default_palette (cc);
|
||||
|
||||
cc->priv->custom = box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
g_object_set (box, "margin-top", 12, NULL);
|
||||
gtk_box_pack_end (GTK_BOX (cc->priv->palette), box, FALSE, TRUE, 0);
|
||||
|
||||
/* translators: label for the custom section in the color chooser */
|
||||
cc->priv->custom_label = label = gtk_label_new (_("Custom"));
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
gtk_box_pack_end (GTK_BOX (cc->priv->palette), label, FALSE, TRUE, 0);
|
||||
|
||||
cc->priv->button = button = gtk_color_swatch_new ();
|
||||
atk_obj = gtk_widget_get_accessible (button);
|
||||
atk_object_set_role (atk_obj, ATK_ROLE_PUSH_BUTTON);
|
||||
atk_object_set_description (atk_obj, _("Create custom color"));
|
||||
connect_button_signals (button, cc);
|
||||
gtk_color_swatch_set_icon (GTK_COLOR_SWATCH (button), "list-add-symbolic");
|
||||
gtk_container_add (GTK_CONTAINER (box), button);
|
||||
|
||||
cc->priv->settings = g_settings_new_with_path ("org.gtk.Settings.ColorChooser",
|
||||
"/org/gtk/settings/color-chooser/");
|
||||
variant = g_settings_get_value (cc->priv->settings, "custom-colors");
|
||||
g_variant_iter_init (&iter, variant);
|
||||
i = 0;
|
||||
p = NULL;
|
||||
while (g_variant_iter_loop (&iter, "(dddd)", &color.red, &color.green, &color.blue, &color.alpha))
|
||||
{
|
||||
i++;
|
||||
p = gtk_color_swatch_new ();
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), &color);
|
||||
gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
|
||||
atk_obj = gtk_widget_get_accessible (p);
|
||||
name = accessible_color_name (&color);
|
||||
text = g_strdup_printf (_("Custom color %d: %s"), i, name);
|
||||
atk_object_set_description (atk_obj, text);
|
||||
g_free (text);
|
||||
g_free (name);
|
||||
connect_custom_signals (p, cc);
|
||||
gtk_container_add (GTK_CONTAINER (box), p);
|
||||
|
||||
if (i == 8)
|
||||
break;
|
||||
}
|
||||
g_variant_unref (variant);
|
||||
|
||||
cc->priv->editor = gtk_color_editor_new ();
|
||||
gtk_widget_set_halign (cc->priv->editor, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_hexpand (cc->priv->editor, TRUE);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (cc), box);
|
||||
gtk_container_add (GTK_CONTAINER (box), cc->priv->editor);
|
||||
|
||||
g_settings_get (cc->priv->settings, "selected-color", "(bdddd)",
|
||||
&selected,
|
||||
&color.red, &color.green, &color.blue, &color.alpha);
|
||||
if (selected)
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc), &color);
|
||||
|
||||
gtk_widget_show_all (GTK_WIDGET (cc));
|
||||
gtk_widget_hide (GTK_WIDGET (cc->priv->editor));
|
||||
gtk_widget_hide (GTK_WIDGET (cc));
|
||||
|
||||
gtk_widget_set_no_show_all (cc->priv->palette, TRUE);
|
||||
gtk_widget_set_no_show_all (cc->priv->editor, TRUE);
|
||||
|
||||
cc->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
|
||||
gtk_size_group_add_widget (cc->priv->size_group, cc->priv->palette);
|
||||
gtk_size_group_add_widget (cc->priv->size_group, box);
|
||||
}
|
||||
|
||||
/* GObject implementation {{{1 */
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorChooserWidget *cw = GTK_COLOR_CHOOSER_WIDGET (object);
|
||||
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_RGBA:
|
||||
{
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_chooser_get_rgba (cc, &color);
|
||||
g_value_set_boxed (value, &color);
|
||||
}
|
||||
break;
|
||||
case PROP_USE_ALPHA:
|
||||
g_value_set_boolean (value, cw->priv->use_alpha);
|
||||
break;
|
||||
case PROP_SHOW_EDITOR:
|
||||
g_value_set_boolean (value, gtk_widget_get_visible (cw->priv->editor));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_RGBA:
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc),
|
||||
g_value_get_boxed (value));
|
||||
break;
|
||||
case PROP_USE_ALPHA:
|
||||
gtk_color_chooser_widget_set_use_alpha (cc,
|
||||
g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_SHOW_EDITOR:
|
||||
gtk_color_chooser_widget_set_show_editor (cc,
|
||||
g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_finalize (GObject *object)
|
||||
{
|
||||
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (object);
|
||||
|
||||
g_object_unref (cc->priv->size_group);
|
||||
g_object_unref (cc->priv->settings);
|
||||
|
||||
G_OBJECT_CLASS (gtk_color_chooser_widget_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_class_init (GtkColorChooserWidgetClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->get_property = gtk_color_chooser_widget_get_property;
|
||||
object_class->set_property = gtk_color_chooser_widget_set_property;
|
||||
object_class->finalize = gtk_color_chooser_widget_finalize;
|
||||
|
||||
g_object_class_override_property (object_class, PROP_RGBA, "rgba");
|
||||
g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
|
||||
|
||||
/**
|
||||
* GtkColorChooserWidget:show-editor:
|
||||
*
|
||||
* The ::show-editor property is %TRUE when the color chooser
|
||||
* is showing the single-color editor. It can be set to switch
|
||||
* the color chooser into single-color editing mode.
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
g_object_class_install_property (object_class, PROP_SHOW_EDITOR,
|
||||
g_param_spec_boolean ("show-editor", P_("Show editor"), P_("Show editor"),
|
||||
FALSE, GTK_PARAM_READWRITE));
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (GtkColorChooserWidgetPrivate));
|
||||
}
|
||||
|
||||
/* GtkColorChooser implementation {{{1 */
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_get_rgba (GtkColorChooser *chooser,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
|
||||
|
||||
if (gtk_widget_get_visible (cc->priv->editor))
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), color);
|
||||
else if (cc->priv->current)
|
||||
gtk_color_swatch_get_rgba (cc->priv->current, color);
|
||||
else
|
||||
{
|
||||
color->red = 1.0;
|
||||
color->green = 1.0;
|
||||
color->blue = 1.0;
|
||||
color->alpha = 1.0;
|
||||
}
|
||||
|
||||
if (!cc->priv->use_alpha)
|
||||
color->alpha = 1.0;
|
||||
}
|
||||
|
||||
static void
|
||||
add_custom_color (GtkColorChooserWidget *cc,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
GtkWidget *last;
|
||||
GtkWidget *p;
|
||||
GList *children;
|
||||
|
||||
children = gtk_container_get_children (GTK_CONTAINER (cc->priv->custom));
|
||||
if (g_list_length (children) >= 8)
|
||||
{
|
||||
last = g_list_last (children)->data;
|
||||
gtk_widget_destroy (last);
|
||||
}
|
||||
|
||||
g_list_free (children);
|
||||
|
||||
p = gtk_color_swatch_new ();
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (p), color);
|
||||
gtk_color_swatch_set_can_drop (GTK_COLOR_SWATCH (p), TRUE);
|
||||
connect_custom_signals (p, cc);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (cc->priv->custom), p);
|
||||
gtk_box_reorder_child (GTK_BOX (cc->priv->custom), p, 1);
|
||||
gtk_widget_show (p);
|
||||
|
||||
select_swatch (cc, GTK_COLOR_SWATCH (p));
|
||||
save_custom_colors (cc);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_set_rgba (GtkColorChooser *chooser,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
|
||||
GList *children, *l;
|
||||
GList *palettes, *p;
|
||||
GtkColorSwatch *swatch;
|
||||
GtkWidget *w;
|
||||
GdkRGBA c;
|
||||
|
||||
palettes = gtk_container_get_children (GTK_CONTAINER (cc->priv->palette));
|
||||
for (p = palettes; p; p = p->next)
|
||||
{
|
||||
w = p->data;
|
||||
if (!GTK_IS_GRID (w) && !GTK_IS_BOX (w))
|
||||
continue;
|
||||
|
||||
children = gtk_container_get_children (GTK_CONTAINER (w));
|
||||
for (l = children; l; l = l->next)
|
||||
{
|
||||
swatch = l->data;
|
||||
gtk_color_swatch_get_rgba (swatch, &c);
|
||||
if (!cc->priv->use_alpha)
|
||||
c.alpha = color->alpha;
|
||||
if (gdk_rgba_equal (color, &c))
|
||||
{
|
||||
select_swatch (cc, swatch);
|
||||
g_list_free (children);
|
||||
return;
|
||||
}
|
||||
}
|
||||
g_list_free (children);
|
||||
}
|
||||
g_list_free (palettes);
|
||||
|
||||
add_custom_color (cc, color);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_add_palette (GtkColorChooser *chooser,
|
||||
gboolean horizontal,
|
||||
gint colors_per_line,
|
||||
gint n_colors,
|
||||
GdkRGBA *colors)
|
||||
{
|
||||
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (chooser);
|
||||
|
||||
remove_default_palette (cc);
|
||||
add_palette (cc, horizontal, colors_per_line, n_colors, colors, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_iface_init (GtkColorChooserInterface *iface)
|
||||
{
|
||||
iface->get_rgba = gtk_color_chooser_widget_get_rgba;
|
||||
iface->set_rgba = gtk_color_chooser_widget_set_rgba;
|
||||
iface->add_palette = gtk_color_chooser_widget_add_palette;
|
||||
}
|
||||
|
||||
/* Public API {{{1 */
|
||||
|
||||
/**
|
||||
* gtk_color_chooser_widget_new:
|
||||
*
|
||||
* Creates a new #GtkColorChooserWidget.
|
||||
*
|
||||
* Returns: a new #GtkColorChooserWidget
|
||||
*
|
||||
* Since: 3.4
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_color_chooser_widget_new (void)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_COLOR_CHOOSER_WIDGET, NULL);
|
||||
}
|
||||
|
||||
/* vim:set foldmethod=marker: */
|
||||
@@ -0,0 +1,71 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __GTK_COLOR_CHOOSER_WIDGET_H__
|
||||
#define __GTK_COLOR_CHOOSER_WIDGET_H__
|
||||
|
||||
#include <gtk/gtkbox.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_COLOR_CHOOSER_WIDGET (gtk_color_chooser_widget_get_type ())
|
||||
#define GTK_COLOR_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidget))
|
||||
#define GTK_COLOR_CHOOSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidgetClass))
|
||||
#define GTK_IS_COLOR_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_CHOOSER_WIDGET))
|
||||
#define GTK_IS_COLOR_CHOOSER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_CHOOSER_WIDGET))
|
||||
#define GTK_COLOR_CHOOSER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_CHOOSER_WIDGET, GtkColorChooserWidgetClass))
|
||||
|
||||
typedef struct _GtkColorChooserWidget GtkColorChooserWidget;
|
||||
typedef struct _GtkColorChooserWidgetPrivate GtkColorChooserWidgetPrivate;
|
||||
typedef struct _GtkColorChooserWidgetClass GtkColorChooserWidgetClass;
|
||||
|
||||
struct _GtkColorChooserWidget
|
||||
{
|
||||
GtkBox parent_instance;
|
||||
|
||||
/*< private >*/
|
||||
GtkColorChooserWidgetPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GtkColorChooserWidgetClass
|
||||
{
|
||||
GtkBoxClass parent_class;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
void (*_gtk_reserved5) (void);
|
||||
void (*_gtk_reserved6) (void);
|
||||
void (*_gtk_reserved7) (void);
|
||||
void (*_gtk_reserved8) (void);
|
||||
};
|
||||
|
||||
GType gtk_color_chooser_widget_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget * gtk_color_chooser_widget_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLOR_CHOOSER_WIDGET_H__ */
|
||||
@@ -0,0 +1,655 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* TODO
|
||||
* - touch
|
||||
* - accessible relations for popups
|
||||
* - saving per-application (?)
|
||||
* - better popup theming
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcoloreditorprivate.h"
|
||||
|
||||
#include "gtkcolorchooserprivate.h"
|
||||
#include "gtkcolorplaneprivate.h"
|
||||
#include "gtkcolorscaleprivate.h"
|
||||
#include "gtkcolorswatchprivate.h"
|
||||
#include "gtkcolorutils.h"
|
||||
#include "gtkgrid.h"
|
||||
#include "gtkorientable.h"
|
||||
#include "gtkentry.h"
|
||||
#include "gtkoverlay.h"
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtklabel.h"
|
||||
#include "gtkspinbutton.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
struct _GtkColorEditorPrivate
|
||||
{
|
||||
GtkWidget *overlay;
|
||||
GtkWidget *grid;
|
||||
GtkWidget *swatch;
|
||||
GtkWidget *entry;
|
||||
GtkWidget *h_slider;
|
||||
GtkWidget *h_popup;
|
||||
GtkWidget *h_entry;
|
||||
GtkWidget *a_slider;
|
||||
GtkWidget *a_popup;
|
||||
GtkWidget *a_entry;
|
||||
GtkWidget *sv_plane;
|
||||
GtkWidget *sv_popup;
|
||||
GtkWidget *s_entry;
|
||||
GtkWidget *v_entry;
|
||||
GtkWidget *current_popup;
|
||||
GtkWidget *popdown_focus;
|
||||
|
||||
GtkAdjustment *h_adj;
|
||||
GtkAdjustment *s_adj;
|
||||
GtkAdjustment *v_adj;
|
||||
GtkAdjustment *a_adj;
|
||||
|
||||
guint text_changed : 1;
|
||||
guint use_alpha : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_ZERO,
|
||||
PROP_RGBA,
|
||||
PROP_USE_ALPHA
|
||||
};
|
||||
|
||||
static void gtk_color_editor_iface_init (GtkColorChooserInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkColorEditor, gtk_color_editor, GTK_TYPE_BOX,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_COLOR_CHOOSER,
|
||||
gtk_color_editor_iface_init))
|
||||
|
||||
static guint
|
||||
scale_round (gdouble value, gdouble scale)
|
||||
{
|
||||
value = floor (value * scale + 0.5);
|
||||
value = MAX (value, 0);
|
||||
value = MIN (value, scale);
|
||||
return (guint)value;
|
||||
}
|
||||
|
||||
static void
|
||||
entry_set_rgba (GtkColorEditor *editor,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
gchar *text;
|
||||
|
||||
text = g_strdup_printf ("#%02X%02X%02X",
|
||||
scale_round (color->red, 255),
|
||||
scale_round (color->green, 255),
|
||||
scale_round (color->blue, 255));
|
||||
gtk_entry_set_text (GTK_ENTRY (editor->priv->entry), text);
|
||||
editor->priv->text_changed = FALSE;
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
entry_apply (GtkWidget *entry,
|
||||
GtkColorEditor *editor)
|
||||
{
|
||||
GdkRGBA color;
|
||||
gchar *text;
|
||||
|
||||
if (!editor->priv->text_changed)
|
||||
return;
|
||||
|
||||
text = gtk_editable_get_chars (GTK_EDITABLE (editor->priv->entry), 0, -1);
|
||||
if (gdk_rgba_parse (&color, text))
|
||||
{
|
||||
color.alpha = gtk_adjustment_get_value (editor->priv->a_adj);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (editor), &color);
|
||||
}
|
||||
|
||||
editor->priv->text_changed = FALSE;
|
||||
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
entry_focus_out (GtkWidget *entry,
|
||||
GdkEventFocus *event,
|
||||
GtkColorEditor *editor)
|
||||
{
|
||||
entry_apply (entry, editor);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
entry_text_changed (GtkWidget *entry,
|
||||
GParamSpec *pspec,
|
||||
GtkColorEditor *editor)
|
||||
{
|
||||
editor->priv->text_changed = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
hsv_changed (GtkColorEditor *editor)
|
||||
{
|
||||
GdkRGBA color;
|
||||
gdouble h, s, v, a;
|
||||
|
||||
h = gtk_adjustment_get_value (editor->priv->h_adj);
|
||||
s = gtk_adjustment_get_value (editor->priv->s_adj);
|
||||
v = gtk_adjustment_get_value (editor->priv->v_adj);
|
||||
a = gtk_adjustment_get_value (editor->priv->a_adj);
|
||||
|
||||
gtk_hsv_to_rgb (h, s, v, &color.red, &color.green, &color.blue);
|
||||
color.alpha = a;
|
||||
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (editor->priv->swatch), &color);
|
||||
gtk_color_scale_set_rgba (GTK_COLOR_SCALE (editor->priv->a_slider), &color);
|
||||
entry_set_rgba (editor, &color);
|
||||
|
||||
g_object_notify (G_OBJECT (editor), "rgba");
|
||||
}
|
||||
|
||||
static void
|
||||
dismiss_current_popup (GtkColorEditor *editor)
|
||||
{
|
||||
if (editor->priv->current_popup)
|
||||
{
|
||||
gtk_widget_hide (editor->priv->current_popup);
|
||||
editor->priv->current_popup = NULL;
|
||||
if (editor->priv->popdown_focus)
|
||||
{
|
||||
gtk_widget_grab_focus (editor->priv->popdown_focus);
|
||||
editor->priv->popdown_focus = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
popup_edit (GtkWidget *widget,
|
||||
GtkColorEditor *editor)
|
||||
{
|
||||
GtkWidget *popup = NULL;
|
||||
GtkWidget *toplevel;
|
||||
GtkWidget *focus;
|
||||
|
||||
if (widget == editor->priv->sv_plane)
|
||||
{
|
||||
popup = editor->priv->sv_popup;
|
||||
focus = editor->priv->s_entry;
|
||||
}
|
||||
else if (widget == editor->priv->h_slider)
|
||||
{
|
||||
popup = editor->priv->h_popup;
|
||||
focus = editor->priv->h_entry;
|
||||
}
|
||||
else if (widget == editor->priv->a_slider)
|
||||
{
|
||||
popup = editor->priv->a_popup;
|
||||
focus = editor->priv->a_entry;
|
||||
}
|
||||
|
||||
if (popup)
|
||||
{
|
||||
dismiss_current_popup (editor);
|
||||
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (editor));
|
||||
editor->priv->popdown_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
|
||||
editor->priv->current_popup = popup;
|
||||
gtk_widget_show (popup);
|
||||
gtk_widget_grab_focus (focus);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
popup_key_press (GtkWidget *popup,
|
||||
GdkEventKey *event,
|
||||
GtkColorEditor *editor)
|
||||
{
|
||||
if (event->keyval == GDK_KEY_Escape)
|
||||
{
|
||||
dismiss_current_popup (editor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_child_position (GtkOverlay *overlay,
|
||||
GtkWidget *widget,
|
||||
GtkAllocation *allocation,
|
||||
GtkColorEditor *editor)
|
||||
{
|
||||
GtkRequisition req;
|
||||
GtkAllocation alloc;
|
||||
gint s, e;
|
||||
|
||||
gtk_widget_get_preferred_size (widget, &req, NULL);
|
||||
|
||||
allocation->width = req.width;
|
||||
allocation->height = req.height;
|
||||
|
||||
if (widget == editor->priv->sv_popup)
|
||||
{
|
||||
if (gtk_widget_get_direction (GTK_WIDGET (overlay)) == GTK_TEXT_DIR_RTL)
|
||||
allocation->x = 0;
|
||||
else
|
||||
allocation->x = gtk_widget_get_allocated_width (GTK_WIDGET (overlay)) - req.width;
|
||||
allocation->y = req.height / 3;
|
||||
}
|
||||
else if (widget == editor->priv->h_popup)
|
||||
{
|
||||
gtk_widget_get_allocation (editor->priv->h_slider, &alloc);
|
||||
gtk_range_get_slider_range (GTK_RANGE (editor->priv->h_slider), &s, &e);
|
||||
|
||||
if (gtk_widget_get_direction (GTK_WIDGET (overlay)) == GTK_TEXT_DIR_RTL)
|
||||
gtk_widget_translate_coordinates (editor->priv->h_slider,
|
||||
gtk_widget_get_parent (editor->priv->grid),
|
||||
- req.width, (s + e - req.height) / 2,
|
||||
&allocation->x, &allocation->y);
|
||||
else
|
||||
gtk_widget_translate_coordinates (editor->priv->h_slider,
|
||||
gtk_widget_get_parent (editor->priv->grid),
|
||||
alloc.width, (s + e - req.height) / 2,
|
||||
&allocation->x, &allocation->y);
|
||||
}
|
||||
else if (widget == editor->priv->a_popup)
|
||||
{
|
||||
gtk_widget_get_allocation (editor->priv->a_slider, &alloc);
|
||||
gtk_range_get_slider_range (GTK_RANGE (editor->priv->a_slider), &s, &e);
|
||||
|
||||
gtk_widget_translate_coordinates (editor->priv->a_slider,
|
||||
gtk_widget_get_parent (editor->priv->grid),
|
||||
(s + e - req.width) / 2, - req.height,
|
||||
&allocation->x, &allocation->y);
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
allocation->x = CLAMP (allocation->x, 0, gtk_widget_get_allocated_width (GTK_WIDGET (overlay)) - req.width);
|
||||
allocation->y = CLAMP (allocation->y, 0, gtk_widget_get_allocated_height (GTK_WIDGET (overlay)) - req.height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
value_changed (GtkAdjustment *a,
|
||||
GtkAdjustment *as)
|
||||
{
|
||||
gdouble scale;
|
||||
|
||||
scale = gtk_adjustment_get_upper (as) / gtk_adjustment_get_upper (a);
|
||||
g_signal_handlers_block_by_func (as, value_changed, a);
|
||||
gtk_adjustment_set_value (as, gtk_adjustment_get_value (a) * scale);
|
||||
g_signal_handlers_unblock_by_func (as, value_changed, a);
|
||||
}
|
||||
|
||||
static GtkAdjustment *
|
||||
scaled_adjustment (GtkAdjustment *a,
|
||||
gdouble scale)
|
||||
{
|
||||
GtkAdjustment *as;
|
||||
|
||||
as = gtk_adjustment_new (gtk_adjustment_get_value (a) * scale,
|
||||
gtk_adjustment_get_lower (a) * scale,
|
||||
gtk_adjustment_get_upper (a) * scale,
|
||||
gtk_adjustment_get_step_increment (a) * scale,
|
||||
gtk_adjustment_get_page_increment (a) * scale,
|
||||
gtk_adjustment_get_page_size (a) * scale);
|
||||
|
||||
g_signal_connect (a, "value-changed", G_CALLBACK (value_changed), as);
|
||||
g_signal_connect (as, "value-changed", G_CALLBACK (value_changed), a);
|
||||
|
||||
return as;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
popup_draw (GtkWidget *popup,
|
||||
cairo_t *cr,
|
||||
GtkColorEditor *editor)
|
||||
{
|
||||
GtkStyleContext *context;
|
||||
gint width, height;
|
||||
|
||||
context = gtk_widget_get_style_context (popup);
|
||||
width = gtk_widget_get_allocated_width (popup);
|
||||
height = gtk_widget_get_allocated_height (popup);
|
||||
|
||||
gtk_render_background (context, cr, 0, 0, width, height);
|
||||
gtk_render_frame (context, cr, 0, 0, width, height);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_popup (GtkColorEditor *editor,
|
||||
GtkWidget *attach,
|
||||
GtkWidget *contents)
|
||||
{
|
||||
GtkWidget *popup;
|
||||
|
||||
g_object_set (contents, "margin", 12, NULL);
|
||||
|
||||
popup = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (popup), GTK_STYLE_CLASS_TOOLTIP);
|
||||
gtk_container_add (GTK_CONTAINER (popup), contents);
|
||||
|
||||
gtk_widget_show_all (contents);
|
||||
gtk_widget_set_no_show_all (popup, TRUE);
|
||||
|
||||
g_signal_connect (popup, "draw", G_CALLBACK (popup_draw), editor);
|
||||
|
||||
gtk_overlay_add_overlay (GTK_OVERLAY (editor->priv->overlay), popup);
|
||||
g_signal_connect (attach, "popup-menu", G_CALLBACK (popup_edit), editor);
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_editor_init (GtkColorEditor *editor)
|
||||
{
|
||||
GtkWidget *grid;
|
||||
GtkWidget *slider;
|
||||
GtkWidget *entry;
|
||||
GtkWidget *swatch;
|
||||
GtkAdjustment *h_adj, *s_adj, *v_adj, *a_adj;
|
||||
AtkObject *atk_obj;
|
||||
GdkRGBA transparent = { 0, 0, 0, 0 };
|
||||
|
||||
editor->priv = G_TYPE_INSTANCE_GET_PRIVATE (editor,
|
||||
GTK_TYPE_COLOR_EDITOR,
|
||||
GtkColorEditorPrivate);
|
||||
editor->priv->use_alpha = TRUE;
|
||||
|
||||
editor->priv->h_adj = h_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
|
||||
editor->priv->s_adj = s_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
|
||||
editor->priv->v_adj = v_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
|
||||
editor->priv->a_adj = a_adj = gtk_adjustment_new (0, 0, 1, 0.01, 0.1, 0);
|
||||
|
||||
g_object_ref_sink (h_adj);
|
||||
g_object_ref_sink (s_adj);
|
||||
g_object_ref_sink (v_adj);
|
||||
g_object_ref_sink (a_adj);
|
||||
|
||||
g_signal_connect_swapped (h_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
|
||||
g_signal_connect_swapped (s_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
|
||||
g_signal_connect_swapped (v_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
|
||||
g_signal_connect_swapped (a_adj, "value-changed", G_CALLBACK (hsv_changed), editor);
|
||||
|
||||
gtk_widget_push_composite_child ();
|
||||
|
||||
/* Construct the main UI */
|
||||
editor->priv->swatch = swatch = gtk_color_swatch_new ();
|
||||
gtk_color_swatch_set_selectable (GTK_COLOR_SWATCH (editor->priv->swatch), FALSE);
|
||||
gtk_widget_set_events (swatch, gtk_widget_get_events (swatch)
|
||||
& ~(GDK_BUTTON_PRESS_MASK
|
||||
| GDK_BUTTON_RELEASE_MASK
|
||||
| GDK_KEY_PRESS_MASK
|
||||
| GDK_KEY_RELEASE_MASK));
|
||||
gtk_widget_set_can_focus (swatch, FALSE);
|
||||
|
||||
editor->priv->entry = entry = gtk_entry_new ();
|
||||
atk_obj = gtk_widget_get_accessible (entry);
|
||||
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
|
||||
atk_object_set_name (atk_obj, _("Color Name"));
|
||||
g_signal_connect (entry, "activate", G_CALLBACK (entry_apply), editor);
|
||||
g_signal_connect (entry, "notify::text", G_CALLBACK (entry_text_changed), editor);
|
||||
g_signal_connect (entry, "focus-out-event", G_CALLBACK (entry_focus_out), editor);
|
||||
|
||||
editor->priv->h_slider = slider = gtk_color_scale_new (h_adj, GTK_COLOR_SCALE_HUE);
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (slider), GTK_ORIENTATION_VERTICAL);
|
||||
if (gtk_widget_get_direction (slider) == GTK_TEXT_DIR_RTL)
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (slider),
|
||||
GTK_STYLE_CLASS_SCALE_HAS_MARKS_ABOVE);
|
||||
else
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (slider),
|
||||
GTK_STYLE_CLASS_SCALE_HAS_MARKS_BELOW);
|
||||
|
||||
editor->priv->sv_plane = gtk_color_plane_new (h_adj, s_adj, v_adj);
|
||||
gtk_widget_set_size_request (editor->priv->sv_plane, 300, 300);
|
||||
|
||||
editor->priv->a_slider = slider = gtk_color_scale_new (a_adj, GTK_COLOR_SCALE_ALPHA);
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (slider), GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (slider),
|
||||
GTK_STYLE_CLASS_SCALE_HAS_MARKS_ABOVE);
|
||||
|
||||
editor->priv->grid = grid = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), editor->priv->swatch, 1, 0, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), editor->priv->entry, 2, 0, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), editor->priv->h_slider, 0, 1, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), editor->priv->sv_plane, 1, 1, 2, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), editor->priv->a_slider, 1, 2, 2, 1);
|
||||
|
||||
/* This extra margin is necessary so we have room to the sides
|
||||
* to place the popups as desired
|
||||
*/
|
||||
gtk_widget_set_margin_left (grid, 30);
|
||||
gtk_widget_set_margin_right (grid, 30);
|
||||
|
||||
editor->priv->overlay = gtk_overlay_new ();
|
||||
gtk_widget_override_background_color (editor->priv->overlay, 0, &transparent);
|
||||
gtk_container_add (GTK_CONTAINER (editor->priv->overlay), grid);
|
||||
|
||||
/* Construct the sv popup */
|
||||
editor->priv->s_entry = entry = gtk_spin_button_new (scaled_adjustment (s_adj, 100), 1, 0);
|
||||
atk_obj = gtk_widget_get_accessible (entry);
|
||||
atk_object_set_name (atk_obj, C_("Color channel", "Saturation"));
|
||||
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
|
||||
g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);
|
||||
|
||||
editor->priv->v_entry = entry = gtk_spin_button_new (scaled_adjustment (v_adj, 100), 1, 0);
|
||||
atk_obj = gtk_widget_get_accessible (entry);
|
||||
atk_object_set_name (atk_obj, C_("Color channel", "Value"));
|
||||
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
|
||||
g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "S")), 0, 0, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), editor->priv->s_entry, 1, 0, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "V")), 0, 1, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), editor->priv->v_entry, 1, 1, 1, 1);
|
||||
|
||||
editor->priv->sv_popup = create_popup (editor, editor->priv->sv_plane, grid);
|
||||
|
||||
/* Construct the h popup */
|
||||
editor->priv->h_entry = entry = gtk_spin_button_new (scaled_adjustment (h_adj, 100), 1, 0);
|
||||
atk_obj = gtk_widget_get_accessible (entry);
|
||||
atk_object_set_name (atk_obj, C_("Color channel", "Hue"));
|
||||
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
|
||||
g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "H")), 0, 0, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), editor->priv->h_entry, 1, 0, 1, 1);
|
||||
|
||||
editor->priv->h_popup = create_popup (editor, editor->priv->h_slider, grid);
|
||||
|
||||
/* Construct the a popup */
|
||||
editor->priv->a_entry = entry = gtk_spin_button_new (scaled_adjustment (a_adj, 100), 1, 0);
|
||||
atk_obj = gtk_widget_get_accessible (entry);
|
||||
atk_object_set_name (atk_obj, C_("Color channel", "Alpha"));
|
||||
atk_object_set_role (atk_obj, ATK_ROLE_ENTRY);
|
||||
g_signal_connect (entry, "key-press-event", G_CALLBACK (popup_key_press), editor);
|
||||
|
||||
grid = gtk_grid_new ();
|
||||
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (grid), gtk_label_new (C_("Color channel", "A")), 0, 0, 1, 1);
|
||||
gtk_grid_attach (GTK_GRID (grid), editor->priv->a_entry, 1, 0, 1, 1);
|
||||
|
||||
editor->priv->a_popup = create_popup (editor, editor->priv->a_slider, grid);
|
||||
|
||||
/* Hook up popup positioning */
|
||||
g_signal_connect (editor->priv->overlay, "get-child-position", G_CALLBACK (get_child_position), editor);
|
||||
g_signal_connect (editor, "notify::visible", G_CALLBACK (dismiss_current_popup), NULL);
|
||||
|
||||
gtk_widget_show_all (editor->priv->overlay);
|
||||
gtk_container_add (GTK_CONTAINER (editor), editor->priv->overlay);
|
||||
|
||||
gtk_widget_pop_composite_child ();
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_editor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorEditor *ce = GTK_COLOR_EDITOR (object);
|
||||
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_RGBA:
|
||||
{
|
||||
GdkRGBA color;
|
||||
gtk_color_chooser_get_rgba (cc, &color);
|
||||
g_value_set_boxed (value, &color);
|
||||
}
|
||||
break;
|
||||
case PROP_USE_ALPHA:
|
||||
g_value_set_boolean (value, gtk_widget_get_visible (ce->priv->a_slider));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_editor_set_use_alpha (GtkColorEditor *editor,
|
||||
gboolean use_alpha)
|
||||
{
|
||||
if (editor->priv->use_alpha != use_alpha)
|
||||
{
|
||||
editor->priv->use_alpha = use_alpha;
|
||||
gtk_widget_set_visible (editor->priv->a_slider, use_alpha);
|
||||
gtk_color_swatch_set_use_alpha (GTK_COLOR_SWATCH (editor->priv->swatch), use_alpha);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_editor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorEditor *ce = GTK_COLOR_EDITOR (object);
|
||||
GtkColorChooser *cc = GTK_COLOR_CHOOSER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_RGBA:
|
||||
gtk_color_chooser_set_rgba (cc, g_value_get_boxed (value));
|
||||
break;
|
||||
case PROP_USE_ALPHA:
|
||||
gtk_color_editor_set_use_alpha (ce, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_editor_finalize (GObject *object)
|
||||
{
|
||||
GtkColorEditor *editor = GTK_COLOR_EDITOR (object);
|
||||
|
||||
g_clear_object (&editor->priv->h_adj);
|
||||
g_clear_object (&editor->priv->s_adj);
|
||||
g_clear_object (&editor->priv->v_adj);
|
||||
g_clear_object (&editor->priv->a_adj);
|
||||
|
||||
G_OBJECT_CLASS (gtk_color_editor_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_editor_class_init (GtkColorEditorClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->finalize = gtk_color_editor_finalize;
|
||||
object_class->get_property = gtk_color_editor_get_property;
|
||||
object_class->set_property = gtk_color_editor_set_property;
|
||||
|
||||
g_object_class_override_property (object_class, PROP_RGBA, "rgba");
|
||||
g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
|
||||
|
||||
g_type_class_add_private (class, sizeof (GtkColorEditorPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_editor_get_rgba (GtkColorChooser *chooser,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser);
|
||||
gdouble h, s, v;
|
||||
|
||||
h = gtk_adjustment_get_value (editor->priv->h_adj);
|
||||
s = gtk_adjustment_get_value (editor->priv->s_adj);
|
||||
v = gtk_adjustment_get_value (editor->priv->v_adj);
|
||||
gtk_hsv_to_rgb (h, s, v, &color->red, &color->green, &color->blue);
|
||||
color->alpha = gtk_adjustment_get_value (editor->priv->a_adj);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_editor_set_rgba (GtkColorChooser *chooser,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
GtkColorEditor *editor = GTK_COLOR_EDITOR (chooser);
|
||||
gdouble h, s, v;
|
||||
|
||||
gtk_rgb_to_hsv (color->red, color->green, color->blue, &h, &s, &v);
|
||||
|
||||
gtk_adjustment_set_value (editor->priv->h_adj, h);
|
||||
gtk_adjustment_set_value (editor->priv->s_adj, s);
|
||||
gtk_adjustment_set_value (editor->priv->v_adj, v);
|
||||
gtk_adjustment_set_value (editor->priv->a_adj, color->alpha);
|
||||
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (editor->priv->swatch), color);
|
||||
gtk_color_scale_set_rgba (GTK_COLOR_SCALE (editor->priv->a_slider), color);
|
||||
entry_set_rgba (editor, color);
|
||||
|
||||
g_object_notify (G_OBJECT (editor), "rgba");
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_editor_iface_init (GtkColorChooserInterface *iface)
|
||||
{
|
||||
iface->get_rgba = gtk_color_editor_get_rgba;
|
||||
iface->set_rgba = gtk_color_editor_set_rgba;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_color_editor_new (void)
|
||||
{
|
||||
return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_EDITOR, NULL);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __GTK_COLOR_EDITOR_H__
|
||||
#define __GTK_COLOR_EDITOR_H__
|
||||
|
||||
#include <gtk/gtkbox.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_COLOR_EDITOR (gtk_color_editor_get_type ())
|
||||
#define GTK_COLOR_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_EDITOR, GtkColorEditor))
|
||||
#define GTK_COLOR_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_EDITOR, GtkColorEditorClass))
|
||||
#define GTK_IS_COLOR_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_EDITOR))
|
||||
#define GTK_IS_COLOR_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_EDITOR))
|
||||
#define GTK_COLOR_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_EDITOR, GtkColorEditorClass))
|
||||
|
||||
|
||||
typedef struct _GtkColorEditor GtkColorEditor;
|
||||
typedef struct _GtkColorEditorClass GtkColorEditorClass;
|
||||
typedef struct _GtkColorEditorPrivate GtkColorEditorPrivate;
|
||||
|
||||
struct _GtkColorEditor
|
||||
{
|
||||
GtkBox parent_instance;
|
||||
|
||||
GtkColorEditorPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GtkColorEditorClass
|
||||
{
|
||||
GtkBoxClass parent_class;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
};
|
||||
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GType gtk_color_editor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GtkWidget * gtk_color_editor_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLOR_EDITOR_H__ */
|
||||
@@ -0,0 +1,449 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcolorplaneprivate.h"
|
||||
|
||||
#include "gtkcolorutils.h"
|
||||
#include "gtkaccessible.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
struct _GtkColorPlanePrivate
|
||||
{
|
||||
GtkAdjustment *h_adj;
|
||||
GtkAdjustment *s_adj;
|
||||
GtkAdjustment *v_adj;
|
||||
|
||||
cairo_surface_t *surface;
|
||||
gboolean in_drag;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkColorPlane, gtk_color_plane, GTK_TYPE_DRAWING_AREA)
|
||||
|
||||
static void
|
||||
sv_to_xy (GtkColorPlane *plane,
|
||||
gint *x,
|
||||
gint *y)
|
||||
{
|
||||
gdouble s, v;
|
||||
gint width, height;
|
||||
|
||||
width = gtk_widget_get_allocated_width (GTK_WIDGET (plane));
|
||||
height = gtk_widget_get_allocated_height (GTK_WIDGET (plane));
|
||||
|
||||
s = gtk_adjustment_get_value (plane->priv->s_adj);
|
||||
v = gtk_adjustment_get_value (plane->priv->v_adj);
|
||||
|
||||
*x = CLAMP (width * v, 0, width - 1);
|
||||
*y = CLAMP (height * (1 - s), 0, height - 1);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plane_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
|
||||
gint x, y;
|
||||
gint width, height;
|
||||
|
||||
cairo_set_source_surface (cr, plane->priv->surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
|
||||
sv_to_xy (plane, &x, &y);
|
||||
width = gtk_widget_get_allocated_width (widget);
|
||||
height = gtk_widget_get_allocated_height (widget);
|
||||
|
||||
cairo_move_to (cr, 0, y + 0.5);
|
||||
cairo_line_to (cr, width, y + 0.5);
|
||||
|
||||
cairo_move_to (cr, x + 0.5, 0);
|
||||
cairo_line_to (cr, x + 0.5, height);
|
||||
|
||||
if (gtk_widget_has_visible_focus (widget))
|
||||
{
|
||||
cairo_set_line_width (cr, 3.0);
|
||||
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
|
||||
cairo_stroke_preserve (cr);
|
||||
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.8);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
create_surface (GtkColorPlane *plane)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (plane);
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *surface;
|
||||
gint width, height, stride;
|
||||
cairo_surface_t *tmp;
|
||||
guint red, green, blue;
|
||||
guint32 *data, *p;
|
||||
gdouble h, s, v;
|
||||
gdouble r, g, b;
|
||||
gdouble sf, vf;
|
||||
gint x, y;
|
||||
|
||||
if (!gtk_widget_get_realized (widget))
|
||||
return;
|
||||
|
||||
width = gtk_widget_get_allocated_width (widget);
|
||||
height = gtk_widget_get_allocated_height (widget);
|
||||
|
||||
surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
|
||||
CAIRO_CONTENT_COLOR,
|
||||
width, height);
|
||||
|
||||
if (plane->priv->surface)
|
||||
cairo_surface_destroy (plane->priv->surface);
|
||||
plane->priv->surface = surface;
|
||||
|
||||
if (width == 1 || height == 1)
|
||||
return;
|
||||
|
||||
stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
|
||||
|
||||
data = g_malloc (height * stride);
|
||||
|
||||
h = gtk_adjustment_get_value (plane->priv->h_adj);
|
||||
sf = 1.0 / (height - 1);
|
||||
vf = 1.0 / (width - 1);
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
s = CLAMP (1.0 - y * sf, 0.0, 1.0);
|
||||
p = data + y * (stride / 4);
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
v = x * vf;
|
||||
gtk_hsv_to_rgb (h, s, v, &r, &g, &b);
|
||||
red = CLAMP (r * 255, 0, 255);
|
||||
green = CLAMP (g * 255, 0, 255);
|
||||
blue = CLAMP (b * 255, 0, 255);
|
||||
p[x] = (red << 16) | (green << 8) | blue;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24,
|
||||
width, height, stride);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
cairo_set_source_surface (cr, tmp, 0, 0);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (tmp);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plane_configure (GtkWidget *widget,
|
||||
GdkEventConfigure *event)
|
||||
{
|
||||
create_surface (GTK_COLOR_PLANE (widget));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_cross_grab (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
guint32 time)
|
||||
{
|
||||
GdkCursor *cursor;
|
||||
|
||||
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (widget)),
|
||||
GDK_CROSSHAIR);
|
||||
gdk_device_grab (device,
|
||||
gtk_widget_get_window (widget),
|
||||
GDK_OWNERSHIP_NONE,
|
||||
FALSE,
|
||||
GDK_POINTER_MOTION_MASK
|
||||
| GDK_POINTER_MOTION_HINT_MASK
|
||||
| GDK_BUTTON_RELEASE_MASK,
|
||||
cursor,
|
||||
time);
|
||||
g_object_unref (cursor);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plane_grab_broken (GtkWidget *widget,
|
||||
GdkEventGrabBroken *event)
|
||||
{
|
||||
GTK_COLOR_PLANE (widget)->priv->in_drag = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
h_changed (GtkColorPlane *plane)
|
||||
{
|
||||
create_surface (plane);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (plane));
|
||||
}
|
||||
|
||||
static void
|
||||
sv_changed (GtkColorPlane *plane)
|
||||
{
|
||||
gtk_widget_queue_draw (GTK_WIDGET (plane));
|
||||
}
|
||||
|
||||
static void
|
||||
update_color (GtkColorPlane *plane,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (plane);
|
||||
gdouble s, v;
|
||||
|
||||
s = CLAMP (1 - y * (1.0 / gtk_widget_get_allocated_height (widget)), 0, 1);
|
||||
v = CLAMP (x * (1.0 / gtk_widget_get_allocated_width (widget)), 0, 1);
|
||||
gtk_adjustment_set_value (plane->priv->s_adj, s);
|
||||
gtk_adjustment_set_value (plane->priv->v_adj, v);
|
||||
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plane_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
|
||||
|
||||
if (event->button == GDK_BUTTON_SECONDARY)
|
||||
{
|
||||
gboolean handled;
|
||||
|
||||
g_signal_emit_by_name (widget, "popup-menu", &handled);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (plane->priv->in_drag || event->button != GDK_BUTTON_PRIMARY)
|
||||
return FALSE;
|
||||
|
||||
plane->priv->in_drag = TRUE;
|
||||
set_cross_grab (widget, gdk_event_get_device ((GdkEvent*)event), event->time);
|
||||
update_color (plane, event->x, event->y);
|
||||
gtk_widget_grab_focus (widget);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plane_button_release (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
|
||||
|
||||
if (!plane->priv->in_drag || event->button != GDK_BUTTON_PRIMARY)
|
||||
return FALSE;
|
||||
|
||||
plane->priv->in_drag = FALSE;
|
||||
|
||||
update_color (plane, event->x, event->y);
|
||||
gdk_device_ungrab (gdk_event_get_device ((GdkEvent *) event), event->time);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plane_motion_notify (GtkWidget *widget,
|
||||
GdkEventMotion *event)
|
||||
{
|
||||
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
|
||||
|
||||
if (!plane->priv->in_drag)
|
||||
return FALSE;
|
||||
|
||||
gdk_event_request_motions (event);
|
||||
update_color (plane, event->x, event->y);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sv_move (GtkColorPlane *plane,
|
||||
gdouble ds,
|
||||
gdouble dv)
|
||||
{
|
||||
gdouble s, v;
|
||||
|
||||
s = gtk_adjustment_get_value (plane->priv->s_adj);
|
||||
v = gtk_adjustment_get_value (plane->priv->v_adj);
|
||||
|
||||
if (s + ds > 1)
|
||||
{
|
||||
if (s < 1)
|
||||
s = 1;
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
else if (s + ds < 0)
|
||||
{
|
||||
if (s > 0)
|
||||
s = 0;
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
s += ds;
|
||||
}
|
||||
|
||||
if (v + dv > 1)
|
||||
{
|
||||
if (v < 1)
|
||||
v = 1;
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
else if (v + dv < 0)
|
||||
{
|
||||
if (v > 0)
|
||||
v = 0;
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
v += dv;
|
||||
}
|
||||
|
||||
gtk_adjustment_set_value (plane->priv->s_adj, s);
|
||||
gtk_adjustment_set_value (plane->priv->v_adj, v);
|
||||
return;
|
||||
|
||||
error:
|
||||
gtk_widget_error_bell (GTK_WIDGET (plane));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plane_key_press (GtkWidget *widget,
|
||||
GdkEventKey *event)
|
||||
{
|
||||
GtkColorPlane *plane = GTK_COLOR_PLANE (widget);
|
||||
gdouble step;
|
||||
|
||||
if ((event->state & GDK_MOD1_MASK) != 0)
|
||||
step = 0.1;
|
||||
else
|
||||
step = 0.01;
|
||||
|
||||
if (event->keyval == GDK_KEY_Up ||
|
||||
event->keyval == GDK_KEY_KP_Up)
|
||||
sv_move (plane, step, 0);
|
||||
else if (event->keyval == GDK_KEY_Down ||
|
||||
event->keyval == GDK_KEY_KP_Down)
|
||||
sv_move (plane, -step, 0);
|
||||
else if (event->keyval == GDK_KEY_Left ||
|
||||
event->keyval == GDK_KEY_KP_Left)
|
||||
sv_move (plane, 0, -step);
|
||||
else if (event->keyval == GDK_KEY_Right ||
|
||||
event->keyval == GDK_KEY_KP_Right)
|
||||
sv_move (plane, 0, step);
|
||||
else
|
||||
return GTK_WIDGET_CLASS (gtk_color_plane_parent_class)->key_press_event (widget, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_plane_init (GtkColorPlane *plane)
|
||||
{
|
||||
AtkObject *atk_obj;
|
||||
|
||||
plane->priv = G_TYPE_INSTANCE_GET_PRIVATE (plane,
|
||||
GTK_TYPE_COLOR_PLANE,
|
||||
GtkColorPlanePrivate);
|
||||
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (plane), TRUE);
|
||||
gtk_widget_set_events (GTK_WIDGET (plane), GDK_KEY_PRESS_MASK
|
||||
| GDK_BUTTON_PRESS_MASK
|
||||
| GDK_BUTTON_RELEASE_MASK
|
||||
| GDK_POINTER_MOTION_MASK);
|
||||
|
||||
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (plane));
|
||||
if (GTK_IS_ACCESSIBLE (atk_obj))
|
||||
{
|
||||
atk_object_set_name (atk_obj, _("Color Plane"));
|
||||
atk_object_set_role (atk_obj, ATK_ROLE_COLOR_CHOOSER);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
plane_finalize (GObject *object)
|
||||
{
|
||||
GtkColorPlane *plane = GTK_COLOR_PLANE (object);
|
||||
|
||||
if (plane->priv->surface)
|
||||
cairo_surface_destroy (plane->priv->surface);
|
||||
|
||||
g_clear_object (&plane->priv->h_adj);
|
||||
g_clear_object (&plane->priv->s_adj);
|
||||
g_clear_object (&plane->priv->v_adj);
|
||||
|
||||
G_OBJECT_CLASS (gtk_color_plane_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_plane_class_init (GtkColorPlaneClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->finalize = plane_finalize;
|
||||
|
||||
widget_class->draw = plane_draw;
|
||||
widget_class->configure_event = plane_configure;
|
||||
widget_class->button_press_event = plane_button_press;
|
||||
widget_class->button_release_event = plane_button_release;
|
||||
widget_class->motion_notify_event = plane_motion_notify;
|
||||
widget_class->grab_broken_event = plane_grab_broken;
|
||||
widget_class->key_press_event = plane_key_press;
|
||||
|
||||
g_type_class_add_private (class, sizeof (GtkColorPlanePrivate));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_color_plane_new (GtkAdjustment *h_adj,
|
||||
GtkAdjustment *s_adj,
|
||||
GtkAdjustment *v_adj)
|
||||
{
|
||||
GtkColorPlane *plane;
|
||||
|
||||
plane = (GtkColorPlane *) g_object_new (GTK_TYPE_COLOR_PLANE, NULL);
|
||||
|
||||
plane->priv->h_adj = g_object_ref_sink (h_adj);
|
||||
plane->priv->s_adj = g_object_ref_sink (s_adj);
|
||||
plane->priv->v_adj = g_object_ref_sink (v_adj);
|
||||
g_signal_connect_swapped (h_adj, "value-changed", G_CALLBACK (h_changed), plane);
|
||||
g_signal_connect_swapped (s_adj, "value-changed", G_CALLBACK (sv_changed), plane);
|
||||
g_signal_connect_swapped (v_adj, "value-changed", G_CALLBACK (sv_changed), plane);
|
||||
|
||||
return (GtkWidget *)plane;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __GTK_COLOR_PLANE_H__
|
||||
#define __GTK_COLOR_PLANE_H__
|
||||
|
||||
#include <gtk/gtkdrawingarea.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_COLOR_PLANE (gtk_color_plane_get_type ())
|
||||
#define GTK_COLOR_PLANE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_PLANE, GtkColorPlane))
|
||||
#define GTK_COLOR_PLANE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_PLANE, GtkColorPlaneClass))
|
||||
#define GTK_IS_COLOR_PLANE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_PLANE))
|
||||
#define GTK_IS_COLOR_PLANE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_PLANE))
|
||||
#define GTK_COLOR_PLANE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_PLANE, GtkColorPlaneClass))
|
||||
|
||||
|
||||
typedef struct _GtkColorPlane GtkColorPlane;
|
||||
typedef struct _GtkColorPlaneClass GtkColorPlaneClass;
|
||||
typedef struct _GtkColorPlanePrivate GtkColorPlanePrivate;
|
||||
|
||||
struct _GtkColorPlane
|
||||
{
|
||||
GtkDrawingArea parent_instance;
|
||||
|
||||
GtkColorPlanePrivate *priv;
|
||||
};
|
||||
|
||||
struct _GtkColorPlaneClass
|
||||
{
|
||||
GtkDrawingAreaClass parent_class;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
};
|
||||
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GType gtk_color_plane_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GtkWidget * gtk_color_plane_new (GtkAdjustment *h_adj,
|
||||
GtkAdjustment *s_adj,
|
||||
GtkAdjustment *v_adj);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLOR_PLANE_H__ */
|
||||
@@ -0,0 +1,362 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcolorscaleprivate.h"
|
||||
|
||||
#include "gtkcolorchooserprivate.h"
|
||||
#include "gtkcolorutils.h"
|
||||
#include "gtkorientable.h"
|
||||
#include "gtkstylecontext.h"
|
||||
#include "gtkaccessible.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
struct _GtkColorScalePrivate
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
gint width, height;
|
||||
GdkRGBA color;
|
||||
GtkColorScaleType type;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_ZERO,
|
||||
PROP_SCALE_TYPE
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkColorScale, gtk_color_scale, GTK_TYPE_SCALE)
|
||||
|
||||
static void
|
||||
gtk_color_scale_get_trough_size (GtkColorScale *scale,
|
||||
gint *x_offset_out,
|
||||
gint *y_offset_out,
|
||||
gint *width_out,
|
||||
gint *height_out)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (scale);
|
||||
gint width, height, focus_line_width, focus_padding;
|
||||
gint x_offset, y_offset;
|
||||
gint slider_width, slider_height;
|
||||
|
||||
gtk_widget_style_get (widget,
|
||||
"focus-line-width", &focus_line_width,
|
||||
"focus-padding", &focus_padding,
|
||||
"slider-width", &slider_width,
|
||||
"slider-length", &slider_height,
|
||||
NULL);
|
||||
|
||||
width = gtk_widget_get_allocated_width (widget) - 2 * (focus_line_width + focus_padding);
|
||||
height = gtk_widget_get_allocated_height (widget) - 2 * (focus_line_width + focus_padding);
|
||||
|
||||
x_offset = focus_line_width + focus_padding;
|
||||
y_offset = focus_line_width + focus_padding;
|
||||
|
||||
/* if the slider has a vertical shape, draw the trough asymmetric */
|
||||
if (slider_width > slider_height)
|
||||
{
|
||||
if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_VERTICAL)
|
||||
{
|
||||
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
|
||||
x_offset += (gint) floor (slider_width / 2.0);
|
||||
|
||||
width = (gint) floor (slider_width / 2.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
height = (gint) floor (slider_width / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
if (width_out)
|
||||
*width_out = width;
|
||||
if (height_out)
|
||||
*height_out = height;
|
||||
if (x_offset_out)
|
||||
*x_offset_out = x_offset;
|
||||
if (y_offset_out)
|
||||
*y_offset_out = y_offset;
|
||||
}
|
||||
|
||||
static void
|
||||
create_surface (GtkColorScale *scale)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (scale);
|
||||
cairo_surface_t *surface;
|
||||
gint width, height;
|
||||
|
||||
if (!gtk_widget_get_realized (widget))
|
||||
return;
|
||||
|
||||
gtk_color_scale_get_trough_size (scale,
|
||||
NULL, NULL,
|
||||
&width, &height);
|
||||
|
||||
if (!scale->priv->surface ||
|
||||
width != scale->priv->width ||
|
||||
height != scale->priv->height)
|
||||
{
|
||||
surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
|
||||
CAIRO_CONTENT_COLOR,
|
||||
width, height);
|
||||
if (scale->priv->surface)
|
||||
cairo_surface_destroy (scale->priv->surface);
|
||||
scale->priv->surface = surface;
|
||||
scale->priv->width = width;
|
||||
scale->priv->height= height;
|
||||
}
|
||||
else
|
||||
surface = scale->priv->surface;
|
||||
|
||||
if (width == 1 || height == 1)
|
||||
return;
|
||||
|
||||
if (scale->priv->type == GTK_COLOR_SCALE_HUE)
|
||||
{
|
||||
cairo_t *cr;
|
||||
gint stride;
|
||||
cairo_surface_t *tmp;
|
||||
guint red, green, blue;
|
||||
guint32 *data, *p;
|
||||
gdouble h;
|
||||
gdouble r, g, b;
|
||||
gdouble f;
|
||||
gint x, y;
|
||||
|
||||
stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
|
||||
|
||||
data = g_malloc (height * stride);
|
||||
|
||||
f = 1.0 / (height - 1);
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
h = CLAMP (y * f, 0.0, 1.0);
|
||||
p = data + y * (stride / 4);
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
gtk_hsv_to_rgb (h, 1, 1, &r, &g, &b);
|
||||
red = CLAMP (r * 255, 0, 255);
|
||||
green = CLAMP (g * 255, 0, 255);
|
||||
blue = CLAMP (b * 255, 0, 255);
|
||||
p[x] = (red << 16) | (green << 8) | blue;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = cairo_image_surface_create_for_data ((guchar *)data, CAIRO_FORMAT_RGB24,
|
||||
width, height, stride);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
cairo_set_source_surface (cr, tmp, 0, 0);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (tmp);
|
||||
g_free (data);
|
||||
}
|
||||
else if (scale->priv->type == GTK_COLOR_SCALE_ALPHA)
|
||||
{
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_matrix_t matrix;
|
||||
GdkRGBA *color;
|
||||
|
||||
cr = cairo_create (surface);
|
||||
|
||||
cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
|
||||
cairo_paint (cr);
|
||||
cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
|
||||
|
||||
pattern = _gtk_color_chooser_get_checkered_pattern ();
|
||||
cairo_matrix_init_scale (&matrix, 0.125, 0.125);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
cairo_mask (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
color = &scale->priv->color;
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, width, 0);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0, color->red, color->green, color->blue, 0);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, width, color->red, color->green, color->blue, 1);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
scale_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GtkColorScale *scale = GTK_COLOR_SCALE (widget);
|
||||
gint width, height, x_offset, y_offset;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
create_surface (scale);
|
||||
gtk_color_scale_get_trough_size (scale,
|
||||
&x_offset, &y_offset,
|
||||
&width, &height);
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_translate (cr, x_offset, y_offset);
|
||||
cairo_rectangle (cr, 0, 0, width, height);
|
||||
|
||||
pattern = cairo_pattern_create_for_surface (scale->priv->surface);
|
||||
if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_HORIZONTAL &&
|
||||
gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
cairo_matrix_init_scale (&matrix, -1, 1);
|
||||
cairo_matrix_translate (&matrix, -width, 0);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
}
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_color_scale_parent_class)->draw (widget, cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_scale_init (GtkColorScale *scale)
|
||||
{
|
||||
scale->priv = G_TYPE_INSTANCE_GET_PRIVATE (scale,
|
||||
GTK_TYPE_COLOR_SCALE,
|
||||
GtkColorScalePrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
scale_finalize (GObject *object)
|
||||
{
|
||||
GtkColorScale *scale = GTK_COLOR_SCALE (object);
|
||||
|
||||
if (scale->priv->surface)
|
||||
cairo_surface_destroy (scale->priv->surface);
|
||||
|
||||
G_OBJECT_CLASS (gtk_color_scale_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
scale_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorScale *scale = GTK_COLOR_SCALE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SCALE_TYPE:
|
||||
g_value_set_int (value, scale->priv->type);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
scale_set_type (GtkColorScale *scale,
|
||||
GtkColorScaleType type)
|
||||
{
|
||||
AtkObject *atk_obj;
|
||||
|
||||
scale->priv->type = type;
|
||||
|
||||
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (scale));
|
||||
if (GTK_IS_ACCESSIBLE (atk_obj))
|
||||
{
|
||||
if (type == GTK_COLOR_SCALE_HUE)
|
||||
atk_object_set_name (atk_obj, C_("Color channel", "Hue"));
|
||||
else if (type == GTK_COLOR_SCALE_ALPHA)
|
||||
atk_object_set_name (atk_obj, C_("Color channel", "Alpha"));
|
||||
atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (scale)), ATK_ROLE_COLOR_CHOOSER);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
scale_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorScale *scale = GTK_COLOR_SCALE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SCALE_TYPE:
|
||||
scale_set_type (scale, (GtkColorScaleType)g_value_get_int (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_scale_class_init (GtkColorScaleClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->finalize = scale_finalize;
|
||||
object_class->get_property = scale_get_property;
|
||||
object_class->set_property = scale_set_property;
|
||||
|
||||
widget_class->draw = scale_draw;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SCALE_TYPE,
|
||||
g_param_spec_int ("scale-type", P_("Scale type"), P_("Scale type"),
|
||||
0, 1, 0,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_type_class_add_private (class, sizeof (GtkColorScalePrivate));
|
||||
}
|
||||
|
||||
void
|
||||
gtk_color_scale_set_rgba (GtkColorScale *scale,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
scale->priv->color = *color;
|
||||
scale->priv->width = -1; /* force surface refresh */
|
||||
create_surface (scale);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (scale));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_color_scale_new (GtkAdjustment *adjustment,
|
||||
GtkColorScaleType type)
|
||||
{
|
||||
return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_SCALE,
|
||||
"adjustment", adjustment,
|
||||
"draw-value", FALSE,
|
||||
"scale-type", type,
|
||||
NULL);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __GTK_COLOR_SCALE_H__
|
||||
#define __GTK_COLOR_SCALE_H__
|
||||
|
||||
#include <gtk/gtkscale.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_COLOR_SCALE (gtk_color_scale_get_type ())
|
||||
#define GTK_COLOR_SCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_SCALE, GtkColorScale))
|
||||
#define GTK_COLOR_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SCALE, GtkColorScaleClass))
|
||||
#define GTK_IS_COLOR_SCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_SCALE))
|
||||
#define GTK_IS_COLOR_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_SCALE))
|
||||
#define GTK_COLOR_SCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_SCALE, GtkColorScaleClass))
|
||||
|
||||
|
||||
typedef struct _GtkColorScale GtkColorScale;
|
||||
typedef struct _GtkColorScaleClass GtkColorScaleClass;
|
||||
typedef struct _GtkColorScalePrivate GtkColorScalePrivate;
|
||||
|
||||
struct _GtkColorScale
|
||||
{
|
||||
GtkScale parent_instance;
|
||||
|
||||
GtkColorScalePrivate *priv;
|
||||
};
|
||||
|
||||
struct _GtkColorScaleClass
|
||||
{
|
||||
GtkScaleClass parent_class;
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GTK_COLOR_SCALE_HUE,
|
||||
GTK_COLOR_SCALE_ALPHA
|
||||
} GtkColorScaleType;
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GType gtk_color_scale_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GtkWidget * gtk_color_scale_new (GtkAdjustment *adjustment,
|
||||
GtkColorScaleType type);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void gtk_color_scale_set_rgba (GtkColorScale *scale,
|
||||
const GdkRGBA *color);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLOR_SCALE_H__ */
|
||||
@@ -0,0 +1,775 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcolorswatchprivate.h"
|
||||
|
||||
#include "gtkcolorchooserprivate.h"
|
||||
#include "gtkroundedboxprivate.h"
|
||||
#include "gtkthemingbackgroundprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkicontheme.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkmenu.h"
|
||||
#include "gtkmenuitem.h"
|
||||
#include "gtkmenushell.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "a11y/gtkcolorswatchaccessible.h"
|
||||
|
||||
|
||||
struct _GtkColorSwatchPrivate
|
||||
{
|
||||
GdkRGBA color;
|
||||
gdouble radius[4];
|
||||
gchar *icon;
|
||||
guint has_color : 1;
|
||||
guint contains_pointer : 1;
|
||||
guint use_alpha : 1;
|
||||
guint selectable : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_ZERO,
|
||||
PROP_RGBA,
|
||||
PROP_SELECTABLE
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ACTIVATE,
|
||||
CUSTOMIZE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
G_DEFINE_TYPE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
gtk_color_swatch_init (GtkColorSwatch *swatch)
|
||||
{
|
||||
swatch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swatch,
|
||||
GTK_TYPE_COLOR_SWATCH,
|
||||
GtkColorSwatchPrivate);
|
||||
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (swatch), TRUE);
|
||||
gtk_widget_set_events (GTK_WIDGET (swatch), GDK_BUTTON_PRESS_MASK
|
||||
| GDK_BUTTON_RELEASE_MASK
|
||||
| GDK_EXPOSURE_MASK
|
||||
| GDK_ENTER_NOTIFY_MASK
|
||||
| GDK_LEAVE_NOTIFY_MASK);
|
||||
swatch->priv->use_alpha = TRUE;
|
||||
swatch->priv->selectable = TRUE;
|
||||
}
|
||||
|
||||
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
|
||||
#define ACTIVE_BADGE_RADIUS 10
|
||||
|
||||
static gboolean
|
||||
swatch_draw (GtkWidget *widget,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GtkColorSwatch *swatch = (GtkColorSwatch*)widget;
|
||||
GtkThemingBackground background;
|
||||
gdouble width, height;
|
||||
GtkStyleContext *context;
|
||||
GtkStateFlags state;
|
||||
GtkIconTheme *theme;
|
||||
GtkIconInfo *icon_info = NULL;
|
||||
|
||||
theme = gtk_icon_theme_get_default ();
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
state = gtk_widget_get_state_flags (widget);
|
||||
width = gtk_widget_get_allocated_width (widget);
|
||||
height = gtk_widget_get_allocated_height (widget);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_set_state (context, state);
|
||||
|
||||
_gtk_theming_background_init_from_context (&background, context,
|
||||
0, 0, width, height,
|
||||
GTK_JUNCTION_NONE);
|
||||
|
||||
if (swatch->priv->has_color)
|
||||
{
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
if (swatch->priv->use_alpha)
|
||||
{
|
||||
cairo_save (cr);
|
||||
|
||||
_gtk_rounded_box_path (&background.clip_box, cr);
|
||||
cairo_clip_preserve (cr);
|
||||
|
||||
cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
|
||||
cairo_fill_preserve (cr);
|
||||
|
||||
pattern = _gtk_color_chooser_get_checkered_pattern ();
|
||||
cairo_matrix_init_scale (&matrix, 0.125, 0.125);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
|
||||
cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
|
||||
cairo_mask (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
background.bg_color = swatch->priv->color;
|
||||
}
|
||||
else
|
||||
{
|
||||
background.bg_color = swatch->priv->color;
|
||||
background.bg_color.alpha = 1.0;
|
||||
}
|
||||
|
||||
_gtk_theming_background_render (&background, cr);
|
||||
}
|
||||
else
|
||||
_gtk_theming_background_render (&background, cr);
|
||||
|
||||
gtk_render_frame (context, cr,
|
||||
0, 0, width, height);
|
||||
|
||||
if (gtk_widget_has_visible_focus (widget))
|
||||
{
|
||||
cairo_set_line_width (cr, 2);
|
||||
if (swatch->priv->has_color && INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) < 0.5)
|
||||
cairo_set_source_rgba (cr, 1., 1., 1., 0.4);
|
||||
else
|
||||
cairo_set_source_rgba (cr, 0., 0., 0., 0.4);
|
||||
_gtk_rounded_box_shrink (&background.clip_box, 3, 3, 3, 3);
|
||||
_gtk_rounded_box_path (&background.clip_box, cr);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
if (swatch->priv->icon)
|
||||
{
|
||||
icon_info = gtk_icon_theme_lookup_icon (theme, swatch->priv->icon, 16,
|
||||
GTK_ICON_LOOKUP_GENERIC_FALLBACK
|
||||
| GTK_ICON_LOOKUP_USE_BUILTIN);
|
||||
}
|
||||
else if ((state & GTK_STATE_FLAG_SELECTED) != 0)
|
||||
{
|
||||
GdkRGBA bg, border;
|
||||
GtkBorder border_width;
|
||||
GIcon *gicon;
|
||||
|
||||
gtk_style_context_add_class (context, "color-active-badge");
|
||||
_gtk_theming_background_init_from_context (&background, context,
|
||||
(width - 2 * ACTIVE_BADGE_RADIUS) / 2, (height - 2 * ACTIVE_BADGE_RADIUS) / 2,
|
||||
2 * ACTIVE_BADGE_RADIUS, 2* ACTIVE_BADGE_RADIUS,
|
||||
GTK_JUNCTION_NONE);
|
||||
|
||||
if (_gtk_theming_background_has_background_image (&background))
|
||||
{
|
||||
_gtk_theming_background_render (&background, cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_style_context_get_background_color (context, state, &bg);
|
||||
gtk_style_context_get_border_color (context, state, &border);
|
||||
gtk_style_context_get_border (context, state, &border_width);
|
||||
|
||||
cairo_new_sub_path (cr);
|
||||
cairo_arc (cr, width / 2, height / 2, ACTIVE_BADGE_RADIUS, 0, 2 * G_PI);
|
||||
cairo_close_path (cr);
|
||||
gdk_cairo_set_source_rgba (cr, &bg);
|
||||
cairo_fill_preserve (cr);
|
||||
|
||||
gdk_cairo_set_source_rgba (cr, &border);
|
||||
cairo_set_line_width (cr, border_width.left);
|
||||
cairo_stroke (cr);
|
||||
|
||||
gicon = g_themed_icon_new ("object-select-symbolic");
|
||||
/* fallback for themes that don't have object-select-symbolic */
|
||||
g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply");
|
||||
|
||||
icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16,
|
||||
GTK_ICON_LOOKUP_GENERIC_FALLBACK
|
||||
| GTK_ICON_LOOKUP_USE_BUILTIN);
|
||||
g_object_unref (gicon);
|
||||
}
|
||||
}
|
||||
|
||||
if (icon_info != NULL)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, context,
|
||||
NULL, NULL);
|
||||
|
||||
if (pixbuf != NULL)
|
||||
{
|
||||
gtk_render_icon (context, cr, pixbuf,
|
||||
(width - gdk_pixbuf_get_width (pixbuf)) / 2,
|
||||
(height - gdk_pixbuf_get_height (pixbuf)) / 2);
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
|
||||
gtk_icon_info_free (icon_info);
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
gtk_style_context_restore (context);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_set_color_icon (GdkDragContext *context,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 48, 32);
|
||||
cr = cairo_create (surface);
|
||||
gdk_cairo_set_source_rgba (cr, color);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_surface_set_device_offset (surface, -4, -4);
|
||||
gtk_drag_set_icon_surface (context, surface);
|
||||
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_drag_begin (GtkWidget *widget,
|
||||
GdkDragContext *context)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
drag_set_color_icon (context, &color);
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_drag_data_get (GtkWidget *widget,
|
||||
GdkDragContext *context,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint time)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
|
||||
guint16 vals[4];
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
|
||||
vals[0] = color.red * 0xffff;
|
||||
vals[1] = color.green * 0xffff;
|
||||
vals[2] = color.blue * 0xffff;
|
||||
vals[3] = color.alpha * 0xffff;
|
||||
|
||||
gtk_selection_data_set (selection_data,
|
||||
gdk_atom_intern_static_string ("application/x-color"),
|
||||
16, (guchar *)vals, 8);
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_drag_data_received (GtkWidget *widget,
|
||||
GdkDragContext *context,
|
||||
gint x,
|
||||
gint y,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
guint time)
|
||||
{
|
||||
gint length;
|
||||
guint16 *vals;
|
||||
GdkRGBA color;
|
||||
|
||||
length = gtk_selection_data_get_length (selection_data);
|
||||
|
||||
if (length < 0)
|
||||
return;
|
||||
|
||||
/* We accept drops with the wrong format, since the KDE color
|
||||
* chooser incorrectly drops application/x-color with format 8.
|
||||
*/
|
||||
if (length != 8)
|
||||
{
|
||||
g_warning ("Received invalid color data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vals = (guint16 *) gtk_selection_data_get_data (selection_data);
|
||||
|
||||
color.red = (gdouble)vals[0] / 0xffff;
|
||||
color.green = (gdouble)vals[1] / 0xffff;
|
||||
color.blue = (gdouble)vals[2] / 0xffff;
|
||||
color.alpha = (gdouble)vals[3] / 0xffff;
|
||||
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (widget), &color);
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_get_preferred_width (GtkWidget *widget,
|
||||
gint *min,
|
||||
gint *nat)
|
||||
{
|
||||
*min = *nat = 48;
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_get_preferred_height (GtkWidget *widget,
|
||||
gint *min,
|
||||
gint *nat)
|
||||
{
|
||||
*min = *nat = 32;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
swatch_key_press (GtkWidget *widget,
|
||||
GdkEventKey *event)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
|
||||
|
||||
if (event->keyval == GDK_KEY_space ||
|
||||
event->keyval == GDK_KEY_Return ||
|
||||
event->keyval == GDK_KEY_ISO_Enter||
|
||||
event->keyval == GDK_KEY_KP_Enter ||
|
||||
event->keyval == GDK_KEY_KP_Space)
|
||||
{
|
||||
if (swatch->priv->has_color &&
|
||||
swatch->priv->selectable &&
|
||||
(gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_SELECTED) == 0)
|
||||
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
|
||||
else
|
||||
g_signal_emit (swatch, signals[ACTIVATE], 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->key_press_event (widget, event))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
swatch_enter_notify (GtkWidget *widget,
|
||||
GdkEventCrossing *event)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
|
||||
swatch->priv->contains_pointer = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
swatch_leave_notify (GtkWidget *widget,
|
||||
GdkEventCrossing *event)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
|
||||
swatch->priv->contains_pointer = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
emit_customize (GtkColorSwatch *swatch)
|
||||
{
|
||||
g_signal_emit (swatch, signals[CUSTOMIZE], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_position_func (GtkMenu *menu,
|
||||
gint *x,
|
||||
gint *y,
|
||||
gboolean *push_in,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GtkRequisition req;
|
||||
gint root_x, root_y;
|
||||
GdkScreen *screen;
|
||||
GdkWindow *window;
|
||||
GdkRectangle monitor;
|
||||
gint monitor_num;
|
||||
|
||||
widget = GTK_WIDGET (user_data);
|
||||
g_return_if_fail (gtk_widget_get_realized (widget));
|
||||
window = gtk_widget_get_window (widget);
|
||||
|
||||
screen = gtk_widget_get_screen (widget);
|
||||
monitor_num = gdk_screen_get_monitor_at_window (screen, window);
|
||||
if (monitor_num < 0)
|
||||
monitor_num = 0;
|
||||
gtk_menu_set_monitor (menu, monitor_num);
|
||||
|
||||
gdk_window_get_origin (window, &root_x, &root_y);
|
||||
gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
|
||||
|
||||
/* Put corner of menu centered on swatch */
|
||||
*x = root_x + gtk_widget_get_allocated_width (widget) / 2;
|
||||
*y = root_y + gtk_widget_get_allocated_height (widget) / 2;
|
||||
|
||||
/* Ensure sanity */
|
||||
gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
|
||||
*x = CLAMP (*x, monitor.x, MAX (monitor.x, monitor.width - req.width));
|
||||
*y = CLAMP (*y, monitor.y, MAX (monitor.y, monitor.height - req.height));
|
||||
}
|
||||
|
||||
static void
|
||||
do_popup (GtkWidget *swatch,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkWidget *menu;
|
||||
GtkWidget *item;
|
||||
|
||||
menu = gtk_menu_new ();
|
||||
item = gtk_menu_item_new_with_mnemonic (_("_Customize"));
|
||||
gtk_menu_attach_to_widget (GTK_MENU (menu), swatch, NULL);
|
||||
|
||||
g_signal_connect_swapped (item, "activate",
|
||||
G_CALLBACK (emit_customize), swatch);
|
||||
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
gtk_widget_show_all (item);
|
||||
|
||||
if (event)
|
||||
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
|
||||
NULL, NULL, event->button, event->time);
|
||||
else
|
||||
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
|
||||
popup_position_func, swatch,
|
||||
0, gtk_get_current_event_time ());
|
||||
}
|
||||
|
||||
static gboolean
|
||||
swatch_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
|
||||
|
||||
gtk_widget_grab_focus (widget);
|
||||
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) event) &&
|
||||
swatch->priv->has_color)
|
||||
{
|
||||
do_popup (widget, event);
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->type == GDK_2BUTTON_PRESS &&
|
||||
event->button == GDK_BUTTON_PRIMARY)
|
||||
{
|
||||
g_signal_emit (swatch, signals[ACTIVATE], 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
swatch_button_release (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
|
||||
GtkStateFlags flags;
|
||||
|
||||
if (event->button == GDK_BUTTON_PRIMARY &&
|
||||
swatch->priv->contains_pointer)
|
||||
{
|
||||
flags = gtk_widget_get_state_flags (widget);
|
||||
if (!swatch->priv->has_color)
|
||||
{
|
||||
g_signal_emit (swatch, signals[ACTIVATE], 0);
|
||||
return TRUE;
|
||||
}
|
||||
else if (swatch->priv->selectable &&
|
||||
(flags & GTK_STATE_FLAG_SELECTED) == 0)
|
||||
{
|
||||
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_realize (GtkWidget *widget)
|
||||
{
|
||||
GtkAllocation allocation;
|
||||
GdkWindow *window;
|
||||
GdkWindowAttr attributes;
|
||||
gint attributes_mask;
|
||||
|
||||
gtk_widget_set_realized (widget, TRUE);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
attributes.window_type = GDK_WINDOW_CHILD;
|
||||
attributes.x = allocation.x;
|
||||
attributes.y = allocation.y;
|
||||
attributes.width = allocation.width;
|
||||
attributes.height = allocation.height;
|
||||
attributes.wclass = GDK_INPUT_OUTPUT;
|
||||
attributes.visual = gtk_widget_get_visual (widget);
|
||||
attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
|
||||
|
||||
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
|
||||
|
||||
window = gdk_window_new (gtk_widget_get_parent_window (widget),
|
||||
&attributes, attributes_mask);
|
||||
gdk_window_set_user_data (window, widget);
|
||||
gtk_widget_set_window (widget, window);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
swatch_popup_menu (GtkWidget *swatch)
|
||||
{
|
||||
do_popup (swatch, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* GObject implementation {{{1 */
|
||||
|
||||
static void
|
||||
swatch_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
|
||||
GdkRGBA color;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_RGBA:
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
g_value_set_boxed (value, &color);
|
||||
break;
|
||||
case PROP_SELECTABLE:
|
||||
g_value_set_boolean (value, gtk_color_swatch_get_selectable (swatch));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_RGBA:
|
||||
gtk_color_swatch_set_rgba (swatch, g_value_get_boxed (value));
|
||||
break;
|
||||
case PROP_SELECTABLE:
|
||||
gtk_color_swatch_set_selectable (swatch, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_finalize (GObject *object)
|
||||
{
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
|
||||
|
||||
g_free (swatch->priv->icon);
|
||||
|
||||
G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_swatch_class_init (GtkColorSwatchClass *class)
|
||||
{
|
||||
GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
|
||||
GObjectClass *object_class = (GObjectClass *)class;
|
||||
|
||||
object_class->get_property = swatch_get_property;
|
||||
object_class->set_property = swatch_set_property;
|
||||
object_class->finalize = swatch_finalize;
|
||||
|
||||
widget_class->get_preferred_width = swatch_get_preferred_width;
|
||||
widget_class->get_preferred_height = swatch_get_preferred_height;
|
||||
widget_class->draw = swatch_draw;
|
||||
widget_class->drag_begin = swatch_drag_begin;
|
||||
widget_class->drag_data_get = swatch_drag_data_get;
|
||||
widget_class->drag_data_received = swatch_drag_data_received;
|
||||
widget_class->key_press_event = swatch_key_press;
|
||||
widget_class->popup_menu = swatch_popup_menu;
|
||||
widget_class->button_press_event = swatch_button_press;
|
||||
widget_class->button_release_event = swatch_button_release;
|
||||
widget_class->enter_notify_event = swatch_enter_notify;
|
||||
widget_class->leave_notify_event = swatch_leave_notify;
|
||||
widget_class->realize = swatch_realize;
|
||||
|
||||
signals[ACTIVATE] =
|
||||
g_signal_new ("activate",
|
||||
GTK_TYPE_COLOR_SWATCH,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (GtkColorSwatchClass, activate),
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
|
||||
signals[CUSTOMIZE] =
|
||||
g_signal_new ("customize",
|
||||
GTK_TYPE_COLOR_SWATCH,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (GtkColorSwatchClass, customize),
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RGBA,
|
||||
g_param_spec_boxed ("rgba", P_("RGBA Color"), P_("Color as RGBA"),
|
||||
GDK_TYPE_RGBA, GTK_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class, PROP_SELECTABLE,
|
||||
g_param_spec_boolean ("selectable", P_("Selectable"), P_("Whether the swatch is selectable"),
|
||||
TRUE, GTK_PARAM_READWRITE));
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (GtkColorSwatchPrivate));
|
||||
|
||||
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COLOR_SWATCH_ACCESSIBLE);
|
||||
}
|
||||
|
||||
/* Public API {{{1 */
|
||||
|
||||
GtkWidget *
|
||||
gtk_color_swatch_new (void)
|
||||
{
|
||||
return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_SWATCH, NULL);
|
||||
}
|
||||
|
||||
static const GtkTargetEntry dnd_targets[] = {
|
||||
{ "application/x-color", 0 }
|
||||
};
|
||||
|
||||
void
|
||||
gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
|
||||
const GdkRGBA *color)
|
||||
{
|
||||
GtkStyleContext *context;
|
||||
|
||||
context = gtk_widget_get_style_context (GTK_WIDGET (swatch));
|
||||
|
||||
if (!swatch->priv->has_color)
|
||||
{
|
||||
gtk_drag_source_set (GTK_WIDGET (swatch),
|
||||
GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
|
||||
dnd_targets, G_N_ELEMENTS (dnd_targets),
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_style_context_remove_class (context, "color-light");
|
||||
gtk_style_context_remove_class (context, "color-dark");
|
||||
}
|
||||
|
||||
swatch->priv->has_color = TRUE;
|
||||
swatch->priv->color = *color;
|
||||
|
||||
if (INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) > 0.5)
|
||||
gtk_style_context_add_class (context, "color-light");
|
||||
else
|
||||
gtk_style_context_add_class (context, "color-dark");
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (swatch));
|
||||
g_object_notify (G_OBJECT (swatch), "rgba");
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_color_swatch_get_rgba (GtkColorSwatch *swatch,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
if (swatch->priv->has_color)
|
||||
{
|
||||
color->red = swatch->priv->color.red;
|
||||
color->green = swatch->priv->color.green;
|
||||
color->blue = swatch->priv->color.blue;
|
||||
color->alpha = swatch->priv->color.alpha;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
color->red = 1.0;
|
||||
color->green = 1.0;
|
||||
color->blue = 1.0;
|
||||
color->alpha = 1.0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gtk_color_swatch_set_icon (GtkColorSwatch *swatch,
|
||||
const gchar *icon)
|
||||
{
|
||||
swatch->priv->icon = g_strdup (icon);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (swatch));
|
||||
}
|
||||
|
||||
void
|
||||
gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
|
||||
gboolean can_drop)
|
||||
{
|
||||
if (can_drop)
|
||||
{
|
||||
gtk_drag_dest_set (GTK_WIDGET (swatch),
|
||||
GTK_DEST_DEFAULT_HIGHLIGHT |
|
||||
GTK_DEST_DEFAULT_MOTION |
|
||||
GTK_DEST_DEFAULT_DROP,
|
||||
dnd_targets, G_N_ELEMENTS (dnd_targets),
|
||||
GDK_ACTION_COPY);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_drag_dest_unset (GTK_WIDGET (swatch));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
|
||||
gboolean use_alpha)
|
||||
{
|
||||
swatch->priv->use_alpha = use_alpha;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (swatch));
|
||||
}
|
||||
|
||||
void
|
||||
gtk_color_swatch_set_selectable (GtkColorSwatch *swatch,
|
||||
gboolean selectable)
|
||||
{
|
||||
if (selectable == swatch->priv->selectable)
|
||||
return;
|
||||
|
||||
swatch->priv->selectable = selectable;
|
||||
g_object_notify (G_OBJECT (swatch), "selectable");
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_color_swatch_get_selectable (GtkColorSwatch *swatch)
|
||||
{
|
||||
return swatch->priv->selectable;
|
||||
}
|
||||
|
||||
/* vim:set foldmethod=marker: */
|
||||
@@ -0,0 +1,101 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __GTK_COLOR_SWATCH_H__
|
||||
#define __GTK_COLOR_SWATCH_H__
|
||||
|
||||
#include <gtk/gtkdrawingarea.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_COLOR_SWATCH (gtk_color_swatch_get_type ())
|
||||
#define GTK_COLOR_SWATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_COLOR_SWATCH, GtkColorSwatch))
|
||||
#define GTK_COLOR_SWATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_COLOR_SWATCH, GtkColorSwatchClass))
|
||||
#define GTK_IS_COLOR_SWATCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_COLOR_SWATCH))
|
||||
#define GTK_IS_COLOR_SWATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_COLOR_SWATCH))
|
||||
#define GTK_COLOR_SWATCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_COLOR_SWATCH, GtkColorSwatchClass))
|
||||
|
||||
|
||||
typedef struct _GtkColorSwatch GtkColorSwatch;
|
||||
typedef struct _GtkColorSwatchClass GtkColorSwatchClass;
|
||||
typedef struct _GtkColorSwatchPrivate GtkColorSwatchPrivate;
|
||||
|
||||
struct _GtkColorSwatch
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
/*< private >*/
|
||||
GtkColorSwatchPrivate *priv;
|
||||
};
|
||||
|
||||
struct _GtkColorSwatchClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
|
||||
void ( * activate) (GtkColorSwatch *swatch);
|
||||
void ( * customize) (GtkColorSwatch *swatch);
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
};
|
||||
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GType gtk_color_swatch_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GtkWidget * gtk_color_swatch_new (void);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
|
||||
const GdkRGBA *color);
|
||||
G_GNUC_INTERNAL
|
||||
gboolean gtk_color_swatch_get_rgba (GtkColorSwatch *swatch,
|
||||
GdkRGBA *color);
|
||||
G_GNUC_INTERNAL
|
||||
void gtk_color_swatch_set_hsva (GtkColorSwatch *swatch,
|
||||
gdouble h,
|
||||
gdouble s,
|
||||
gdouble v,
|
||||
gdouble a);
|
||||
G_GNUC_INTERNAL
|
||||
void gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
|
||||
gboolean can_drop);
|
||||
G_GNUC_INTERNAL
|
||||
void gtk_color_swatch_set_icon (GtkColorSwatch *swatch,
|
||||
const gchar *icon);
|
||||
G_GNUC_INTERNAL
|
||||
void gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
|
||||
gboolean use_alpha);
|
||||
G_GNUC_INTERNAL
|
||||
void gtk_color_swatch_set_selectable (GtkColorSwatch *swatch,
|
||||
gboolean selectable);
|
||||
G_GNUC_INTERNAL
|
||||
gboolean gtk_color_swatch_get_selectable (GtkColorSwatch *swatch);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLOR_SWATCH_H__ */
|
||||
@@ -0,0 +1,260 @@
|
||||
/* Color utilities
|
||||
*
|
||||
* Copyright (C) 1999 The Free Software Foundation
|
||||
*
|
||||
* Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code)
|
||||
* Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+)
|
||||
* Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gtkcolorutils.h"
|
||||
|
||||
|
||||
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
|
||||
|
||||
/* Converts from HSV to RGB */
|
||||
static void
|
||||
hsv_to_rgb (gdouble *h,
|
||||
gdouble *s,
|
||||
gdouble *v)
|
||||
{
|
||||
gdouble hue, saturation, value;
|
||||
gdouble f, p, q, t;
|
||||
|
||||
if (*s == 0.0)
|
||||
{
|
||||
*h = *v;
|
||||
*s = *v;
|
||||
*v = *v; /* heh */
|
||||
}
|
||||
else
|
||||
{
|
||||
hue = *h * 6.0;
|
||||
saturation = *s;
|
||||
value = *v;
|
||||
|
||||
if (hue == 6.0)
|
||||
hue = 0.0;
|
||||
|
||||
f = hue - (int) hue;
|
||||
p = value * (1.0 - saturation);
|
||||
q = value * (1.0 - saturation * f);
|
||||
t = value * (1.0 - saturation * (1.0 - f));
|
||||
|
||||
switch ((int) hue)
|
||||
{
|
||||
case 0:
|
||||
*h = value;
|
||||
*s = t;
|
||||
*v = p;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
*h = q;
|
||||
*s = value;
|
||||
*v = p;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
*h = p;
|
||||
*s = value;
|
||||
*v = t;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
*h = p;
|
||||
*s = q;
|
||||
*v = value;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
*h = t;
|
||||
*s = p;
|
||||
*v = value;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
*h = value;
|
||||
*s = p;
|
||||
*v = q;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Converts from RGB to HSV */
|
||||
static void
|
||||
rgb_to_hsv (gdouble *r,
|
||||
gdouble *g,
|
||||
gdouble *b)
|
||||
{
|
||||
gdouble red, green, blue;
|
||||
gdouble h, s, v;
|
||||
gdouble min, max;
|
||||
gdouble delta;
|
||||
|
||||
red = *r;
|
||||
green = *g;
|
||||
blue = *b;
|
||||
|
||||
h = 0.0;
|
||||
|
||||
if (red > green)
|
||||
{
|
||||
if (red > blue)
|
||||
max = red;
|
||||
else
|
||||
max = blue;
|
||||
|
||||
if (green < blue)
|
||||
min = green;
|
||||
else
|
||||
min = blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (green > blue)
|
||||
max = green;
|
||||
else
|
||||
max = blue;
|
||||
|
||||
if (red < blue)
|
||||
min = red;
|
||||
else
|
||||
min = blue;
|
||||
}
|
||||
|
||||
v = max;
|
||||
|
||||
if (max != 0.0)
|
||||
s = (max - min) / max;
|
||||
else
|
||||
s = 0.0;
|
||||
|
||||
if (s == 0.0)
|
||||
h = 0.0;
|
||||
else
|
||||
{
|
||||
delta = max - min;
|
||||
|
||||
if (red == max)
|
||||
h = (green - blue) / delta;
|
||||
else if (green == max)
|
||||
h = 2 + (blue - red) / delta;
|
||||
else if (blue == max)
|
||||
h = 4 + (red - green) / delta;
|
||||
|
||||
h /= 6.0;
|
||||
|
||||
if (h < 0.0)
|
||||
h += 1.0;
|
||||
else if (h > 1.0)
|
||||
h -= 1.0;
|
||||
}
|
||||
|
||||
*r = h;
|
||||
*g = s;
|
||||
*b = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_hsv_to_rgb:
|
||||
* @h: Hue
|
||||
* @s: Saturation
|
||||
* @v: Value
|
||||
* @r: (out): Return value for the red component
|
||||
* @g: (out): Return value for the green component
|
||||
* @b: (out): Return value for the blue component
|
||||
*
|
||||
* Converts a color from HSV space to RGB.
|
||||
*
|
||||
* Input values must be in the [0.0, 1.0] range;
|
||||
* output values will be in the same range.
|
||||
*
|
||||
* Since: 2.14
|
||||
*/
|
||||
void
|
||||
gtk_hsv_to_rgb (gdouble h, gdouble s, gdouble v,
|
||||
gdouble *r, gdouble *g, gdouble *b)
|
||||
{
|
||||
g_return_if_fail (h >= 0.0 && h <= 1.0);
|
||||
g_return_if_fail (s >= 0.0 && s <= 1.0);
|
||||
g_return_if_fail (v >= 0.0 && v <= 1.0);
|
||||
|
||||
hsv_to_rgb (&h, &s, &v);
|
||||
|
||||
if (r)
|
||||
*r = h;
|
||||
|
||||
if (g)
|
||||
*g = s;
|
||||
|
||||
if (b)
|
||||
*b = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_rgb_to_hsv:
|
||||
* @r: Red
|
||||
* @g: Green
|
||||
* @b: Blue
|
||||
* @h: (out): Return value for the hue component
|
||||
* @s: (out): Return value for the saturation component
|
||||
* @v: (out): Return value for the value component
|
||||
*
|
||||
* Converts a color from RGB space to HSV.
|
||||
*
|
||||
* Input values must be in the [0.0, 1.0] range;
|
||||
* output values will be in the same range.
|
||||
*
|
||||
* Since: 2.14
|
||||
*/
|
||||
void
|
||||
gtk_rgb_to_hsv (gdouble r, gdouble g, gdouble b,
|
||||
gdouble *h, gdouble *s, gdouble *v)
|
||||
{
|
||||
g_return_if_fail (r >= 0.0 && r <= 1.0);
|
||||
g_return_if_fail (g >= 0.0 && g <= 1.0);
|
||||
g_return_if_fail (b >= 0.0 && b <= 1.0);
|
||||
|
||||
rgb_to_hsv (&r, &g, &b);
|
||||
|
||||
if (h)
|
||||
*h = r;
|
||||
|
||||
if (s)
|
||||
*s = g;
|
||||
|
||||
if (v)
|
||||
*v = b;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Color utilties
|
||||
*
|
||||
* Copyright (C) 1999 The Free Software Foundation
|
||||
*
|
||||
* Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code)
|
||||
* Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+)
|
||||
* Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __GTK_COLOR_UTILS_H__
|
||||
#define __GTK_COLOR_UTILS_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gtk_hsv_to_rgb (gdouble h, gdouble s, gdouble v,
|
||||
gdouble *r, gdouble *g, gdouble *b);
|
||||
void gtk_rgb_to_hsv (gdouble r, gdouble g, gdouble b,
|
||||
gdouble *h, gdouble *s, gdouble *v);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLOR_UTILS_H__ */
|
||||
@@ -467,7 +467,7 @@ gtk_combo_box_text_prepend (GtkComboBoxText *combo_box,
|
||||
*
|
||||
* Inserts @text at @position in the list of strings stored in @combo_box.
|
||||
* If @id is non-%NULL then it is used as the ID of the row. See
|
||||
* #GtkComboBox::id-column.
|
||||
* #GtkComboBox:id-column.
|
||||
*
|
||||
* If @position is negative then @text is appended.
|
||||
*
|
||||
|
||||
+102
-27
@@ -147,6 +147,8 @@ struct _GtkEntryPrivate
|
||||
GtkShadowType shadow_type;
|
||||
GtkWidget *popup_menu;
|
||||
|
||||
GdkDevice *device;
|
||||
|
||||
GdkDevice *completion_device;
|
||||
GdkWindow *text_area;
|
||||
|
||||
@@ -481,6 +483,11 @@ static void gtk_entry_toggle_overwrite (GtkEntry *entry);
|
||||
static void gtk_entry_select_all (GtkEntry *entry);
|
||||
static void gtk_entry_real_activate (GtkEntry *entry);
|
||||
static gboolean gtk_entry_popup_menu (GtkWidget *widget);
|
||||
static gboolean gtk_entry_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
static void keymap_direction_changed (GdkKeymap *keymap,
|
||||
GtkEntry *entry);
|
||||
@@ -544,9 +551,13 @@ static void gtk_entry_paste (GtkEntry *entry,
|
||||
GdkAtom selection);
|
||||
static void gtk_entry_update_primary_selection (GtkEntry *entry);
|
||||
static void gtk_entry_do_popup (GtkEntry *entry,
|
||||
GdkEventButton *event);
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button);
|
||||
static gboolean gtk_entry_mnemonic_activate (GtkWidget *widget,
|
||||
gboolean group_cycling);
|
||||
static void gtk_entry_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed);
|
||||
static void gtk_entry_check_cursor_blink (GtkEntry *entry);
|
||||
static void gtk_entry_pend_cursor_blink (GtkEntry *entry);
|
||||
static void gtk_entry_reset_blink_time (GtkEntry *entry);
|
||||
@@ -691,6 +702,7 @@ gtk_entry_class_init (GtkEntryClass *class)
|
||||
widget_class->state_flags_changed = gtk_entry_state_flags_changed;
|
||||
widget_class->screen_changed = gtk_entry_screen_changed;
|
||||
widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
|
||||
widget_class->grab_notify = gtk_entry_grab_notify;
|
||||
|
||||
widget_class->drag_drop = gtk_entry_drag_drop;
|
||||
widget_class->drag_motion = gtk_entry_drag_motion;
|
||||
@@ -700,6 +712,7 @@ gtk_entry_class_init (GtkEntryClass *class)
|
||||
widget_class->drag_data_delete = gtk_entry_drag_data_delete;
|
||||
|
||||
widget_class->popup_menu = gtk_entry_popup_menu;
|
||||
widget_class->press_and_hold = gtk_entry_press_and_hold;
|
||||
|
||||
class->move_cursor = gtk_entry_move_cursor;
|
||||
class->insert_at_cursor = gtk_entry_insert_at_cursor;
|
||||
@@ -1392,7 +1405,7 @@ gtk_entry_class_init (GtkEntryClass *class)
|
||||
*
|
||||
* The invisible character is used when masking entry contents (in
|
||||
* \"password mode\")"). When it is not explicitly set with the
|
||||
* #GtkEntry::invisible-char property, GTK+ determines the character
|
||||
* #GtkEntry:invisible-char property, GTK+ determines the character
|
||||
* to use from a list of possible candidates, depending on availability
|
||||
* in the current font.
|
||||
*
|
||||
@@ -3810,7 +3823,8 @@ gtk_entry_button_press (GtkWidget *widget,
|
||||
gtk_entry_reset_blink_time (entry);
|
||||
|
||||
priv->button = event->button;
|
||||
|
||||
priv->device = gdk_event_get_device ((GdkEvent *) event);
|
||||
|
||||
if (!gtk_widget_has_focus (widget))
|
||||
{
|
||||
priv->in_click = TRUE;
|
||||
@@ -3822,8 +3836,10 @@ gtk_entry_button_press (GtkWidget *widget,
|
||||
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||||
{
|
||||
gtk_entry_do_popup (entry, event);
|
||||
gtk_entry_do_popup (entry, event->device,
|
||||
event->time, event->button);
|
||||
priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */
|
||||
priv->device = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -4001,9 +4017,10 @@ gtk_entry_button_release (GtkWidget *widget,
|
||||
|
||||
priv->in_drag = 0;
|
||||
}
|
||||
|
||||
|
||||
priv->button = 0;
|
||||
|
||||
priv->device = NULL;
|
||||
|
||||
gtk_entry_update_primary_selection (entry);
|
||||
|
||||
return TRUE;
|
||||
@@ -4112,7 +4129,8 @@ gtk_entry_motion_notify (GtkWidget *widget,
|
||||
|
||||
priv->in_drag = FALSE;
|
||||
priv->button = 0;
|
||||
|
||||
priv->device = NULL;
|
||||
|
||||
gtk_target_list_unref (target_list);
|
||||
}
|
||||
}
|
||||
@@ -8553,6 +8571,26 @@ gtk_entry_mnemonic_activate (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_entry_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed)
|
||||
{
|
||||
GtkEntryPrivate *priv;
|
||||
|
||||
priv = GTK_ENTRY (widget)->priv;
|
||||
|
||||
if (priv->device &&
|
||||
gtk_widget_device_is_shadowed (widget, priv->device))
|
||||
{
|
||||
/* Unset button so we don't expect
|
||||
* a button release anymore
|
||||
*/
|
||||
priv->button = 0;
|
||||
priv->device = NULL;
|
||||
priv->in_drag = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
append_action_signal (GtkEntry *entry,
|
||||
GtkWidget *menu,
|
||||
@@ -8755,15 +8793,17 @@ popup_targets_received (GtkClipboard *clipboard,
|
||||
info_entry_priv->popup_menu);
|
||||
|
||||
|
||||
if (info->device)
|
||||
if (gdk_device_get_source (info->device) != GDK_SOURCE_KEYBOARD)
|
||||
gtk_menu_popup_for_device (GTK_MENU (info_entry_priv->popup_menu),
|
||||
info->device, NULL, NULL, NULL, NULL, NULL,
|
||||
info->button, info->time);
|
||||
else
|
||||
{
|
||||
gtk_menu_popup (GTK_MENU (info_entry_priv->popup_menu), NULL, NULL,
|
||||
popup_position_func, entry,
|
||||
0, gtk_get_current_event_time ());
|
||||
gtk_menu_popup_for_device (GTK_MENU (info_entry_priv->popup_menu),
|
||||
info->device, NULL, NULL,
|
||||
popup_position_func,
|
||||
entry, NULL,
|
||||
0, info->time);
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (info_entry_priv->popup_menu), FALSE);
|
||||
}
|
||||
}
|
||||
@@ -8771,10 +8811,12 @@ popup_targets_received (GtkClipboard *clipboard,
|
||||
g_object_unref (entry);
|
||||
g_slice_free (PopupInfo, info);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_entry_do_popup (GtkEntry *entry,
|
||||
GdkEventButton *event)
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button)
|
||||
{
|
||||
PopupInfo *info = g_slice_new (PopupInfo);
|
||||
|
||||
@@ -8783,19 +8825,10 @@ gtk_entry_do_popup (GtkEntry *entry,
|
||||
* we get them, then we actually pop up the menu.
|
||||
*/
|
||||
info->entry = g_object_ref (entry);
|
||||
|
||||
if (event)
|
||||
{
|
||||
info->button = event->button;
|
||||
info->time = event->time;
|
||||
info->device = event->device;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->button = 0;
|
||||
info->time = gtk_get_current_event_time ();
|
||||
info->device = NULL;
|
||||
}
|
||||
|
||||
info->button = button;
|
||||
info->time = _time;
|
||||
info->device = device;
|
||||
|
||||
gtk_clipboard_request_contents (gtk_widget_get_clipboard (GTK_WIDGET (entry), GDK_SELECTION_CLIPBOARD),
|
||||
gdk_atom_intern_static_string ("TARGETS"),
|
||||
@@ -8806,7 +8839,49 @@ gtk_entry_do_popup (GtkEntry *entry,
|
||||
static gboolean
|
||||
gtk_entry_popup_menu (GtkWidget *widget)
|
||||
{
|
||||
gtk_entry_do_popup (GTK_ENTRY (widget), NULL);
|
||||
gtk_entry_do_popup (GTK_ENTRY (widget),
|
||||
gtk_get_current_event_device (),
|
||||
gtk_get_current_event_time (),
|
||||
0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_entry_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
if (action == GTK_PRESS_AND_HOLD_TRIGGER)
|
||||
gtk_entry_do_popup (GTK_ENTRY (widget),
|
||||
device, GDK_CURRENT_TIME, 1);
|
||||
else if (action == GTK_PRESS_AND_HOLD_QUERY)
|
||||
{
|
||||
GtkEntryPrivate *priv;
|
||||
GdkDevice *source_device;
|
||||
GdkEvent *event;
|
||||
|
||||
priv = GTK_ENTRY (widget)->priv;
|
||||
event = gtk_get_current_event ();
|
||||
|
||||
if (!event)
|
||||
return FALSE;
|
||||
|
||||
source_device = gdk_event_get_source_device (event);
|
||||
|
||||
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH ||
|
||||
(event->type != GDK_BUTTON_PRESS &&
|
||||
event->type != GDK_TOUCH_PRESS) ||
|
||||
event->button.window != priv->text_area)
|
||||
{
|
||||
gdk_event_free (event);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gdk_event_free (event);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -932,6 +932,78 @@ typedef enum {
|
||||
GTK_BORDER_STYLE_RIDGE
|
||||
} GtkBorderStyle;
|
||||
|
||||
/**
|
||||
* GtkCapturedEventFlags:
|
||||
* @GTK_CAPTURED_EVENT_NONE: Event goes uncaptured
|
||||
* @GTK_CAPTURED_EVENT_HANDLED: The event was handled
|
||||
* @GTK_CAPTURED_EVENT_STORE: Store for later propagation, see
|
||||
* gtk_widget_release_captured_events()
|
||||
*
|
||||
* Describes how an event in the #GtkWidget::captured-event handler
|
||||
* is handled.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_CAPTURED_EVENT_NONE = 0,
|
||||
GTK_CAPTURED_EVENT_HANDLED = 1 << 0,
|
||||
GTK_CAPTURED_EVENT_STORE = 1 << 1
|
||||
} GtkCapturedEventFlags;
|
||||
|
||||
/**
|
||||
* GtkKineticScrollingFlags:
|
||||
* @GTK_KINETIC_SCROLLING_NONE: No kinetic scrolling.
|
||||
* @GTK_KINETIC_SCROLLING_ENABLED: Kinetic scrolling is enabled.
|
||||
* @GTK_KINETIC_SCROLLING_CAPTURE_BUTTON_PRESS: The first button
|
||||
* press is captured by the scrolled window, and then replayed
|
||||
* if the button press is meant to go to the child widget. This
|
||||
* flag should be enabled if the child widget(s) perform
|
||||
* non-reversible actions on #GtkWidget::button-press-event.
|
||||
* If the widget does not do so, and handles
|
||||
* #GtkWidget::grab-broken-event, it might be better off without
|
||||
* this flag.
|
||||
*
|
||||
* Describes the kinetic scrolling behavior of a #GtkScrolledWindow
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_KINETIC_SCROLLING_NONE = 0,
|
||||
GTK_KINETIC_SCROLLING_ENABLED = 1 << 0,
|
||||
GTK_KINETIC_SCROLLING_CAPTURE_BUTTON_PRESS = 1 << 1
|
||||
} GtkKineticScrollingFlags;
|
||||
|
||||
/**
|
||||
* GtkGestureType:
|
||||
* @GTK_GESTURE_SWIPE_RIGHT: A swipe from left to right
|
||||
* @GTK_GESTURE_SWIPE_LEFT: A swipe from right to left
|
||||
* @GTK_GESTURE_SWIPE_UP: A swipe from bottom to top
|
||||
* @GTK_GESTURE_SWIPE_DOWN: A swipe from top to bottom
|
||||
* @GTK_GESTURE_CIRCULAR_CLOCKWISE: A circular clockwise movement
|
||||
* @GTK_GESTURE_CIRCULAR_COUNTERCLOCKWISE: A circular counterclockwise movement
|
||||
*
|
||||
* Describes the stock gestures handled by GTK+.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_GESTURE_SWIPE_RIGHT = 1,
|
||||
GTK_GESTURE_SWIPE_LEFT,
|
||||
GTK_GESTURE_SWIPE_UP,
|
||||
GTK_GESTURE_SWIPE_DOWN,
|
||||
GTK_GESTURE_CIRCULAR_CLOCKWISE,
|
||||
GTK_GESTURE_CIRCULAR_COUNTERCLOCKWISE
|
||||
} GtkGestureType;
|
||||
|
||||
/**
|
||||
* GtkGestureFlags:
|
||||
* @GTK_GESTURE_FLAG_NONE: Gesture is interpreted as-is.
|
||||
* @GTK_GESTURE_FLAG_IGNORE_INITIAL_ORIENTATION:
|
||||
* The initial orientation is ignored in comparisons,
|
||||
* so the gesture doesn't have a sense of direction,
|
||||
* this is useful for i.e. circular strokes.
|
||||
*
|
||||
* Flags accepted by gtk_gesture_new()
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_GESTURE_FLAG_NONE = 0,
|
||||
GTK_GESTURE_FLAG_IGNORE_INITIAL_ORIENTATION = 1 << 1
|
||||
} GtkGestureFlags;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
|
||||
@@ -46,12 +46,12 @@ struct _GtkFontChooserDialogPrivate
|
||||
};
|
||||
|
||||
/**
|
||||
* SECTION:gtkfontchooserdlg
|
||||
* @Short_description: A dialog box for selecting fonts
|
||||
* SECTION:gtkfontchooserdialog
|
||||
* @Short_description: A dialog for selecting fonts
|
||||
* @Title: GtkFontChooserDialog
|
||||
* @See_also: #GtkFontChooser, #GtkDialog
|
||||
*
|
||||
* The #GtkFontChooserDialog widget is a dialog box for selecting a font.
|
||||
* The #GtkFontChooserDialog widget is a dialog for selecting a font.
|
||||
* It implements the #GtkFontChooser interface.
|
||||
*
|
||||
* <refsect2 id="GtkFontChooserDialog-BUILDER-UI">
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
#include "gtkgrid.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkfontchooser
|
||||
* SECTION:gtkfontchooserwidget
|
||||
* @Short_description: A widget for selecting fonts
|
||||
* @Title: GtkFontChooserWidget
|
||||
* @See_also: #GtkFontChooserDialog
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,121 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2011 Carlos Garnacho <carlosg@gnome.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __GTK_GESTURES_INTERPRETER_H__
|
||||
#define __GTK_GESTURES_INTERPRETER_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_GESTURE (gtk_gesture_get_type ())
|
||||
#define GTK_TYPE_GESTURE_STROKE (gtk_gesture_stroke_get_type ())
|
||||
|
||||
#define GTK_TYPE_GESTURES_INTERPRETER (gtk_gestures_interpreter_get_type ())
|
||||
#define GTK_GESTURES_INTERPRETER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_GESTURES_INTERPRETER, GtkGesturesInterpreter))
|
||||
#define GTK_GESTURES_INTERPRETER_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GTK_TYPE_GESTURES_INTERPRETER, GtkGesturesInterpreterClass))
|
||||
#define GTK_IS_GESTURES_INTERPRETER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_GESTURES_INTERPRETER))
|
||||
#define GTK_IS_GESTURES_INTERPRETER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GTK_TYPE_GESTURES_INTERPRETER))
|
||||
#define GTK_GESTURES_INTERPRETER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_GESTURES_INTERPRETER, GtkGesturesInterpreterClass))
|
||||
|
||||
typedef struct _GtkGestureStroke GtkGestureStroke;
|
||||
typedef struct _GtkGesture GtkGesture;
|
||||
|
||||
typedef struct _GtkGesturesInterpreter GtkGesturesInterpreter;
|
||||
typedef struct _GtkGesturesInterpreterClass GtkGesturesInterpreterClass;
|
||||
|
||||
struct _GtkGesturesInterpreter
|
||||
{
|
||||
GObject parent_object;
|
||||
gpointer priv;
|
||||
};
|
||||
|
||||
struct _GtkGesturesInterpreterClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* events_vectorized) (GtkGesturesInterpreter *interpreter,
|
||||
GtkGesture *gesture);
|
||||
|
||||
void (* gesture_detected) (GtkGesturesInterpreter *interpreter,
|
||||
guint gesture_id,
|
||||
gdouble confidence);
|
||||
};
|
||||
|
||||
/* Gesture stroke */
|
||||
GType gtk_gesture_stroke_get_type (void) G_GNUC_CONST;
|
||||
GtkGestureStroke * gtk_gesture_stroke_new (void);
|
||||
GtkGestureStroke * gtk_gesture_stroke_copy (const GtkGestureStroke *stroke);
|
||||
void gtk_gesture_stroke_free (GtkGestureStroke *stroke);
|
||||
void gtk_gesture_stroke_append_vector (GtkGestureStroke *stroke,
|
||||
gdouble angle,
|
||||
guint length);
|
||||
|
||||
guint gtk_gesture_stroke_get_n_vectors (const GtkGestureStroke *stroke);
|
||||
gboolean gtk_gesture_stroke_get_vector (const GtkGestureStroke *stroke,
|
||||
guint n_vector,
|
||||
gdouble *angle,
|
||||
guint *length,
|
||||
gdouble *relative_length);
|
||||
/* Gesture */
|
||||
GType gtk_gesture_get_type (void) G_GNUC_CONST;
|
||||
GtkGesture * gtk_gesture_new (const GtkGestureStroke *stroke,
|
||||
GtkGestureFlags flags);
|
||||
void gtk_gesture_add_stroke (GtkGesture *gesture,
|
||||
const GtkGestureStroke *stroke,
|
||||
gint dx,
|
||||
gint dy);
|
||||
GtkGesture * gtk_gesture_copy (const GtkGesture *gesture);
|
||||
void gtk_gesture_free (GtkGesture *gesture);
|
||||
|
||||
GtkGestureFlags gtk_gesture_get_flags (const GtkGesture *gesture);
|
||||
guint gtk_gesture_get_n_strokes (const GtkGesture *gesture);
|
||||
const GtkGestureStroke * gtk_gesture_get_stroke (const GtkGesture *gesture,
|
||||
guint n_stroke,
|
||||
gint *dx,
|
||||
gint *dy);
|
||||
|
||||
guint gtk_gesture_register (const GtkGesture *gesture);
|
||||
guint gtk_gesture_register_static (const GtkGesture *gesture);
|
||||
const GtkGesture * gtk_gesture_lookup (guint gesture_id);
|
||||
|
||||
/* Gestures interpreter */
|
||||
GType gtk_gestures_interpreter_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkGesturesInterpreter * gtk_gestures_interpreter_new (void);
|
||||
|
||||
gboolean gtk_gestures_interpreter_add_gesture (GtkGesturesInterpreter *interpreter,
|
||||
guint gesture_id);
|
||||
void gtk_gestures_interpreter_remove_gesture (GtkGesturesInterpreter *interpreter,
|
||||
guint gesture_id);
|
||||
|
||||
guint gtk_gestures_interpreter_get_n_active_strokes (GtkGesturesInterpreter *interpreter);
|
||||
|
||||
gboolean gtk_gestures_interpreter_feed_event (GtkGesturesInterpreter *interpreter,
|
||||
GdkEvent *event);
|
||||
gboolean gtk_gestures_interpreter_finish (GtkGesturesInterpreter *interpreter,
|
||||
guint *gesture_id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_GESTURES_INTERPRETER_H__ */
|
||||
+9
-7
@@ -1285,12 +1285,13 @@ gtk_icon_view_realize (GtkWidget *widget)
|
||||
attributes.width = MAX (icon_view->priv->width, allocation.width);
|
||||
attributes.height = MAX (icon_view->priv->height, allocation.height);
|
||||
attributes.event_mask = (GDK_EXPOSURE_MASK |
|
||||
GDK_SCROLL_MASK |
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_PRESS_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_KEY_PRESS_MASK |
|
||||
GDK_KEY_RELEASE_MASK) |
|
||||
GDK_SCROLL_MASK |
|
||||
GDK_SMOOTH_SCROLL_MASK |
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_PRESS_MASK |
|
||||
GDK_BUTTON_RELEASE_MASK |
|
||||
GDK_KEY_PRESS_MASK |
|
||||
GDK_KEY_RELEASE_MASK) |
|
||||
gtk_widget_get_events (widget);
|
||||
|
||||
icon_view->priv->bin_window = gdk_window_new (window,
|
||||
@@ -1302,6 +1303,7 @@ gtk_icon_view_realize (GtkWidget *widget)
|
||||
gtk_style_context_save (context);
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
|
||||
gtk_style_context_set_background (context, icon_view->priv->bin_window);
|
||||
gtk_style_context_set_background (context, window);
|
||||
gtk_style_context_restore (context);
|
||||
|
||||
gdk_window_show (icon_view->priv->bin_window);
|
||||
@@ -4494,7 +4496,7 @@ gtk_icon_view_set_tooltip_query_cb (GtkWidget *widget,
|
||||
* for you. @column should be set to the column in @icon_view's model
|
||||
* containing the tooltip texts, or -1 to disable this feature.
|
||||
*
|
||||
* When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
|
||||
* When enabled, #GtkWidget:has-tooltip will be set to %TRUE and
|
||||
* @icon_view will connect a #GtkWidget::query-tooltip signal handler.
|
||||
*
|
||||
* Note that the signal handler sets the text with gtk_tooltip_set_markup(),
|
||||
|
||||
@@ -843,7 +843,6 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
|
||||
if (priv->tentative_match &&
|
||||
g_unichar_validate (priv->tentative_match))
|
||||
{
|
||||
g_print ("committing tentative match on release\n");
|
||||
gtk_im_context_simple_commit_char (context, priv->tentative_match);
|
||||
priv->compose_buffer[0] = 0;
|
||||
|
||||
|
||||
+56
-13
@@ -437,6 +437,11 @@ static void gtk_label_hierarchy_changed (GtkWidget *widget,
|
||||
static void gtk_label_screen_changed (GtkWidget *widget,
|
||||
GdkScreen *old_screen);
|
||||
static gboolean gtk_label_popup_menu (GtkWidget *widget);
|
||||
static gboolean gtk_label_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y);
|
||||
|
||||
static void gtk_label_create_window (GtkLabel *label);
|
||||
static void gtk_label_destroy_window (GtkLabel *label);
|
||||
@@ -490,7 +495,9 @@ static void gtk_label_move_cursor (GtkLabel *label,
|
||||
static void gtk_label_copy_clipboard (GtkLabel *label);
|
||||
static void gtk_label_select_all (GtkLabel *label);
|
||||
static void gtk_label_do_popup (GtkLabel *label,
|
||||
GdkEventButton *event);
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button);
|
||||
static gint gtk_label_move_forward_word (GtkLabel *label,
|
||||
gint start);
|
||||
static gint gtk_label_move_backward_word (GtkLabel *label,
|
||||
@@ -585,6 +592,7 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
widget_class->drag_data_get = gtk_label_drag_data_get;
|
||||
widget_class->grab_focus = gtk_label_grab_focus;
|
||||
widget_class->popup_menu = gtk_label_popup_menu;
|
||||
widget_class->press_and_hold = gtk_label_press_and_hold;
|
||||
widget_class->focus = gtk_label_focus;
|
||||
widget_class->get_request_mode = gtk_label_get_request_mode;
|
||||
widget_class->get_preferred_width = gtk_label_get_preferred_width;
|
||||
@@ -4638,7 +4646,8 @@ gtk_label_button_press (GtkWidget *widget,
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||||
{
|
||||
info->link_clicked = 1;
|
||||
gtk_label_do_popup (label, event);
|
||||
gtk_label_do_popup (label, event->device,
|
||||
event->time, event->button);
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->button == GDK_BUTTON_PRIMARY)
|
||||
@@ -4656,7 +4665,8 @@ gtk_label_button_press (GtkWidget *widget,
|
||||
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||||
{
|
||||
gtk_label_do_popup (label, event);
|
||||
gtk_label_do_popup (label, event->device,
|
||||
event->time, event->button);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -4921,6 +4931,8 @@ gtk_label_motion (GtkWidget *widget,
|
||||
if ((event->state & GDK_BUTTON1_MASK) == 0)
|
||||
return FALSE;
|
||||
|
||||
gdk_event_request_motions (event);
|
||||
|
||||
if (info->in_drag)
|
||||
{
|
||||
if (gtk_drag_check_threshold (widget,
|
||||
@@ -6170,14 +6182,43 @@ copy_link_activate_cb (GtkMenuItem *menu_item,
|
||||
static gboolean
|
||||
gtk_label_popup_menu (GtkWidget *widget)
|
||||
{
|
||||
gtk_label_do_popup (GTK_LABEL (widget), NULL);
|
||||
gtk_label_do_popup (GTK_LABEL (widget),
|
||||
gtk_get_current_event_device (),
|
||||
gtk_get_current_event_time (),
|
||||
0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_label_press_and_hold (GtkWidget *widget,
|
||||
GdkDevice *device,
|
||||
GtkPressAndHoldAction action,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
if (action == GTK_PRESS_AND_HOLD_TRIGGER)
|
||||
gtk_label_do_popup (GTK_LABEL (widget),
|
||||
device, GDK_CURRENT_TIME, 1);
|
||||
else if (action == GTK_PRESS_AND_HOLD_QUERY)
|
||||
{
|
||||
GdkDevice *source_device;
|
||||
GdkEvent *event;
|
||||
|
||||
event = gtk_get_current_event ();
|
||||
source_device = gdk_event_get_source_device (event);
|
||||
|
||||
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_label_do_popup (GtkLabel *label,
|
||||
GdkEventButton *event)
|
||||
GdkDevice *device,
|
||||
guint32 _time,
|
||||
guint button)
|
||||
{
|
||||
GtkLabelPrivate *priv = label->priv;
|
||||
GtkWidget *menuitem;
|
||||
@@ -6199,7 +6240,7 @@ gtk_label_do_popup (GtkLabel *label,
|
||||
have_selection =
|
||||
priv->select_info->selection_anchor != priv->select_info->selection_end;
|
||||
|
||||
if (event)
|
||||
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
|
||||
{
|
||||
if (priv->select_info->link_clicked)
|
||||
link = priv->select_info->active_link;
|
||||
@@ -6259,15 +6300,17 @@ gtk_label_do_popup (GtkLabel *label,
|
||||
|
||||
g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
|
||||
|
||||
if (event)
|
||||
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
|
||||
NULL, NULL,
|
||||
event->button, event->time);
|
||||
if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
|
||||
gtk_menu_popup_for_device (GTK_MENU (menu), device,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
button, _time);
|
||||
else
|
||||
{
|
||||
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
|
||||
popup_position_func, label,
|
||||
0, gtk_get_current_event_time ());
|
||||
gtk_menu_popup_for_device (GTK_MENU (menu),
|
||||
device, NULL, NULL,
|
||||
popup_position_func,
|
||||
label, NULL,
|
||||
0, _time);
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -894,7 +894,8 @@ gtk_layout_realize (GtkWidget *widget)
|
||||
attributes.y = - gtk_adjustment_get_value (priv->vadjustment);
|
||||
attributes.width = MAX (priv->width, allocation.width);
|
||||
attributes.height = MAX (priv->height, allocation.height);
|
||||
attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK |
|
||||
attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK |
|
||||
GDK_SMOOTH_SCROLL_MASK |
|
||||
gtk_widget_get_events (widget);
|
||||
|
||||
priv->bin_window = gdk_window_new (window,
|
||||
|
||||
+210
-83
@@ -1332,11 +1332,14 @@ rewrite_event_for_window (GdkEvent *event,
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
rewrite_events_translate (event->any.window,
|
||||
new_window,
|
||||
&event->button.x, &event->button.y);
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
rewrite_events_translate (event->any.window,
|
||||
new_window,
|
||||
&event->motion.x, &event->motion.y);
|
||||
@@ -1386,6 +1389,9 @@ rewrite_event_for_grabs (GdkEvent *event)
|
||||
case GDK_PROXIMITY_OUT:
|
||||
case GDK_KEY_PRESS:
|
||||
case GDK_KEY_RELEASE:
|
||||
case GDK_TOUCH_PRESS:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
case GDK_TOUCH_MOTION:
|
||||
display = gdk_window_get_display (event->any.window);
|
||||
device = gdk_event_get_device (event);
|
||||
|
||||
@@ -1473,6 +1479,7 @@ gtk_main_do_event (GdkEvent *event)
|
||||
{
|
||||
GtkWidget *event_widget;
|
||||
GtkWidget *grab_widget = NULL;
|
||||
GtkWidget *topmost_widget = NULL;
|
||||
GtkWindowGroup *window_group;
|
||||
GdkEvent *rewritten_event = NULL;
|
||||
GdkDevice *device;
|
||||
@@ -1532,6 +1539,14 @@ gtk_main_do_event (GdkEvent *event)
|
||||
if (!grab_widget)
|
||||
grab_widget = gtk_window_group_get_current_grab (window_group);
|
||||
|
||||
/* Find out the topmost widget where captured event propagation
|
||||
* should start, which is the widget holding the GTK+ grab
|
||||
* if any, otherwise it's left NULL and events are emitted
|
||||
* from the toplevel (or topmost parentless parent).
|
||||
*/
|
||||
if (grab_widget)
|
||||
topmost_widget = grab_widget;
|
||||
|
||||
/* If the grab widget is an ancestor of the event widget
|
||||
* then we send the event to the original event widget.
|
||||
* This is the key to implementing modality.
|
||||
@@ -1628,14 +1643,28 @@ gtk_main_do_event (GdkEvent *event)
|
||||
case GDK_WINDOW_STATE:
|
||||
case GDK_GRAB_BROKEN:
|
||||
case GDK_DAMAGE:
|
||||
gtk_widget_event (event_widget, event);
|
||||
if (!_gtk_widget_captured_event (event_widget, event))
|
||||
gtk_widget_event (event_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_SCROLL:
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
case GDK_TOUCH_PRESS:
|
||||
if ((event->type == GDK_BUTTON_PRESS ||
|
||||
event->type == GDK_TOUCH_PRESS) &&
|
||||
event->button.button == 1)
|
||||
{
|
||||
/* Handle press and hold on the grab widget before propagating up,
|
||||
* so a parent capturing events doesn't delay nor prevent a child
|
||||
* from doing the press-and-hold action.
|
||||
*/
|
||||
_gtk_widget_press_and_hold_check_start (grab_widget, &event->button);
|
||||
}
|
||||
|
||||
if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_KEY_PRESS:
|
||||
@@ -1684,22 +1713,43 @@ gtk_main_do_event (GdkEvent *event)
|
||||
case GDK_BUTTON_RELEASE:
|
||||
case GDK_PROXIMITY_IN:
|
||||
case GDK_PROXIMITY_OUT:
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
case GDK_TOUCH_MOTION:
|
||||
case GDK_TOUCH_RELEASE:
|
||||
case GDK_MULTITOUCH_ADDED:
|
||||
case GDK_MULTITOUCH_REMOVED:
|
||||
case GDK_MULTITOUCH_UPDATED:
|
||||
if ((event->type == GDK_BUTTON_RELEASE ||
|
||||
event->type == GDK_TOUCH_RELEASE) &&
|
||||
event->button.button == 1)
|
||||
_gtk_widget_press_and_hold_check_cancel (grab_widget, &event->button);
|
||||
else if (event->type == GDK_MOTION_NOTIFY ||
|
||||
event->type == GDK_TOUCH_MOTION)
|
||||
_gtk_widget_press_and_hold_check_threshold (grab_widget,
|
||||
&event->motion);
|
||||
|
||||
if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_propagate_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_ENTER_NOTIFY:
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
event->any.window);
|
||||
if (gtk_widget_is_sensitive (grab_widget))
|
||||
if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
|
||||
event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
event->any.window);
|
||||
if (gtk_widget_is_sensitive (grab_widget) &&
|
||||
!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_widget_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
NULL);
|
||||
if (gtk_widget_is_sensitive (grab_widget))
|
||||
if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
|
||||
event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
|
||||
_gtk_widget_set_device_window (event_widget,
|
||||
gdk_event_get_device (event),
|
||||
NULL);
|
||||
if (gtk_widget_is_sensitive (grab_widget) &&
|
||||
!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
|
||||
gtk_widget_event (grab_widget, event);
|
||||
break;
|
||||
|
||||
@@ -1727,11 +1777,22 @@ gtk_main_do_event (GdkEvent *event)
|
||||
|| event->type == GDK_DRAG_ENTER
|
||||
|| event->type == GDK_GRAB_BROKEN
|
||||
|| event->type == GDK_MOTION_NOTIFY
|
||||
|| event->type == GDK_TOUCH_MOTION
|
||||
|| event->type == GDK_SCROLL)
|
||||
{
|
||||
_gtk_tooltip_handle_event (event);
|
||||
}
|
||||
|
||||
/* Handle gestures for touch events */
|
||||
if (gdk_event_get_touch_id (event, NULL))
|
||||
{
|
||||
_gtk_widget_gesture_stroke (grab_widget, event);
|
||||
|
||||
if (event->type == GDK_BUTTON_RELEASE ||
|
||||
event->type == GDK_TOUCH_RELEASE)
|
||||
_gtk_widget_gesture_finish (grab_widget);
|
||||
}
|
||||
|
||||
tmp_list = current_events;
|
||||
current_events = g_list_remove_link (current_events, tmp_list);
|
||||
g_list_free_1 (tmp_list);
|
||||
@@ -2329,6 +2390,135 @@ gtk_get_event_widget (GdkEvent *event)
|
||||
return widget;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
propagate_event_up (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
gboolean handled_event = FALSE;
|
||||
|
||||
/* Propagate event up the widget tree so that
|
||||
* parents can see the button and motion
|
||||
* events of the children.
|
||||
*/
|
||||
while (TRUE)
|
||||
{
|
||||
GtkWidget *tmp;
|
||||
|
||||
g_object_ref (widget);
|
||||
|
||||
/* Scroll events are special cased here because it
|
||||
* feels wrong when scrolling a GtkViewport, say,
|
||||
* to have children of the viewport eat the scroll
|
||||
* event
|
||||
*/
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
handled_event = event->type != GDK_SCROLL;
|
||||
else
|
||||
handled_event = gtk_widget_event (widget, event);
|
||||
|
||||
tmp = gtk_widget_get_parent (widget);
|
||||
g_object_unref (widget);
|
||||
|
||||
if (widget == topmost)
|
||||
break;
|
||||
|
||||
widget = tmp;
|
||||
|
||||
if (handled_event || !widget)
|
||||
break;
|
||||
}
|
||||
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
propagate_event_down (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
gint handled_event = FALSE;
|
||||
GList *widgets = NULL;
|
||||
GList *l;
|
||||
|
||||
widgets = g_list_prepend (widgets, g_object_ref (widget));
|
||||
while (widget && widget != topmost)
|
||||
{
|
||||
widget = gtk_widget_get_parent (widget);
|
||||
if (!widget)
|
||||
break;
|
||||
|
||||
widgets = g_list_prepend (widgets, g_object_ref (widget));
|
||||
|
||||
if (widget == topmost)
|
||||
break;
|
||||
}
|
||||
|
||||
for (l = widgets; l && !handled_event; l = g_list_next (l))
|
||||
{
|
||||
widget = (GtkWidget *)l->data;
|
||||
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
handled_event = TRUE;
|
||||
else
|
||||
handled_event = _gtk_widget_captured_event (widget, event);
|
||||
}
|
||||
g_list_free_full (widgets, (GDestroyNotify)g_object_unref);
|
||||
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
propagate_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
gboolean captured,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
gboolean handled_event = FALSE;
|
||||
gboolean (* propagate_func) (GtkWidget *widget, GdkEvent *event);
|
||||
|
||||
propagate_func = captured ? _gtk_widget_captured_event : gtk_widget_event;
|
||||
|
||||
if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)
|
||||
{
|
||||
/* Only send key events within Window widgets to the Window
|
||||
* The Window widget will in turn pass the
|
||||
* key event on to the currently focused widget
|
||||
* for that window.
|
||||
*/
|
||||
GtkWidget *window;
|
||||
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
g_object_ref (widget);
|
||||
/* If there is a grab within the window, give the grab widget
|
||||
* a first crack at the key event
|
||||
*/
|
||||
if (widget != window && gtk_widget_has_grab (widget))
|
||||
handled_event = propagate_func (widget, event);
|
||||
|
||||
if (!handled_event)
|
||||
{
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
if (gtk_widget_is_sensitive (window))
|
||||
handled_event = propagate_func (window, event);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (widget);
|
||||
return handled_event;
|
||||
}
|
||||
}
|
||||
|
||||
/* Other events get propagated up/down the widget tree */
|
||||
return captured ?
|
||||
propagate_event_down (widget, event, topmost) :
|
||||
propagate_event_up (widget, event, topmost);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_propagate_event:
|
||||
* @widget: a #GtkWidget
|
||||
@@ -2357,79 +2547,16 @@ void
|
||||
gtk_propagate_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
gint handled_event;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (event != NULL);
|
||||
|
||||
handled_event = FALSE;
|
||||
|
||||
g_object_ref (widget);
|
||||
|
||||
if ((event->type == GDK_KEY_PRESS) ||
|
||||
(event->type == GDK_KEY_RELEASE))
|
||||
{
|
||||
/* Only send key events within Window widgets to the Window
|
||||
* The Window widget will in turn pass the
|
||||
* key event on to the currently focused widget
|
||||
* for that window.
|
||||
*/
|
||||
GtkWidget *window;
|
||||
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
/* If there is a grab within the window, give the grab widget
|
||||
* a first crack at the key event
|
||||
*/
|
||||
if (widget != window && gtk_widget_has_grab (widget))
|
||||
handled_event = gtk_widget_event (widget, event);
|
||||
|
||||
if (!handled_event)
|
||||
{
|
||||
window = gtk_widget_get_toplevel (widget);
|
||||
if (GTK_IS_WINDOW (window))
|
||||
{
|
||||
if (gtk_widget_is_sensitive (window))
|
||||
gtk_widget_event (window, event);
|
||||
}
|
||||
}
|
||||
|
||||
handled_event = TRUE; /* don't send to widget */
|
||||
}
|
||||
}
|
||||
|
||||
/* Other events get propagated up the widget tree
|
||||
* so that parents can see the button and motion
|
||||
* events of the children.
|
||||
*/
|
||||
if (!handled_event)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
GtkWidget *tmp;
|
||||
|
||||
/* Scroll events are special cased here because it
|
||||
* feels wrong when scrolling a GtkViewport, say,
|
||||
* to have children of the viewport eat the scroll
|
||||
* event
|
||||
*/
|
||||
if (!gtk_widget_is_sensitive (widget))
|
||||
handled_event = event->type != GDK_SCROLL;
|
||||
else
|
||||
handled_event = gtk_widget_event (widget, event);
|
||||
|
||||
tmp = gtk_widget_get_parent (widget);
|
||||
g_object_unref (widget);
|
||||
|
||||
widget = tmp;
|
||||
|
||||
if (!handled_event && widget)
|
||||
g_object_ref (widget);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
g_object_unref (widget);
|
||||
propagate_event (widget, event, FALSE, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_gtk_propagate_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkWidget *topmost)
|
||||
{
|
||||
return propagate_event (widget, event, TRUE, topmost);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ BOOLEAN:OBJECT,BOXED,BOXED
|
||||
BOOLEAN:OBJECT,OBJECT,OBJECT
|
||||
BOOLEAN:OBJECT,STRING,STRING
|
||||
BOOLEAN:OBJECT,ENUM
|
||||
BOOLEAN:OBJECT,ENUM,INT,INT
|
||||
BOOLEAN:INT
|
||||
BOOLEAN:INT,INT
|
||||
BOOLEAN:INT,INT,INT
|
||||
@@ -47,6 +48,7 @@ BOOLEAN:BOOLEAN,BOOLEAN,BOOLEAN
|
||||
BOOLEAN:STRING
|
||||
ENUM:ENUM
|
||||
ENUM:VOID
|
||||
FLAGS:BOXED
|
||||
INT:POINTER
|
||||
OBJECT:VOID
|
||||
STRING:DOUBLE
|
||||
@@ -109,6 +111,7 @@ VOID:STRING,STRING,STRING
|
||||
VOID:STRING,INT,POINTER
|
||||
VOID:STRING,UINT,FLAGS
|
||||
VOID:STRING,UINT,FLAGS,UINT
|
||||
VOID:UINT,DOUBLE
|
||||
VOID:UINT,FLAGS,BOXED
|
||||
VOID:UINT,UINT
|
||||
VOID:UINT,STRING
|
||||
|
||||
+230
-276
@@ -110,6 +110,7 @@
|
||||
#include "gtksettings.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
@@ -227,12 +228,14 @@ static void gtk_menu_scroll_to (GtkMenu *menu,
|
||||
gint offset);
|
||||
static void gtk_menu_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed);
|
||||
static GtkCapturedEventFlags
|
||||
gtk_menu_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event);
|
||||
|
||||
|
||||
static void gtk_menu_stop_scrolling (GtkMenu *menu);
|
||||
static void gtk_menu_remove_scroll_timeout (GtkMenu *menu);
|
||||
static gboolean gtk_menu_scroll_timeout (gpointer data);
|
||||
static gboolean gtk_menu_scroll_timeout_initial (gpointer data);
|
||||
static void gtk_menu_start_scrolling (GtkMenu *menu);
|
||||
|
||||
static void gtk_menu_scroll_item_visible (GtkMenuShell *menu_shell,
|
||||
GtkWidget *menu_item);
|
||||
@@ -510,6 +513,7 @@ gtk_menu_class_init (GtkMenuClass *class)
|
||||
widget_class->get_preferred_width = gtk_menu_get_preferred_width;
|
||||
widget_class->get_preferred_height = gtk_menu_get_preferred_height;
|
||||
widget_class->get_preferred_height_for_width = gtk_menu_get_preferred_height_for_width;
|
||||
widget_class->captured_event = gtk_menu_captured_event;
|
||||
|
||||
container_class->remove = gtk_menu_remove;
|
||||
container_class->get_child_property = gtk_menu_get_child_property;
|
||||
@@ -1057,6 +1061,7 @@ gtk_menu_init (GtkMenu *menu)
|
||||
priv->needs_destruction_ref = TRUE;
|
||||
|
||||
priv->monitor_num = -1;
|
||||
priv->drag_start_y = -1;
|
||||
|
||||
context = gtk_widget_get_style_context (GTK_WIDGET (menu));
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENU);
|
||||
@@ -1465,7 +1470,7 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
GtkMenuShell *menu_shell;
|
||||
gboolean grab_keyboard;
|
||||
GtkWidget *parent_toplevel;
|
||||
GdkDevice *keyboard, *pointer;
|
||||
GdkDevice *keyboard, *pointer, *source_device = NULL;
|
||||
|
||||
g_return_if_fail (GTK_IS_MENU (menu));
|
||||
g_return_if_fail (device == NULL || GDK_IS_DEVICE (device));
|
||||
@@ -1602,6 +1607,7 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
(current_event->type != GDK_ENTER_NOTIFY))
|
||||
menu_shell->priv->ignore_enter = TRUE;
|
||||
|
||||
source_device = gdk_event_get_source_device (current_event);
|
||||
gdk_event_free (current_event);
|
||||
}
|
||||
else
|
||||
@@ -1671,17 +1677,9 @@ gtk_menu_popup_for_device (GtkMenu *menu,
|
||||
gtk_menu_scroll_to (menu, priv->scroll_offset);
|
||||
|
||||
/* if no item is selected, select the first one */
|
||||
if (!menu_shell->priv->active_menu_item)
|
||||
{
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (touchscreen_mode)
|
||||
gtk_menu_shell_select_first (menu_shell, TRUE);
|
||||
}
|
||||
if (!menu_shell->priv->active_menu_item &&
|
||||
source_device && gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
gtk_menu_shell_select_first (menu_shell, TRUE);
|
||||
|
||||
/* Once everything is set up correctly, map the toplevel */
|
||||
gtk_widget_show (priv->toplevel);
|
||||
@@ -3316,34 +3314,6 @@ gtk_menu_get_preferred_height_for_width (GtkWidget *widget,
|
||||
g_free (nat_heights);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static gboolean
|
||||
gtk_menu_button_scroll (GtkMenu *menu,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
|
||||
if (priv->upper_arrow_prelight || priv->lower_arrow_prelight)
|
||||
{
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (touchscreen_mode)
|
||||
gtk_menu_handle_scrolling (menu,
|
||||
event->x_root, event->y_root,
|
||||
event->type == GDK_BUTTON_PRESS,
|
||||
FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pointer_in_menu_window (GtkWidget *widget,
|
||||
gdouble x_root,
|
||||
@@ -3380,13 +3350,16 @@ static gboolean
|
||||
gtk_menu_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GdkDevice *source_device;
|
||||
GtkWidget *event_widget;
|
||||
GtkMenu *menu;
|
||||
|
||||
if (event->type != GDK_BUTTON_PRESS)
|
||||
return FALSE;
|
||||
|
||||
/* Don't pass down to menu shell for presses over scroll arrows
|
||||
*/
|
||||
if (gtk_menu_button_scroll (GTK_MENU (widget), event))
|
||||
return TRUE;
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
event_widget = gtk_get_event_widget ((GdkEvent *) event);
|
||||
menu = GTK_MENU (widget);
|
||||
|
||||
/* Don't pass down to menu shell if a non-menuitem part of the menu
|
||||
* was clicked. The check for the event_widget being a GtkMenuShell
|
||||
@@ -3395,10 +3368,16 @@ gtk_menu_button_press (GtkWidget *widget,
|
||||
* the menu or on its border are delivered relative to
|
||||
* menu_shell->window.
|
||||
*/
|
||||
if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) &&
|
||||
if (GTK_IS_MENU_SHELL (event_widget) &&
|
||||
pointer_in_menu_window (widget, event->x_root, event->y_root))
|
||||
return TRUE;
|
||||
|
||||
if (GTK_IS_MENU_ITEM (event_widget) &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH &&
|
||||
GTK_MENU_ITEM (event_widget)->priv->submenu != NULL &&
|
||||
!gtk_widget_is_drawable (GTK_MENU_ITEM (event_widget)->priv->submenu))
|
||||
menu->priv->ignore_button_release = TRUE;
|
||||
|
||||
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_press_event (widget, event);
|
||||
}
|
||||
|
||||
@@ -3417,11 +3396,6 @@ gtk_menu_button_release (GtkWidget *widget,
|
||||
if (event->type != GDK_BUTTON_RELEASE)
|
||||
return FALSE;
|
||||
|
||||
/* Don't pass down to menu shell for releases over scroll arrows
|
||||
*/
|
||||
if (gtk_menu_button_scroll (GTK_MENU (widget), event))
|
||||
return TRUE;
|
||||
|
||||
/* Don't pass down to menu shell if a non-menuitem part of the menu
|
||||
* was clicked (see comment in button_press()).
|
||||
*/
|
||||
@@ -3665,10 +3639,14 @@ gtk_menu_motion_notify (GtkWidget *widget,
|
||||
GtkMenu *menu;
|
||||
GtkMenuShell *menu_shell;
|
||||
GtkWidget *parent;
|
||||
GdkDevice *source_device;
|
||||
|
||||
gboolean need_enter;
|
||||
|
||||
if (GTK_IS_MENU (widget))
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
if (GTK_IS_MENU (widget) &&
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
|
||||
{
|
||||
GtkMenuPrivate *priv = GTK_MENU(widget)->priv;
|
||||
|
||||
@@ -3832,90 +3810,17 @@ gtk_menu_scroll_by (GtkMenu *menu,
|
||||
gtk_menu_scroll_to (menu, offset);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_do_timeout_scroll (GtkMenu *menu,
|
||||
gboolean touchscreen_mode)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
gboolean upper_visible;
|
||||
gboolean lower_visible;
|
||||
|
||||
upper_visible = priv->upper_arrow_visible;
|
||||
lower_visible = priv->lower_arrow_visible;
|
||||
|
||||
gtk_menu_scroll_by (menu, priv->scroll_step);
|
||||
|
||||
if (touchscreen_mode &&
|
||||
(upper_visible != priv->upper_arrow_visible ||
|
||||
lower_visible != priv->lower_arrow_visible))
|
||||
{
|
||||
/* We are about to hide a scroll arrow while the mouse is pressed,
|
||||
* this would cause the uncovered menu item to be activated on button
|
||||
* release. Therefore we need to ignore button release here
|
||||
*/
|
||||
GTK_MENU_SHELL (menu)->priv->ignore_enter = TRUE;
|
||||
priv->ignore_button_release = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_scroll_timeout (gpointer data)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
menu = GTK_MENU (data);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
|
||||
gtk_menu_scroll_by (menu, menu->priv->scroll_step);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_scroll_timeout_initial (gpointer data)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
guint timeout;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
menu = GTK_MENU (data);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-timeout-repeat", &timeout,
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
|
||||
menu->priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout, menu);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_start_scrolling (GtkMenu *menu)
|
||||
{
|
||||
guint timeout;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-timeout-repeat", &timeout,
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
|
||||
|
||||
menu->priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (timeout, gtk_menu_scroll_timeout_initial, menu);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_scroll (GtkWidget *widget,
|
||||
GdkEventScroll *event)
|
||||
@@ -4039,14 +3944,9 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
gboolean in_arrow;
|
||||
gboolean scroll_fast = FALSE;
|
||||
gint top_x, top_y;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
menu_shell = GTK_MENU_SHELL (menu);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
|
||||
&top_x, &top_y);
|
||||
x -= top_x;
|
||||
@@ -4064,82 +3964,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
in_arrow = TRUE;
|
||||
}
|
||||
|
||||
if (touchscreen_mode)
|
||||
priv->upper_arrow_prelight = in_arrow;
|
||||
|
||||
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
{
|
||||
gboolean arrow_pressed = FALSE;
|
||||
|
||||
if (priv->upper_arrow_visible && !priv->tearoff_active)
|
||||
{
|
||||
if (touchscreen_mode)
|
||||
scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->upper_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
if (enter && priv->upper_arrow_prelight)
|
||||
{
|
||||
if (priv->scroll_timeout == 0)
|
||||
{
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
priv->upper_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
if (!motion)
|
||||
{
|
||||
/* Only do stuff on click. */
|
||||
gtk_menu_start_scrolling (menu);
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else if (!enter)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? -MENU_SCROLL_STEP2
|
||||
: -MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else /* !touchscreen_mode */
|
||||
else if (!enter && !in_arrow && priv->upper_arrow_prelight)
|
||||
{
|
||||
scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->upper_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
priv->upper_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? -MENU_SCROLL_STEP2
|
||||
: -MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else if (!enter && !in_arrow && priv->upper_arrow_prelight)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
}
|
||||
|
||||
/* gtk_menu_start_scrolling() might have hit the top of the
|
||||
* menu, so check if the button isn't insensitive before
|
||||
/* check if the button isn't insensitive before
|
||||
* changing it to something else.
|
||||
*/
|
||||
if ((priv->upper_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
@@ -4174,82 +4036,44 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
in_arrow = TRUE;
|
||||
}
|
||||
|
||||
if (touchscreen_mode)
|
||||
priv->lower_arrow_prelight = in_arrow;
|
||||
|
||||
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
{
|
||||
gboolean arrow_pressed = FALSE;
|
||||
|
||||
if (priv->lower_arrow_visible && !priv->tearoff_active)
|
||||
{
|
||||
if (touchscreen_mode)
|
||||
scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->lower_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
if (enter && priv->lower_arrow_prelight)
|
||||
{
|
||||
if (priv->scroll_timeout == 0)
|
||||
{
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
priv->lower_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = MENU_SCROLL_STEP2; /* always fast */
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
if (!motion)
|
||||
{
|
||||
/* Only do stuff on click. */
|
||||
gtk_menu_start_scrolling (menu);
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
arrow_pressed = TRUE;
|
||||
}
|
||||
}
|
||||
else if (!enter)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? MENU_SCROLL_STEP2
|
||||
: MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else /* !touchscreen_mode */
|
||||
else if (!enter && !in_arrow && priv->lower_arrow_prelight)
|
||||
{
|
||||
scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
|
||||
|
||||
if (enter && in_arrow &&
|
||||
(!priv->lower_arrow_prelight ||
|
||||
priv->scroll_fast != scroll_fast))
|
||||
{
|
||||
priv->lower_arrow_prelight = TRUE;
|
||||
priv->scroll_fast = scroll_fast;
|
||||
|
||||
/* Deselect the active item so that
|
||||
* any submenus are popped down
|
||||
*/
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
priv->scroll_step = scroll_fast
|
||||
? MENU_SCROLL_STEP2
|
||||
: MENU_SCROLL_STEP1;
|
||||
|
||||
priv->scroll_timeout =
|
||||
gdk_threads_add_timeout (scroll_fast
|
||||
? MENU_SCROLL_TIMEOUT2
|
||||
: MENU_SCROLL_TIMEOUT1,
|
||||
gtk_menu_scroll_timeout, menu);
|
||||
}
|
||||
else if (!enter && !in_arrow && priv->lower_arrow_prelight)
|
||||
{
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
gtk_menu_stop_scrolling (menu);
|
||||
}
|
||||
}
|
||||
|
||||
/* gtk_menu_start_scrolling() might have hit the bottom of the
|
||||
* menu, so check if the button isn't insensitive before
|
||||
/* check if the button isn't insensitive before
|
||||
* changing it to something else.
|
||||
*/
|
||||
if ((priv->lower_arrow_state & GTK_STATE_FLAG_INSENSITIVE) == 0)
|
||||
@@ -4279,19 +4103,18 @@ gtk_menu_enter_notify (GtkWidget *widget,
|
||||
{
|
||||
GtkWidget *menu_item;
|
||||
GtkWidget *parent;
|
||||
gboolean touchscreen_mode;
|
||||
GdkDevice *source_device;
|
||||
|
||||
if (event->mode == GDK_CROSSING_GTK_GRAB ||
|
||||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
|
||||
event->mode == GDK_CROSSING_STATE_CHANGED)
|
||||
return TRUE;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
menu_item = gtk_get_event_widget ((GdkEvent*) event);
|
||||
if (GTK_IS_MENU (widget))
|
||||
|
||||
if (GTK_IS_MENU (widget) &&
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
|
||||
{
|
||||
GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget);
|
||||
|
||||
@@ -4300,7 +4123,8 @@ gtk_menu_enter_notify (GtkWidget *widget,
|
||||
event->x_root, event->y_root, TRUE, TRUE);
|
||||
}
|
||||
|
||||
if (!touchscreen_mode && GTK_IS_MENU_ITEM (menu_item))
|
||||
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH &&
|
||||
GTK_IS_MENU_ITEM (menu_item))
|
||||
{
|
||||
GtkWidget *menu = gtk_widget_get_parent (menu_item);
|
||||
|
||||
@@ -4357,6 +4181,7 @@ gtk_menu_leave_notify (GtkWidget *widget,
|
||||
GtkMenu *menu;
|
||||
GtkMenuItem *menu_item;
|
||||
GtkWidget *event_widget;
|
||||
GdkDevice *source_device;
|
||||
|
||||
if (event->mode == GDK_CROSSING_GTK_GRAB ||
|
||||
event->mode == GDK_CROSSING_GTK_UNGRAB ||
|
||||
@@ -4369,7 +4194,10 @@ gtk_menu_leave_notify (GtkWidget *widget,
|
||||
if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root))
|
||||
return TRUE;
|
||||
|
||||
gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
if (gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH)
|
||||
gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE);
|
||||
|
||||
event_widget = gtk_get_event_widget ((GdkEvent*) event);
|
||||
|
||||
@@ -4404,6 +4232,138 @@ gtk_menu_leave_notify (GtkWidget *widget,
|
||||
return GTK_WIDGET_CLASS (gtk_menu_parent_class)->leave_notify_event (widget, event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pointer_on_menu_widget (GtkMenu *menu,
|
||||
gdouble x_root,
|
||||
gdouble y_root)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
GtkAllocation allocation;
|
||||
gint window_x, window_y;
|
||||
|
||||
gtk_widget_get_allocation (GTK_WIDGET (menu), &allocation);
|
||||
gdk_window_get_position (gtk_widget_get_window (priv->toplevel),
|
||||
&window_x, &window_y);
|
||||
|
||||
if (x_root >= window_x && x_root < window_x + allocation.width &&
|
||||
y_root >= window_y && y_root < window_y + allocation.height)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GtkCapturedEventFlags
|
||||
gtk_menu_captured_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GdkDevice *source_device;
|
||||
GtkCapturedEventFlags flags;
|
||||
GtkMenuPrivate *priv;
|
||||
GtkMenu *menu;
|
||||
|
||||
menu = GTK_MENU (widget);
|
||||
priv = menu->priv;
|
||||
flags = GTK_CAPTURED_EVENT_NONE;
|
||||
|
||||
if (!priv->upper_arrow_visible && !priv->lower_arrow_visible)
|
||||
return flags;
|
||||
|
||||
source_device = gdk_event_get_source_device (event);
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_PRESS:
|
||||
if (event->button.button == 1 &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH &&
|
||||
pointer_on_menu_widget (menu, event->button.x_root, event->button.y_root))
|
||||
{
|
||||
priv->drag_start_y = event->button.y_root;
|
||||
priv->initial_drag_offset = priv->scroll_offset;
|
||||
priv->drag_scroll_started = FALSE;
|
||||
}
|
||||
else
|
||||
priv->drag_start_y = -1;
|
||||
|
||||
priv->drag_already_pressed = TRUE;
|
||||
break;
|
||||
case GDK_BUTTON_RELEASE:
|
||||
if (priv->drag_scroll_started)
|
||||
{
|
||||
flags = GTK_CAPTURED_EVENT_HANDLED;
|
||||
priv->drag_scroll_started = FALSE;
|
||||
priv->drag_start_y = -1;
|
||||
priv->drag_already_pressed = FALSE;
|
||||
}
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if (event->motion.state & GDK_BUTTON1_MASK &&
|
||||
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
{
|
||||
if (!priv->drag_already_pressed)
|
||||
{
|
||||
if (pointer_on_menu_widget (menu,
|
||||
event->motion.x_root,
|
||||
event->motion.y_root))
|
||||
{
|
||||
priv->drag_start_y = event->motion.y_root;
|
||||
priv->initial_drag_offset = priv->scroll_offset;
|
||||
priv->drag_scroll_started = FALSE;
|
||||
}
|
||||
else
|
||||
priv->drag_start_y = -1;
|
||||
|
||||
priv->drag_already_pressed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->drag_start_y < 0 &&
|
||||
!priv->drag_scroll_started)
|
||||
break;
|
||||
|
||||
if (priv->drag_scroll_started)
|
||||
{
|
||||
gint offset, view_height;
|
||||
GtkBorder arrow_border;
|
||||
gdouble y_diff;
|
||||
|
||||
y_diff = event->motion.y_root - priv->drag_start_y;
|
||||
offset = priv->initial_drag_offset - y_diff;
|
||||
|
||||
view_height = gdk_window_get_height (gtk_widget_get_window (widget));
|
||||
get_arrows_border (menu, &arrow_border);
|
||||
|
||||
if (priv->upper_arrow_visible)
|
||||
view_height -= arrow_border.top;
|
||||
|
||||
if (priv->lower_arrow_visible)
|
||||
view_height -= arrow_border.bottom;
|
||||
|
||||
offset = CLAMP (offset, 0, priv->requested_height - view_height);
|
||||
gtk_menu_scroll_to (menu, offset);
|
||||
|
||||
flags = GTK_CAPTURED_EVENT_HANDLED;
|
||||
}
|
||||
else if (gtk_drag_check_threshold (widget,
|
||||
0, priv->drag_start_y,
|
||||
0, event->motion.y_root))
|
||||
{
|
||||
priv->drag_scroll_started = TRUE;
|
||||
flags = GTK_CAPTURED_EVENT_HANDLED;
|
||||
gtk_menu_shell_deselect (GTK_MENU_SHELL (menu));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GDK_ENTER_NOTIFY:
|
||||
case GDK_LEAVE_NOTIFY:
|
||||
if (priv->drag_scroll_started)
|
||||
flags = GTK_CAPTURED_EVENT_HANDLED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_menu_stop_navigating_submenu (GtkMenu *menu)
|
||||
{
|
||||
@@ -4846,19 +4806,10 @@ static void
|
||||
gtk_menu_stop_scrolling (GtkMenu *menu)
|
||||
{
|
||||
GtkMenuPrivate *priv = menu->priv;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
gtk_menu_remove_scroll_timeout (menu);
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (!touchscreen_mode)
|
||||
{
|
||||
priv->upper_arrow_prelight = FALSE;
|
||||
priv->lower_arrow_prelight = FALSE;
|
||||
}
|
||||
priv->upper_arrow_prelight = FALSE;
|
||||
priv->lower_arrow_prelight = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -5664,7 +5615,6 @@ gtk_menu_real_move_scroll (GtkMenu *menu,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gtk_menu_set_monitor:
|
||||
* @menu: a #GtkMenu
|
||||
@@ -5741,11 +5691,13 @@ static void
|
||||
gtk_menu_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed)
|
||||
{
|
||||
GtkMenu *menu;
|
||||
GtkWidget *toplevel;
|
||||
GtkWindowGroup *group;
|
||||
GtkWidget *grab;
|
||||
GdkDevice *pointer;
|
||||
|
||||
menu = GTK_MENU (widget);
|
||||
pointer = _gtk_menu_shell_get_grab_device (GTK_MENU_SHELL (widget));
|
||||
|
||||
if (!pointer ||
|
||||
@@ -5762,6 +5714,8 @@ gtk_menu_grab_notify (GtkWidget *widget,
|
||||
|
||||
if (GTK_MENU_SHELL (widget)->priv->active && !GTK_IS_MENU_SHELL (grab))
|
||||
gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
|
||||
|
||||
menu->priv->drag_scroll_started = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-5
@@ -1690,13 +1690,20 @@ static void
|
||||
gtk_real_menu_item_select (GtkMenuItem *menu_item)
|
||||
{
|
||||
GtkMenuItemPrivate *priv = menu_item->priv;
|
||||
gboolean touchscreen_mode;
|
||||
GdkDevice *source_device = NULL;
|
||||
GdkEvent *current_event;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_item)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
current_event = gtk_get_current_event ();
|
||||
|
||||
if (!touchscreen_mode && priv->submenu &&
|
||||
if (current_event)
|
||||
{
|
||||
source_device = gdk_event_get_source_device (current_event);
|
||||
gdk_event_free (current_event);
|
||||
}
|
||||
|
||||
if ((!source_device ||
|
||||
gdk_device_get_source (source_device) != GDK_SOURCE_TOUCH) &&
|
||||
priv->submenu &&
|
||||
(!gtk_widget_get_mapped (priv->submenu) ||
|
||||
GTK_MENU (priv->submenu)->priv->tearoff_active))
|
||||
{
|
||||
|
||||
@@ -100,6 +100,8 @@ struct _GtkMenuPrivate
|
||||
guint seen_item_enter : 1;
|
||||
guint ignore_button_release : 1;
|
||||
guint no_toggle_size : 1;
|
||||
guint drag_already_pressed : 1;
|
||||
guint drag_scroll_started : 1;
|
||||
|
||||
/* info used for the table */
|
||||
guint *heights;
|
||||
@@ -126,6 +128,9 @@ struct _GtkMenuPrivate
|
||||
gint navigation_height;
|
||||
|
||||
guint navigation_timeout;
|
||||
|
||||
gdouble drag_start_y;
|
||||
gint initial_drag_offset;
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
+4
-32
@@ -1084,13 +1084,11 @@ gtk_menu_shell_enter_notify (GtkWidget *widget,
|
||||
|
||||
if (!gtk_widget_get_visible (GTK_MENU_ITEM (menu_item)->priv->submenu))
|
||||
{
|
||||
gboolean touchscreen_mode;
|
||||
GdkDevice *source_device;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
source_device = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
|
||||
if (touchscreen_mode)
|
||||
if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCH)
|
||||
_gtk_menu_item_popup_submenu (menu_item, TRUE);
|
||||
}
|
||||
}
|
||||
@@ -1612,45 +1610,19 @@ gtk_real_menu_shell_move_current (GtkMenuShell *menu_shell,
|
||||
GtkMenuShellPrivate *priv = menu_shell->priv;
|
||||
GtkMenuShell *parent_menu_shell = NULL;
|
||||
gboolean had_selection;
|
||||
gboolean touchscreen_mode;
|
||||
|
||||
priv->in_unselectable_item = FALSE;
|
||||
|
||||
had_selection = priv->active_menu_item != NULL;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
|
||||
"gtk-touchscreen-mode", &touchscreen_mode,
|
||||
NULL);
|
||||
|
||||
if (priv->parent_menu_shell)
|
||||
parent_menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_MENU_DIR_PARENT:
|
||||
if (touchscreen_mode &&
|
||||
priv->active_menu_item &&
|
||||
GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu &&
|
||||
gtk_widget_get_visible (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu))
|
||||
if (parent_menu_shell)
|
||||
{
|
||||
/* if we are on a menu item that has an open submenu but the
|
||||
* focus is not in that submenu (e.g. because it's empty or
|
||||
* has only insensitive items), close that submenu instead of
|
||||
* running into the code below which would close *this* menu.
|
||||
*/
|
||||
_gtk_menu_item_popdown_submenu (priv->active_menu_item);
|
||||
_gtk_menu_shell_update_mnemonics (menu_shell);
|
||||
}
|
||||
else if (parent_menu_shell)
|
||||
{
|
||||
if (touchscreen_mode)
|
||||
{
|
||||
/* close menu when returning from submenu. */
|
||||
_gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->priv->parent_menu_item);
|
||||
_gtk_menu_shell_update_mnemonics (parent_menu_shell);
|
||||
break;
|
||||
}
|
||||
|
||||
if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
|
||||
GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement)
|
||||
gtk_menu_shell_deselect (menu_shell);
|
||||
|
||||
+29
-7
@@ -3185,7 +3185,7 @@ gtk_notebook_stop_reorder (GtkNotebook *notebook)
|
||||
{
|
||||
if (priv->during_reorder)
|
||||
{
|
||||
gint old_page_num, page_num;
|
||||
gint old_page_num, page_num, i;
|
||||
GList *element;
|
||||
|
||||
element = get_drop_position (notebook);
|
||||
@@ -3194,9 +3194,16 @@ gtk_notebook_stop_reorder (GtkNotebook *notebook)
|
||||
gtk_notebook_child_reordered (notebook, page);
|
||||
|
||||
if (priv->has_scrolled || old_page_num != page_num)
|
||||
g_signal_emit (notebook,
|
||||
notebook_signals[PAGE_REORDERED], 0,
|
||||
page->child, page_num);
|
||||
{
|
||||
for (element = priv->children, i = 0; element; element = element->next, i++)
|
||||
{
|
||||
if (MIN (old_page_num, page_num) <= i && i <= MAX (old_page_num, page_num))
|
||||
gtk_widget_child_notify (((GtkNotebookPage *) element->data)->child, "position");
|
||||
}
|
||||
g_signal_emit (notebook,
|
||||
notebook_signals[PAGE_REORDERED], 0,
|
||||
page->child, page_num);
|
||||
}
|
||||
|
||||
priv->has_scrolled = FALSE;
|
||||
priv->during_reorder = FALSE;
|
||||
@@ -4097,7 +4104,7 @@ gtk_notebook_remove (GtkContainer *container,
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (container);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GtkNotebookPage *page;
|
||||
GList *children;
|
||||
GList *children, *list;
|
||||
gint page_num = 0;
|
||||
|
||||
children = priv->children;
|
||||
@@ -4117,8 +4124,15 @@ gtk_notebook_remove (GtkContainer *container,
|
||||
|
||||
g_object_ref (widget);
|
||||
|
||||
list = children->next;
|
||||
gtk_notebook_real_remove (notebook, children);
|
||||
|
||||
while (list)
|
||||
{
|
||||
gtk_widget_child_notify (((GtkNotebookPage *)list->data)->child, "position");
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
g_signal_emit (notebook,
|
||||
notebook_signals[PAGE_REMOVED],
|
||||
0,
|
||||
@@ -4566,6 +4580,7 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GtkNotebookPage *page;
|
||||
gint nchildren;
|
||||
GList *list;
|
||||
|
||||
gtk_widget_freeze_child_notify (child);
|
||||
|
||||
@@ -4648,7 +4663,14 @@ gtk_notebook_real_insert_page (GtkNotebook *notebook,
|
||||
gtk_widget_child_notify (child, "tab-fill");
|
||||
gtk_widget_child_notify (child, "tab-label");
|
||||
gtk_widget_child_notify (child, "menu-label");
|
||||
gtk_widget_child_notify (child, "position");
|
||||
|
||||
list = g_list_nth (priv->children, position);
|
||||
while (list)
|
||||
{
|
||||
gtk_widget_child_notify (((GtkNotebookPage *)list->data)->child, "position");
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
gtk_widget_thaw_child_notify (child);
|
||||
|
||||
/* The page-added handler might have reordered the pages, re-get the position */
|
||||
@@ -8017,7 +8039,7 @@ gtk_notebook_reorder_child (GtkNotebook *notebook,
|
||||
/* Move around the menu items if necessary */
|
||||
gtk_notebook_child_reordered (notebook, page);
|
||||
|
||||
for (list = priv->children, i = 0; list; list = list->next)
|
||||
for (list = priv->children, i = 0; list; list = list->next, i++)
|
||||
{
|
||||
if (MIN (old_pos, position) <= i && i <= MAX (old_pos, position))
|
||||
gtk_widget_child_notify (((GtkNotebookPage *) list->data)->child, "position");
|
||||
|
||||
+3
-3
@@ -37,8 +37,8 @@
|
||||
*
|
||||
* GtkOverlay is a container which contains a single main child, on top
|
||||
* of which it can place <firstterm>overlay</firstterm> widgets. The
|
||||
* position of each overlay widget is determined by its #GtkWidget::halign
|
||||
* and #GtkWidget::valign properties. E.g. a widget with both alignments
|
||||
* position of each overlay widget is determined by its #GtkWidget:halign
|
||||
* and #GtkWidget:valign properties. E.g. a widget with both alignments
|
||||
* set to %GTK_ALIGN_START will be placed at the top left corner of the
|
||||
* main widget, whereas an overlay with halign set to %GTK_ALIGN_CENTER
|
||||
* and valign set to %GTK_ALIGN_END will be placed a the bottom edge of
|
||||
@@ -605,7 +605,7 @@ gtk_overlay_new (void)
|
||||
* added with gtk_container_add().
|
||||
*
|
||||
* The position at which @widget is placed is determined
|
||||
* from its #GtkWidget::halign and #GtkWidget::valign properties.
|
||||
* from its #GtkWidget:halign and #GtkWidget:valign properties.
|
||||
*
|
||||
* Since: 3.2
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user