Compare commits
398 Commits
3.3.12
...
multitouch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
42c2d51ad9 | ||
|
|
2d972058ab | ||
|
|
842d3ac53d | ||
|
|
90e65f30ab | ||
|
|
a96c122fa4 | ||
|
|
194a48bd4a | ||
|
|
01193bcae2 | ||
|
|
3827d75f64 | ||
|
|
bf8d9ceb2f | ||
|
|
315ac9413b | ||
|
|
6130c65470 | ||
|
|
da30c8253b | ||
|
|
5e587229c8 | ||
|
|
24db6d7a6f | ||
|
|
5fe947640c | ||
|
|
07f8336dbd | ||
|
|
00a810ae04 | ||
|
|
f90ff5d50b | ||
|
|
a4559f1e19 | ||
|
|
f33fe5b677 | ||
|
|
e2339f5ebd | ||
|
|
3b1d8beab0 | ||
|
|
5e3c2524f8 | ||
|
|
6d430ad713 | ||
|
|
db2eb85e4a | ||
|
|
cdc6e82720 | ||
|
|
7de0672650 | ||
|
|
251cffb638 | ||
|
|
5d9736fe13 | ||
|
|
b21dd67d60 | ||
|
|
fed1cfb122 | ||
|
|
6723feae8a | ||
|
|
c525fe27f3 | ||
|
|
56f8cf91e0 | ||
|
|
71efe31f16 | ||
|
|
41e98b14d3 | ||
|
|
72ede43928 | ||
|
|
b4c31b070f | ||
|
|
bc95f03f37 | ||
|
|
c2512d1c03 | ||
|
|
63865720b7 | ||
|
|
a0f6fc137b | ||
|
|
afcd3c9f70 | ||
|
|
9a2ea96a1b | ||
|
|
de1b5e67b6 | ||
|
|
20c3f95e7b | ||
|
|
33864064f4 | ||
|
|
75eddfffbb | ||
|
|
6a381b0c1d | ||
|
|
9e14789b63 | ||
|
|
137bab8710 | ||
|
|
9ec7d6b68e | ||
|
|
ac9a94b7af | ||
|
|
40a89fccb5 | ||
|
|
33961154b6 | ||
|
|
c2a6dcc73c | ||
|
|
b5d5e6427a | ||
|
|
81465d2d97 | ||
|
|
cb625d21b4 | ||
|
|
af200feb0e | ||
|
|
bd05c1f959 | ||
|
|
c064bdb00c | ||
|
|
a45b3df9d0 | ||
|
|
68f51ee980 | ||
|
|
aa390b5e57 | ||
|
|
8971d5ed74 | ||
|
|
022e17afbc | ||
|
|
fb0c53a0ed | ||
|
|
6b2f10321f | ||
|
|
b5b9965283 | ||
|
|
610ea728b2 | ||
|
|
57386285fa | ||
|
|
35db0819ff | ||
|
|
fa3544e744 | ||
|
|
f855238cc7 | ||
|
|
8cdbebae71 | ||
|
|
1484208b4c | ||
|
|
bc1a689e55 | ||
|
|
e84af235ee | ||
|
|
f2352a5f35 | ||
|
|
2fdadb053c | ||
|
|
f1c73fcc0c | ||
|
|
cc83986eb8 | ||
|
|
3c4b8a676f | ||
|
|
cfebd1ec06 | ||
|
|
1eeafcf569 | ||
|
|
ceed732d65 | ||
|
|
2434dbc10a | ||
|
|
82b739c490 | ||
|
|
1979d048d3 | ||
|
|
d56ac0d4df | ||
|
|
2e901752b1 | ||
|
|
811e848832 | ||
|
|
5df9b0188a | ||
|
|
f22c986102 | ||
|
|
0c140daff2 | ||
|
|
a63ff72406 | ||
|
|
82c2dad178 | ||
|
|
762ea4793f | ||
|
|
a81ac3d5cd | ||
|
|
9551f542bd | ||
|
|
893807bee0 | ||
|
|
bd8fefb20e | ||
|
|
032e8f9f9b | ||
|
|
6ba33e7af5 | ||
|
|
e4c2d9b259 | ||
|
|
4c8e9ee6b6 | ||
|
|
c8786c3b97 | ||
|
|
5e5e8367ce | ||
|
|
f7e0ce3b28 | ||
|
|
25affd4766 | ||
|
|
c2fb315878 | ||
|
|
9fa764abec | ||
|
|
05f14af24c | ||
|
|
6b04c0f828 | ||
|
|
21e20b0d5b | ||
|
|
4dd9a73c8a | ||
|
|
95f5ca062b | ||
|
|
d61a84bb3a | ||
|
|
2ae2c443d0 | ||
|
|
623b5192cc | ||
|
|
c0ee68b7fe | ||
|
|
26ff536069 | ||
|
|
aa16f469bc | ||
|
|
65e6248542 | ||
|
|
cf7f0cb27a | ||
|
|
ec6b36add5 | ||
|
|
a8211b75b2 | ||
|
|
00325e992b | ||
|
|
c598a9501f | ||
|
|
1bbd2c48c5 | ||
|
|
821365af15 | ||
|
|
93523e70a0 | ||
|
|
4675ed27fd | ||
|
|
9d7a722b38 | ||
|
|
44135ba2eb | ||
|
|
8abc74680d | ||
|
|
0e395ea5a2 | ||
|
|
8dab59e5c9 | ||
|
|
5ec36a015c | ||
|
|
2cbe088674 | ||
|
|
dd2bbd1b85 | ||
|
|
a5b189093b | ||
|
|
4b90ba2701 | ||
|
|
d140411698 | ||
|
|
3ca795d447 | ||
|
|
8275a20026 | ||
|
|
5b2c1ee828 | ||
|
|
9afe13bf91 | ||
|
|
0481fbf7ce | ||
|
|
4041accda3 | ||
|
|
36242f8035 |
@@ -10,7 +10,7 @@ TEST_PROGS =
|
||||
### testing rules
|
||||
|
||||
# Xvfb based test rules
|
||||
XVFB = Xvfb -ac -noreset -screen 0 800x600x16
|
||||
XVFB = Xvfb -ac -noreset -screen 0 1024x768x16
|
||||
XIDS = 101 102 103 104 105 106 107 197 199 211 223 227 293 307 308 309 310 311 \
|
||||
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 \
|
||||
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 \
|
||||
@@ -29,7 +29,7 @@ endif
|
||||
XVFB_START = \
|
||||
${XVFB} -help 2>/dev/null 1>&2 \
|
||||
&& XID=`for id in $(XIDS) ; do test -e /tmp/.X$$id-lock || { echo $$id; exit 0; }; done; exit 1` \
|
||||
&& { ${XVFB} :$$XID -screen 0 800x600x16 -nolisten tcp -auth /dev/null >/dev/null 2>&1 & \
|
||||
&& { ${XVFB} :$$XID -nolisten tcp -auth /dev/null >/dev/null 2>&1 & \
|
||||
trap "kill -15 $$! " 0 HUP INT QUIT TRAP USR1 PIPE TERM ; } \
|
||||
|| { echo "Gtk+Tests:ERROR: Failed to start Xvfb environment for X11 target tests."; exit 1; } \
|
||||
&& DISPLAY=:$$XID && export DISPLAY
|
||||
|
||||
23
NEWS
23
NEWS
@@ -1,3 +1,26 @@
|
||||
Overview of Changes in GTK+ 3.3.14
|
||||
==================================
|
||||
|
||||
* Theming
|
||||
- Fixes for border handling in GtkEntry,
|
||||
GtkCellRendererText, GtkComboBox
|
||||
- Parse values more carefully, supporting
|
||||
percentages, angles
|
||||
- Implement CSS linear-gradient syntax
|
||||
- Support background-size
|
||||
- Support a gtk.gresource file in themes
|
||||
|
||||
* Bugs fixed
|
||||
543520 Cups custom options are not sent properly
|
||||
649121 Crash in GtkAppChooserDialog packagekit button
|
||||
669176 Regression: atk-add-key-event-listener doesn't work
|
||||
|
||||
* Updated translations
|
||||
Galician
|
||||
Norwegian bokmål
|
||||
Spanish
|
||||
|
||||
|
||||
Overview of Changes in GTK+ 3.3.10
|
||||
==================================
|
||||
|
||||
|
||||
13
configure.ac
13
configure.ac
@@ -10,7 +10,7 @@
|
||||
|
||||
m4_define([gtk_major_version], [3])
|
||||
m4_define([gtk_minor_version], [3])
|
||||
m4_define([gtk_micro_version], [12])
|
||||
m4_define([gtk_micro_version], [15])
|
||||
m4_define([gtk_interface_age], [0])
|
||||
m4_define([gtk_binary_age],
|
||||
[m4_eval(100 * gtk_minor_version + gtk_micro_version)])
|
||||
@@ -39,11 +39,11 @@ AC_CONFIG_AUX_DIR([build-aux])
|
||||
m4_define([gtk_binary_version], [3.0.0])
|
||||
|
||||
# required versions of other packages
|
||||
m4_define([glib_required_version], [2.31.13])
|
||||
m4_define([glib_required_version], [2.31.14])
|
||||
m4_define([pango_required_version], [1.29.0])
|
||||
m4_define([atk_required_version], [2.1.5])
|
||||
m4_define([cairo_required_version], [1.10.0])
|
||||
m4_define([gdk_pixbuf_required_version], [2.23.5])
|
||||
m4_define([gdk_pixbuf_required_version], [2.25.2])
|
||||
m4_define([introspection_required_version], [0.10.1])
|
||||
GLIB_REQUIRED_VERSION=glib_required_version
|
||||
PANGO_REQUIRED_VERSION=pango_required_version
|
||||
@@ -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])
|
||||
@@ -1748,6 +1752,7 @@ demos/Makefile
|
||||
demos/gtk-demo/Makefile
|
||||
demos/gtk-demo/geninclude.pl
|
||||
demos/pixbuf-demo/Makefile
|
||||
demos/widget-factory/Makefile
|
||||
examples/Makefile
|
||||
tests/Makefile
|
||||
tests/a11y/Makefile
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Makefile.am for gtk+/demos
|
||||
include $(top_srcdir)/Makefile.decl
|
||||
|
||||
SUBDIRS = gtk-demo pixbuf-demo
|
||||
SUBDIRS = gtk-demo widget-factory pixbuf-demo
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
|
||||
@@ -29,6 +29,7 @@ demos = \
|
||||
links.c \
|
||||
list_store.c \
|
||||
menus.c \
|
||||
multitouch.c \
|
||||
offscreen_window.c \
|
||||
offscreen_window2.c \
|
||||
overlay.c \
|
||||
|
||||
@@ -96,7 +96,6 @@ activate_about (GSimpleAction *action,
|
||||
{
|
||||
GtkWidget *window = user_data;
|
||||
GdkPixbuf *pixbuf;
|
||||
GInputStream *stream;
|
||||
|
||||
const gchar *authors[] = {
|
||||
"Peter Mattis",
|
||||
@@ -114,9 +113,7 @@ activate_about (GSimpleAction *action,
|
||||
NULL
|
||||
};
|
||||
|
||||
stream = g_resources_open_stream ("/logos/gtk-logo-48.png", 0, NULL);
|
||||
pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL);
|
||||
g_object_unref (stream);
|
||||
pixbuf = gdk_pixbuf_new_from_resource ("/logos/gtk-logo-48.png", NULL);
|
||||
|
||||
gtk_show_about_dialog (GTK_WINDOW (window),
|
||||
"program-name", "GTK+ Code Demos",
|
||||
@@ -168,7 +165,6 @@ register_stock_icons (void)
|
||||
GdkPixbuf *pixbuf;
|
||||
GtkIconFactory *factory;
|
||||
GtkIconSet *icon_set;
|
||||
GInputStream *stream;
|
||||
|
||||
static GtkStockItem items[] = {
|
||||
{ "demo-gtk-logo", "_GTK!", 0, 0, NULL }
|
||||
@@ -181,9 +177,7 @@ register_stock_icons (void)
|
||||
factory = gtk_icon_factory_new ();
|
||||
gtk_icon_factory_add_default (factory);
|
||||
|
||||
stream = g_resources_open_stream ("/logos/gtk-logo-24.png", 0, NULL);
|
||||
pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL);
|
||||
g_object_unref (stream);
|
||||
pixbuf = gdk_pixbuf_new_from_resource ("/logos/gtk-logo-24.png", NULL);
|
||||
|
||||
icon_set = gtk_icon_set_new_from_pixbuf (pixbuf);
|
||||
gtk_icon_factory_add (factory, "demo-gtk-logo", icon_set);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/logos">
|
||||
<file>gtk-logo-24.png</file>
|
||||
<file>gtk-logo-48.png</file>
|
||||
<file preprocess="to-pixdata">gtk-logo-24.png</file>
|
||||
<file preprocess="to-pixdata">gtk-logo-48.png</file>
|
||||
</gresource>
|
||||
<gresource prefix="/ui">
|
||||
<file>application.ui</file>
|
||||
<file>menus.ui</file>
|
||||
<file preprocess="xml-stripblanks">application.ui</file>
|
||||
<file preprocess="xml-stripblanks">menus.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
698
demos/gtk-demo/multitouch.c
Normal file
698
demos/gtk-demo/multitouch.c
Normal file
@@ -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;
|
||||
}
|
||||
31
demos/widget-factory/Makefile.am
Normal file
31
demos/widget-factory/Makefile.am
Normal file
@@ -0,0 +1,31 @@
|
||||
include $(top_srcdir)/Makefile.decl
|
||||
|
||||
bin_PROGRAMS = gtk3-widget-factory
|
||||
|
||||
gtk3_widget_factory_SOURCES = \
|
||||
widget-factory.c \
|
||||
widget_factory_resources.c
|
||||
|
||||
BUILT_SOURCES = \
|
||||
widget_factory_resources.c
|
||||
|
||||
gtk3_widget_factory_DEPENDENCIES = \
|
||||
$(top_builddir)/gtk/libgtk-3.la
|
||||
|
||||
gtk3_widget_factory_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
$(GTK_DEBUG_FLAGS) \
|
||||
$(GTK_DEP_CFLAGS)
|
||||
|
||||
gtk3_widget_factory_LDADD = \
|
||||
$(top_builddir)/gdk/libgdk-3.la \
|
||||
$(top_builddir)/gtk/libgtk-3.la \
|
||||
$(GTK_DEP_LIBS)
|
||||
|
||||
widget_factory_resources.c: widget-factory.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies $(srcdir)/widget-factory.gresource.xml)
|
||||
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate-source $<
|
||||
|
||||
EXTRA_DIST += \
|
||||
widget-factory.ui \
|
||||
widget-factory.gresource.xml \
|
||||
gtk-logo-256.png
|
||||
BIN
demos/widget-factory/gtk-logo-256.png
Normal file
BIN
demos/widget-factory/gtk-logo-256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -22,6 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static void
|
||||
@@ -35,6 +36,37 @@ dark_toggled (GtkCheckMenuItem *item, gpointer data)
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
show_about (GtkMenuItem *item, GtkWidget *window)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
const gchar *authors[] = {
|
||||
"Andrea Cimitan",
|
||||
"Cosimo Cecchi",
|
||||
NULL
|
||||
};
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_resource ("/logos/gtk-logo-256.png", NULL);
|
||||
|
||||
gtk_show_about_dialog (GTK_WINDOW (window),
|
||||
"program-name", "GTK+ Widget Factory",
|
||||
"version", g_strdup_printf ("%s,\nRunning against GTK+ %d.%d.%d",
|
||||
PACKAGE_VERSION,
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ()),
|
||||
"copyright", "(C) 1997-2009 The GTK+ Team",
|
||||
"license-type", GTK_LICENSE_LGPL_2_1,
|
||||
"website", "http://www.gtk.org",
|
||||
"comments", "Program to demonstrate GTK+ themes and widgets",
|
||||
"authors", authors,
|
||||
"logo", pixbuf,
|
||||
"title", "About GTK+ Widget Factory",
|
||||
NULL);
|
||||
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -49,7 +81,7 @@ main (int argc, char *argv[])
|
||||
dark = TRUE;
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_add_from_file (builder, "./widget-factory.ui", NULL);
|
||||
gtk_builder_add_from_resource (builder, "/ui/widget-factory.ui", NULL);
|
||||
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
gtk_builder_connect_signals (builder, NULL);
|
||||
@@ -58,6 +90,9 @@ main (int argc, char *argv[])
|
||||
g_signal_connect (widget, "toggled", G_CALLBACK (dark_toggled), NULL);
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), dark);
|
||||
|
||||
widget = (GtkWidget*) gtk_builder_get_object (builder, "aboutmenuitem");
|
||||
g_signal_connect (widget, "activate", G_CALLBACK (show_about), window);
|
||||
|
||||
g_object_unref (G_OBJECT (builder));
|
||||
|
||||
gtk_widget_show (window);
|
||||
9
demos/widget-factory/widget-factory.gresource.xml
Normal file
9
demos/widget-factory/widget-factory.gresource.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/logos">
|
||||
<file>gtk-logo-256.png</file>
|
||||
</gresource>
|
||||
<gresource prefix="/ui">
|
||||
<file preprocess="xml-stripblanks">widget-factory.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
@@ -54,6 +54,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus. </property>
|
||||
<object class="GtkAccelGroup" id="accelgroup1"/>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title">GTK+ Widget Factory</property>
|
||||
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
|
||||
<signal name="delete-event" handler="gtk_false" swapped="no"/>
|
||||
<child>
|
||||
@@ -390,7 +391,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus. </property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="imagemenuitem10">
|
||||
<object class="GtkImageMenuItem" id="aboutmenuitem">
|
||||
<property name="label">gtk-about</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
@@ -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 \
|
||||
|
||||
578
docs/reference/gtk/device-interaction-patterns.xml
Normal file
578
docs/reference/gtk/device-interaction-patterns.xml
Normal file
@@ -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
|
||||
|
||||
BIN
docs/reference/gtk/images/colorchooser.png
Normal file
BIN
docs/reference/gtk/images/colorchooser.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/reference/gtk/images/fontchooser.png
Normal file
BIN
docs/reference/gtk/images/fontchooser.png
Normal file
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;
|
||||
}
|
||||
|
||||
@@ -276,20 +276,20 @@ bloat_pad_startup (GApplication *application)
|
||||
" <menu id='app-menu'>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_New Window</attribute>"
|
||||
" <attribute name='label' translatable='yes'>_New Window</attribute>"
|
||||
" <attribute name='action'>app.new</attribute>"
|
||||
" <attribute name='accel'><Primary>n</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_About Bloatpad</attribute>"
|
||||
" <attribute name='label' translatable='yes'>_About Bloatpad</attribute>"
|
||||
" <attribute name='action'>app.about</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_Quit</attribute>"
|
||||
" <attribute name='label' translatable='yes'>_Quit</attribute>"
|
||||
" <attribute name='action'>app.quit</attribute>"
|
||||
" <attribute name='accel'><Primary>q</attribute>"
|
||||
" </item>"
|
||||
@@ -297,25 +297,25 @@ bloat_pad_startup (GApplication *application)
|
||||
" </menu>"
|
||||
" <menu id='menubar'>"
|
||||
" <submenu>"
|
||||
" <attribute name='label'>_Edit</attribute>"
|
||||
" <attribute name='label' translatable='yes'>_Edit</attribute>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_Copy</attribute>"
|
||||
" <attribute name='label' translatable='yes'>_Copy</attribute>"
|
||||
" <attribute name='action'>win.copy</attribute>"
|
||||
" <attribute name='accel'><Primary>c</attribute>"
|
||||
" </item>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_Parse</attribute>"
|
||||
" <attribute name='label' translatable='yes'>_Parse</attribute>"
|
||||
" <attribute name='action'>win.parse</attribute>"
|
||||
" <attribute name='accel'><Primary>v</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" </submenu>"
|
||||
" <submenu>"
|
||||
" <attribute name='label'>_View</attribute>"
|
||||
" <attribute name='label' translatable='yes'>_View</attribute>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_Fullscreen</attribute>"
|
||||
" <attribute name='label' translatable='yes'>_Fullscreen</attribute>"
|
||||
" <attribute name='action'>win.fullscreen</attribute>"
|
||||
" <attribute name='accel'>F11</attribute>"
|
||||
" </item>"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -422,7 +422,11 @@ parse_input (BroadwayInput *input)
|
||||
#endif
|
||||
}
|
||||
else
|
||||
parse_input_message (input, (char *)data);
|
||||
{
|
||||
char *terminated = g_strndup((char *)data, payload_len);
|
||||
parse_input_message (input, terminated);
|
||||
g_free (terminated);
|
||||
}
|
||||
break;
|
||||
case BROADWAY_WS_CNX_PING:
|
||||
broadway_output_pong (broadway_display->output);
|
||||
@@ -1012,7 +1016,7 @@ got_http_request_line (GInputStream *stream,
|
||||
/* Protect against overflow in request length */
|
||||
if (request->request->len > 1024 * 5)
|
||||
{
|
||||
send_error (request, 400, "Request to long");
|
||||
send_error (request, 400, "Request too long");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
148
gdk/gdkdisplay.c
148
gdk/gdkdisplay.c
@@ -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,
|
||||
|
||||
250
gdk/gdkevents.c
250
gdk/gdkevents.c
@@ -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.;
|
||||
@@ -487,7 +490,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 +585,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 +613,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 +685,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 +697,7 @@ gdk_event_free (GdkEvent *event)
|
||||
break;
|
||||
|
||||
case GDK_MOTION_NOTIFY:
|
||||
case GDK_TOUCH_MOTION:
|
||||
g_free (event->motion.axes);
|
||||
break;
|
||||
|
||||
@@ -668,6 +717,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 +759,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 +792,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 +841,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 +863,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 +943,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 +989,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 +1001,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;
|
||||
@@ -1162,7 +1246,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 +1257,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 +1280,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 +1325,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 +1343,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 +1379,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 +1405,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 +1427,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 +1796,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.
|
||||
|
||||
108
gdk/gdkevents.h
108
gdk/gdkevents.h
@@ -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;
|
||||
|
||||
@@ -385,6 +405,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 +422,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 +582,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 +603,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 +680,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 +718,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 +737,7 @@ struct _GdkEventButton
|
||||
guint button;
|
||||
GdkDevice *device;
|
||||
gdouble x_root, y_root;
|
||||
guint touch_id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1086,6 +1181,7 @@ union _GdkEvent
|
||||
GdkEventWindowState window_state;
|
||||
GdkEventSetting setting;
|
||||
GdkEventGrabBroken grab_broken;
|
||||
GdkEventMultiTouch multitouch;
|
||||
};
|
||||
|
||||
GType gdk_event_get_type (void) G_GNUC_CONST;
|
||||
@@ -1150,6 +1246,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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -145,19 +145,12 @@ _gdk_offscreen_window_create_surface (GdkWindow *offscreen,
|
||||
{
|
||||
cairo_surface_t *similar;
|
||||
cairo_surface_t *surface;
|
||||
cairo_content_t content = CAIRO_CONTENT_COLOR;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_OFFSCREEN_WINDOW (offscreen->impl), NULL);
|
||||
|
||||
similar = _gdk_window_ref_cairo_surface (offscreen->parent);
|
||||
|
||||
if (gdk_window_get_visual (offscreen) ==
|
||||
gdk_screen_get_rgba_visual (gdk_window_get_screen (offscreen)))
|
||||
{
|
||||
content = CAIRO_CONTENT_COLOR_ALPHA;
|
||||
}
|
||||
|
||||
surface = cairo_surface_create_similar (similar, content, width, height);
|
||||
surface = cairo_surface_create_similar (similar, CAIRO_CONTENT_COLOR_ALPHA, width, height);
|
||||
|
||||
cairo_surface_destroy (similar);
|
||||
|
||||
|
||||
448
gdk/gdktouchcluster.c
Normal file
448
gdk/gdktouchcluster.c
Normal file
@@ -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;
|
||||
}
|
||||
71
gdk/gdktouchcluster.h
Normal file
71
gdk/gdktouchcluster.h
Normal file
@@ -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__ */
|
||||
@@ -350,6 +350,7 @@ 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_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 +366,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 +397,8 @@ 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_ALL_EVENTS_MASK = 0x3FFFFF
|
||||
} GdkEventMask;
|
||||
|
||||
/**
|
||||
|
||||
817
gdk/gdkwindow.c
817
gdk/gdkwindow.c
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__ */
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -388,6 +388,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 +396,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 +411,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 +629,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 +649,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 +705,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 +768,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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,10 +234,14 @@ 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;
|
||||
default:
|
||||
/* Ignore */
|
||||
@@ -232,6 +252,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 +285,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 +298,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 +456,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 +583,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 +610,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 +885,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;
|
||||
|
||||
@@ -1043,56 +1110,55 @@ 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.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);
|
||||
}
|
||||
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 +1190,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 +1224,25 @@ 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;
|
||||
|
||||
event->motion.type = GDK_MOTION_NOTIFY;
|
||||
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;
|
||||
|
||||
@@ -1165,6 +1261,12 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
|
||||
|
||||
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 +1382,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 +1397,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) \
|
||||
|
||||
@@ -131,6 +131,8 @@ struct _GdkX11Display
|
||||
GdkWindow *active_offscreen_window;
|
||||
|
||||
GSList *error_traps;
|
||||
|
||||
gint wm_moveresize_button;
|
||||
};
|
||||
|
||||
struct _GdkX11DisplayClass
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -4020,6 +4020,85 @@ gdk_window_x11_set_static_gravities (GdkWindow *window,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* From the WM spec */
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOP 1
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
|
||||
#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
|
||||
#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
|
||||
#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
|
||||
#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
|
||||
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
|
||||
#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */
|
||||
|
||||
static void
|
||||
wmspec_send_message (GdkDisplay *display,
|
||||
GdkWindow *window,
|
||||
gint root_x,
|
||||
gint root_y,
|
||||
gint action,
|
||||
gint button)
|
||||
{
|
||||
XClientMessageEvent xclient;
|
||||
|
||||
memset (&xclient, 0, sizeof (xclient));
|
||||
xclient.type = ClientMessage;
|
||||
xclient.window = GDK_WINDOW_XID (window);
|
||||
xclient.message_type =
|
||||
gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
|
||||
xclient.format = 32;
|
||||
xclient.data.l[0] = root_x;
|
||||
xclient.data.l[1] = root_y;
|
||||
xclient.data.l[2] = action;
|
||||
xclient.data.l[3] = button;
|
||||
xclient.data.l[4] = 1; /* source indication */
|
||||
|
||||
XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
(XEvent *)&xclient);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_wmspec_button_release (GdkDisplay *display,
|
||||
XEvent *xevent)
|
||||
{
|
||||
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
|
||||
GdkWindow *window;
|
||||
|
||||
#if defined (HAVE_XGENERICEVENTS) && defined (XINPUT_2)
|
||||
XIEvent *xiev = (XIEvent *) xevent->xcookie.data;
|
||||
XIDeviceEvent *xidev = (XIDeviceEvent *) xiev;
|
||||
|
||||
if (xevent->xany.type == GenericEvent)
|
||||
window = gdk_x11_window_lookup_for_display (display, xidev->event);
|
||||
else
|
||||
#endif
|
||||
window = gdk_x11_window_lookup_for_display (display, xevent->xany.window);
|
||||
|
||||
if (display_x11->wm_moveresize_button != 0 && window != NULL)
|
||||
{
|
||||
if ((xevent->xany.type == ButtonRelease &&
|
||||
xevent->xbutton.button == display_x11->wm_moveresize_button)
|
||||
#if defined (HAVE_XGENERICEVENTS) && defined (XINPUT_2)
|
||||
||
|
||||
(xevent->xany.type == GenericEvent &&
|
||||
xiev->evtype == XI_ButtonRelease &&
|
||||
xidev->detail == display_x11->wm_moveresize_button)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
display_x11->wm_moveresize_button = 0;
|
||||
wmspec_send_message (display, window, 0, 0, _NET_WM_MOVERESIZE_CANCEL, 0);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
wmspec_moveresize (GdkWindow *window,
|
||||
gint direction,
|
||||
@@ -4030,64 +4109,14 @@ wmspec_moveresize (GdkWindow *window,
|
||||
guint32 timestamp)
|
||||
{
|
||||
GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
|
||||
|
||||
XClientMessageEvent xclient;
|
||||
|
||||
/* Release passive grab */
|
||||
gdk_device_ungrab (device, timestamp);
|
||||
GDK_X11_DISPLAY (display)->wm_moveresize_button = button;
|
||||
|
||||
memset (&xclient, 0, sizeof (xclient));
|
||||
xclient.type = ClientMessage;
|
||||
xclient.window = GDK_WINDOW_XID (window);
|
||||
xclient.message_type =
|
||||
gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
|
||||
xclient.format = 32;
|
||||
xclient.data.l[0] = root_x;
|
||||
xclient.data.l[1] = root_y;
|
||||
xclient.data.l[2] = direction;
|
||||
xclient.data.l[3] = button;
|
||||
xclient.data.l[4] = 1; /* source indication */
|
||||
|
||||
XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
(XEvent *)&xclient);
|
||||
wmspec_send_message (display, window, root_x, root_y, direction, button);
|
||||
}
|
||||
|
||||
typedef struct _MoveResizeData MoveResizeData;
|
||||
|
||||
struct _MoveResizeData
|
||||
{
|
||||
GdkDisplay *display;
|
||||
|
||||
GdkWindow *moveresize_window;
|
||||
GdkWindow *moveresize_emulation_window;
|
||||
gboolean is_resize;
|
||||
GdkWindowEdge resize_edge;
|
||||
GdkDevice *device;
|
||||
gint moveresize_button;
|
||||
gint moveresize_x;
|
||||
gint moveresize_y;
|
||||
gint moveresize_orig_x;
|
||||
gint moveresize_orig_y;
|
||||
gint moveresize_orig_width;
|
||||
gint moveresize_orig_height;
|
||||
GdkWindowHints moveresize_geom_mask;
|
||||
GdkGeometry moveresize_geometry;
|
||||
Time moveresize_process_time;
|
||||
XEvent *moveresize_pending_event;
|
||||
};
|
||||
|
||||
/* From the WM spec */
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOP 1
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
|
||||
#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
|
||||
#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
|
||||
#define _NET_WM_MOVERESIZE_MOVE 8
|
||||
|
||||
static void
|
||||
wmspec_resize_drag (GdkWindow *window,
|
||||
GdkWindowEdge edge,
|
||||
@@ -4145,6 +4174,30 @@ wmspec_resize_drag (GdkWindow *window,
|
||||
wmspec_moveresize (window, direction, device, button, root_x, root_y, timestamp);
|
||||
}
|
||||
|
||||
typedef struct _MoveResizeData MoveResizeData;
|
||||
|
||||
struct _MoveResizeData
|
||||
{
|
||||
GdkDisplay *display;
|
||||
|
||||
GdkWindow *moveresize_window;
|
||||
GdkWindow *moveresize_emulation_window;
|
||||
gboolean is_resize;
|
||||
GdkWindowEdge resize_edge;
|
||||
GdkDevice *device;
|
||||
gint moveresize_button;
|
||||
gint moveresize_x;
|
||||
gint moveresize_y;
|
||||
gint moveresize_orig_x;
|
||||
gint moveresize_orig_y;
|
||||
gint moveresize_orig_width;
|
||||
gint moveresize_orig_height;
|
||||
GdkWindowHints moveresize_geom_mask;
|
||||
GdkGeometry moveresize_geometry;
|
||||
Time moveresize_process_time;
|
||||
XEvent *moveresize_pending_event;
|
||||
};
|
||||
|
||||
static MoveResizeData *
|
||||
get_move_resize_data (GdkDisplay *display,
|
||||
gboolean create)
|
||||
@@ -4324,6 +4377,9 @@ _gdk_x11_moveresize_handle_event (XEvent *event)
|
||||
GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
|
||||
MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
|
||||
|
||||
if (handle_wmspec_button_release (display, event))
|
||||
return TRUE;
|
||||
|
||||
if (!mv_resize || !mv_resize->moveresize_window)
|
||||
return FALSE;
|
||||
|
||||
@@ -4405,6 +4461,8 @@ _gdk_x11_moveresize_configure_done (GdkDisplay *display,
|
||||
XEvent *tmp_event;
|
||||
MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
|
||||
|
||||
GDK_X11_DISPLAY (display)->wm_moveresize_button = 0;
|
||||
|
||||
if (!mv_resize || window != mv_resize->moveresize_window)
|
||||
return FALSE;
|
||||
|
||||
|
||||
@@ -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,10 +415,16 @@ 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 \
|
||||
gtkcssimagegradientprivate.h \
|
||||
gtkcssimagelinearprivate.h \
|
||||
gtkcssimageprivate.h \
|
||||
gtkcssimageurlprivate.h \
|
||||
gtkcssimagewin32private.h \
|
||||
@@ -505,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 \
|
||||
@@ -513,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 \
|
||||
@@ -589,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 \
|
||||
@@ -598,6 +618,7 @@ gtk_base_c_sources = \
|
||||
gtkcsscustomproperty.c \
|
||||
gtkcssimage.c \
|
||||
gtkcssimagegradient.c \
|
||||
gtkcssimagelinear.c \
|
||||
gtkcssimageurl.c \
|
||||
gtkcssimagewin32.c \
|
||||
gtkcsslookup.c \
|
||||
@@ -637,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 \
|
||||
@@ -1106,8 +1127,6 @@ dist-hook: ../build/win32/vs9/gtk.vcproj ../build/win32/vs10/gtk.vcxproj ../buil
|
||||
|
||||
# Install a RC file for the default GTK+ theme, and key themes
|
||||
install-data-local: install-ms-lib install-def-file install-mac-key-theme
|
||||
$(mkdir_p) $(DESTDIR)$(datadir)/themes/Raleigh/gtk-3.0
|
||||
$(INSTALL_DATA) $(srcdir)/gtk.css.raleigh $(DESTDIR)$(datadir)/themes/Raleigh/gtk-3.0/gtk.css
|
||||
$(mkdir_p) $(DESTDIR)$(datadir)/themes/Default/gtk-3.0
|
||||
$(INSTALL_DATA) $(srcdir)/gtk-keys.css.default $(DESTDIR)$(datadir)/themes/Default/gtk-3.0/gtk-keys.css
|
||||
$(mkdir_p) $(DESTDIR)$(datadir)/themes/Emacs/gtk-3.0
|
||||
@@ -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 \
|
||||
|
||||
104
gtk/a11y/gtkcolorswatchaccessible.c
Normal file
104
gtk/a11y/gtkcolorswatchaccessible.c
Normal file
@@ -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;
|
||||
}
|
||||
51
gtk/a11y/gtkcolorswatchaccessible.h
Normal file
51
gtk/a11y/gtkcolorswatchaccessible.h
Normal file
@@ -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__ */
|
||||
@@ -45,13 +45,6 @@ struct _GtkTreeViewAccessibleCellInfo
|
||||
GtkTreeViewAccessible *view;
|
||||
};
|
||||
|
||||
/* signal handling */
|
||||
|
||||
static void cursor_changed (GtkTreeView *tree_view,
|
||||
GtkTreeViewAccessible *accessible);
|
||||
static gboolean focus_in (GtkWidget *widget);
|
||||
static gboolean focus_out (GtkWidget *widget);
|
||||
|
||||
/* Misc */
|
||||
|
||||
static int cell_info_get_index (GtkTreeView *tree_view,
|
||||
@@ -59,25 +52,13 @@ static int cell_info_get_index (GtkTreeView
|
||||
static gboolean is_cell_showing (GtkTreeView *tree_view,
|
||||
GdkRectangle *cell_rect);
|
||||
|
||||
static void cell_destroyed (gpointer data);
|
||||
static void cell_info_new (GtkTreeViewAccessible *accessible,
|
||||
GtkTreeModel *tree_model,
|
||||
static void cell_info_new (GtkTreeViewAccessible *accessible,
|
||||
GtkRBTree *tree,
|
||||
GtkRBNode *node,
|
||||
GtkTreeViewColumn *tv_col,
|
||||
GtkCellAccessible *cell);
|
||||
static gint get_column_number (GtkTreeView *tree_view,
|
||||
GtkTreeViewColumn *column);
|
||||
static gint get_focus_index (GtkTreeView *tree_view);
|
||||
static gint get_index (GtkTreeView *tree_view,
|
||||
GtkTreePath *path,
|
||||
gint actual_column);
|
||||
static void count_rows (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreePath *end_path,
|
||||
gint *count,
|
||||
gint level,
|
||||
gint depth);
|
||||
|
||||
static gboolean get_rbtree_column_from_index (GtkTreeView *tree_view,
|
||||
gint index,
|
||||
@@ -116,12 +97,8 @@ gtk_tree_view_accessible_get_data_quark (void)
|
||||
static void
|
||||
cell_info_free (GtkTreeViewAccessibleCellInfo *cell_info)
|
||||
{
|
||||
if (cell_info->cell)
|
||||
{
|
||||
g_object_steal_qdata (G_OBJECT (cell_info->cell),
|
||||
gtk_tree_view_accessible_get_data_quark ());
|
||||
gtk_accessible_set_widget (GTK_ACCESSIBLE (cell_info->cell), NULL);
|
||||
}
|
||||
gtk_accessible_set_widget (GTK_ACCESSIBLE (cell_info->cell), NULL);
|
||||
g_object_unref (cell_info->cell);
|
||||
|
||||
g_free (cell_info);
|
||||
}
|
||||
@@ -166,7 +143,6 @@ gtk_tree_view_accessible_initialize (AtkObject *obj,
|
||||
ATK_OBJECT_CLASS (_gtk_tree_view_accessible_parent_class)->initialize (obj, data);
|
||||
|
||||
accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
|
||||
accessible->focus_cell = NULL;
|
||||
|
||||
accessible->cell_infos = g_hash_table_new_full (cell_info_hash,
|
||||
cell_info_equal, NULL, (GDestroyNotify) cell_info_free);
|
||||
@@ -175,13 +151,6 @@ gtk_tree_view_accessible_initialize (AtkObject *obj,
|
||||
tree_view = GTK_TREE_VIEW (widget);
|
||||
tree_model = gtk_tree_view_get_model (tree_view);
|
||||
|
||||
g_signal_connect (tree_view, "cursor-changed",
|
||||
G_CALLBACK (cursor_changed), accessible);
|
||||
g_signal_connect (tree_view, "focus-in-event",
|
||||
G_CALLBACK (focus_in), NULL);
|
||||
g_signal_connect (tree_view, "focus-out-event",
|
||||
G_CALLBACK (focus_out), NULL);
|
||||
|
||||
if (tree_model)
|
||||
{
|
||||
if (gtk_tree_model_get_flags (tree_model) & GTK_TREE_MODEL_LIST_ONLY)
|
||||
@@ -248,11 +217,7 @@ gtk_tree_view_accessible_widget_unset (GtkAccessible *gtkaccessible)
|
||||
{
|
||||
GtkTreeViewAccessible *accessible = GTK_TREE_VIEW_ACCESSIBLE (gtkaccessible);
|
||||
|
||||
if (accessible->focus_cell)
|
||||
{
|
||||
g_object_unref (accessible->focus_cell);
|
||||
accessible->focus_cell = NULL;
|
||||
}
|
||||
g_hash_table_remove_all (accessible->cell_infos);
|
||||
|
||||
GTK_ACCESSIBLE_CLASS (_gtk_tree_view_accessible_parent_class)->widget_unset (gtkaccessible);
|
||||
}
|
||||
@@ -387,6 +352,94 @@ peek_cell (GtkTreeViewAccessible *accessible,
|
||||
return cell_info->cell;
|
||||
}
|
||||
|
||||
static GtkCellAccessible *
|
||||
create_cell (GtkTreeView *treeview,
|
||||
GtkTreeViewAccessible *accessible,
|
||||
GtkRBTree *tree,
|
||||
GtkRBNode *node,
|
||||
GtkTreeViewColumn *column)
|
||||
{
|
||||
GtkCellRenderer *renderer;
|
||||
AtkObject *parent;
|
||||
GList *renderer_list;
|
||||
GList *l;
|
||||
GtkContainerCellAccessible *container = NULL;
|
||||
GtkCellAccessible *cell;
|
||||
|
||||
renderer_list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
|
||||
|
||||
/* If there is not exactly one renderer in the list,
|
||||
* make a container
|
||||
*/
|
||||
if (renderer_list == NULL || renderer_list->next)
|
||||
{
|
||||
GtkCellAccessible *container_cell;
|
||||
|
||||
container = _gtk_container_cell_accessible_new ();
|
||||
|
||||
container_cell = GTK_CELL_ACCESSIBLE (container);
|
||||
_gtk_cell_accessible_initialise (container_cell, GTK_WIDGET (treeview), ATK_OBJECT (accessible));
|
||||
|
||||
/* The GtkTreeViewAccessibleCellInfo structure for the container will
|
||||
* be before the ones for the cells so that the first one we find for
|
||||
* a position will be for the container
|
||||
*/
|
||||
cell_info_new (accessible, tree, node, column, container_cell);
|
||||
parent = ATK_OBJECT (container);
|
||||
}
|
||||
else
|
||||
parent = ATK_OBJECT (accessible);
|
||||
|
||||
cell = NULL;
|
||||
|
||||
for (l = renderer_list; l; l = l->next)
|
||||
{
|
||||
renderer = GTK_CELL_RENDERER (l->data);
|
||||
|
||||
cell = GTK_CELL_ACCESSIBLE (_gtk_renderer_cell_accessible_new (renderer));
|
||||
|
||||
/* Create the GtkTreeViewAccessibleCellInfo for this cell */
|
||||
if (parent == ATK_OBJECT (accessible))
|
||||
cell_info_new (accessible, tree, node, column, cell);
|
||||
|
||||
_gtk_cell_accessible_initialise (cell, GTK_WIDGET (treeview), parent);
|
||||
|
||||
if (container)
|
||||
_gtk_container_cell_accessible_add_child (container, cell);
|
||||
}
|
||||
g_list_free (renderer_list);
|
||||
if (container)
|
||||
cell = GTK_CELL_ACCESSIBLE (container);
|
||||
|
||||
set_cell_data (treeview, accessible, cell);
|
||||
_gtk_cell_accessible_update_cache (cell);
|
||||
|
||||
if (gtk_tree_view_get_expander_column (treeview) == column)
|
||||
{
|
||||
AtkRelationSet *relation_set;
|
||||
AtkRelation* relation;
|
||||
AtkObject *parent_node;
|
||||
|
||||
relation_set = atk_object_ref_relation_set (ATK_OBJECT (cell));
|
||||
|
||||
if (tree->parent_tree)
|
||||
{
|
||||
parent_node = ATK_OBJECT (peek_cell (accessible, tree->parent_tree, tree->parent_node, column));
|
||||
if (parent_node == NULL)
|
||||
parent_node = ATK_OBJECT (create_cell (treeview, accessible, tree->parent_tree, tree->parent_node, column));
|
||||
}
|
||||
else
|
||||
parent_node = ATK_OBJECT (accessible);
|
||||
relation = atk_relation_new (&parent_node, 1, ATK_RELATION_NODE_CHILD_OF);
|
||||
atk_relation_set_add (relation_set, relation);
|
||||
atk_object_add_relationship (parent_node, ATK_RELATION_NODE_PARENT_OF, ATK_OBJECT (cell));
|
||||
g_object_unref (relation);
|
||||
g_object_unref (relation_set);
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
static AtkObject *
|
||||
gtk_tree_view_accessible_ref_child (AtkObject *obj,
|
||||
gint i)
|
||||
@@ -395,18 +448,10 @@ gtk_tree_view_accessible_ref_child (AtkObject *obj,
|
||||
GtkTreeViewAccessible *accessible;
|
||||
GtkCellAccessible *cell;
|
||||
GtkTreeView *tree_view;
|
||||
GtkTreeModel *tree_model;
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *tv_col;
|
||||
GtkTreePath *path;
|
||||
GtkRBTree *tree;
|
||||
GtkRBNode *node;
|
||||
AtkObject *child;
|
||||
AtkObject *parent;
|
||||
GList *renderer_list;
|
||||
GList *l;
|
||||
GtkContainerCellAccessible *container = NULL;
|
||||
gint focus_index;
|
||||
|
||||
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (obj));
|
||||
if (widget == NULL)
|
||||
@@ -431,109 +476,10 @@ gtk_tree_view_accessible_ref_child (AtkObject *obj,
|
||||
return NULL;
|
||||
|
||||
cell = peek_cell (accessible, tree, node, tv_col);
|
||||
if (cell)
|
||||
return g_object_ref (cell);
|
||||
if (cell == NULL)
|
||||
cell = create_cell (tree_view, accessible, tree, node, tv_col);
|
||||
|
||||
if (accessible->focus_cell == NULL)
|
||||
focus_index = get_focus_index (tree_view);
|
||||
else
|
||||
focus_index = -1;
|
||||
|
||||
path = _gtk_tree_path_new_from_rbtree (tree, node);
|
||||
tree_model = gtk_tree_view_get_model (tree_view);
|
||||
|
||||
renderer_list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tv_col));
|
||||
|
||||
/* If there is not exactly one renderer in the list,
|
||||
* make a container
|
||||
*/
|
||||
if (renderer_list == NULL || renderer_list->next)
|
||||
{
|
||||
GtkCellAccessible *container_cell;
|
||||
|
||||
container = _gtk_container_cell_accessible_new ();
|
||||
|
||||
container_cell = GTK_CELL_ACCESSIBLE (container);
|
||||
_gtk_cell_accessible_initialise (container_cell, widget, ATK_OBJECT (accessible));
|
||||
|
||||
/* The GtkTreeViewAccessibleCellInfo structure for the container will
|
||||
* be before the ones for the cells so that the first one we find for
|
||||
* a position will be for the container
|
||||
*/
|
||||
cell_info_new (accessible, tree_model, tree, node, tv_col, container_cell);
|
||||
parent = ATK_OBJECT (container);
|
||||
}
|
||||
else
|
||||
parent = ATK_OBJECT (accessible);
|
||||
|
||||
child = NULL;
|
||||
|
||||
for (l = renderer_list; l; l = l->next)
|
||||
{
|
||||
renderer = GTK_CELL_RENDERER (l->data);
|
||||
|
||||
child = _gtk_renderer_cell_accessible_new (renderer);
|
||||
|
||||
cell = GTK_CELL_ACCESSIBLE (child);
|
||||
|
||||
/* Create the GtkTreeViewAccessibleCellInfo for this cell */
|
||||
if (parent == ATK_OBJECT (accessible))
|
||||
cell_info_new (accessible, tree_model, tree, node, tv_col, cell);
|
||||
|
||||
_gtk_cell_accessible_initialise (cell, widget, parent);
|
||||
|
||||
if (container)
|
||||
_gtk_container_cell_accessible_add_child (container, cell);
|
||||
|
||||
_gtk_cell_accessible_add_state (cell, ATK_STATE_FOCUSABLE, FALSE);
|
||||
if (focus_index == i)
|
||||
{
|
||||
accessible->focus_cell = g_object_ref (cell);
|
||||
_gtk_cell_accessible_add_state (cell, ATK_STATE_FOCUSED, FALSE);
|
||||
g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
|
||||
}
|
||||
}
|
||||
g_list_free (renderer_list);
|
||||
if (container)
|
||||
child = ATK_OBJECT (container);
|
||||
|
||||
set_cell_data (tree_view, accessible, GTK_CELL_ACCESSIBLE (child));
|
||||
_gtk_cell_accessible_update_cache (GTK_CELL_ACCESSIBLE (child));
|
||||
|
||||
if (gtk_tree_view_get_expander_column (tree_view) == tv_col)
|
||||
{
|
||||
AtkRelationSet *relation_set;
|
||||
AtkObject *accessible_array[1];
|
||||
AtkRelation* relation;
|
||||
AtkObject *parent_node;
|
||||
|
||||
relation_set = atk_object_ref_relation_set (ATK_OBJECT (child));
|
||||
|
||||
gtk_tree_path_up (path);
|
||||
if (gtk_tree_path_get_depth (path) == 0)
|
||||
parent_node = obj;
|
||||
else
|
||||
{
|
||||
gint parent_index;
|
||||
|
||||
parent_index = get_index (tree_view, path, i % get_n_columns (tree_view));
|
||||
parent_node = atk_object_ref_accessible_child (obj, parent_index);
|
||||
}
|
||||
accessible_array[0] = parent_node;
|
||||
relation = atk_relation_new (accessible_array, 1,
|
||||
ATK_RELATION_NODE_CHILD_OF);
|
||||
atk_relation_set_add (relation_set, relation);
|
||||
atk_object_add_relationship (parent_node, ATK_RELATION_NODE_PARENT_OF, child);
|
||||
g_object_unref (relation);
|
||||
g_object_unref (relation_set);
|
||||
}
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
/* We do not increase the reference count here; when g_object_unref()
|
||||
* is called for the cell then cell_destroyed() is called and this
|
||||
* removes the cell from the cache.
|
||||
*/
|
||||
return child;
|
||||
return g_object_ref (cell);
|
||||
}
|
||||
|
||||
static AtkStateSet*
|
||||
@@ -584,46 +530,6 @@ _gtk_tree_view_accessible_init (GtkTreeViewAccessible *view)
|
||||
{
|
||||
}
|
||||
|
||||
gint
|
||||
get_focus_index (GtkTreeView *tree_view)
|
||||
{
|
||||
GtkTreePath *focus_path;
|
||||
GtkTreeViewColumn *focus_column;
|
||||
gint index;
|
||||
|
||||
gtk_tree_view_get_cursor (tree_view, &focus_path, &focus_column);
|
||||
if (focus_path && focus_column)
|
||||
index = get_index (tree_view, focus_path,
|
||||
get_column_number (tree_view, focus_column));
|
||||
else
|
||||
index = -1;
|
||||
|
||||
if (focus_path)
|
||||
gtk_tree_path_free (focus_path);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* This function returns a reference to the accessible object
|
||||
* for the cell in the treeview which has focus, if any
|
||||
*/
|
||||
static AtkObject *
|
||||
gtk_tree_view_accessible_ref_focus_cell (GtkTreeView *tree_view)
|
||||
{
|
||||
AtkObject *focus_cell = NULL;
|
||||
AtkObject *atk_obj;
|
||||
gint focus_index;
|
||||
|
||||
focus_index = get_focus_index (tree_view);
|
||||
if (focus_index >= 0)
|
||||
{
|
||||
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (tree_view));
|
||||
focus_cell = atk_object_ref_accessible_child (atk_obj, focus_index);
|
||||
}
|
||||
|
||||
return focus_cell;
|
||||
}
|
||||
|
||||
/* atkcomponent.h */
|
||||
|
||||
static AtkObject *
|
||||
@@ -635,10 +541,12 @@ gtk_tree_view_accessible_ref_accessible_at_point (AtkComponent *component,
|
||||
GtkWidget *widget;
|
||||
GtkTreeView *tree_view;
|
||||
GtkTreePath *path;
|
||||
GtkTreeViewColumn *tv_column;
|
||||
GtkTreeViewColumn *column;
|
||||
gint x_pos, y_pos;
|
||||
gint bx, by;
|
||||
gboolean ret_val;
|
||||
GtkCellAccessible *cell;
|
||||
GtkRBTree *tree;
|
||||
GtkRBNode *node;
|
||||
|
||||
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (component));
|
||||
if (widget == NULL)
|
||||
@@ -648,21 +556,22 @@ gtk_tree_view_accessible_ref_accessible_at_point (AtkComponent *component,
|
||||
|
||||
atk_component_get_extents (component, &x_pos, &y_pos, NULL, NULL, coord_type);
|
||||
gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, x, y, &bx, &by);
|
||||
ret_val = gtk_tree_view_get_path_at_pos (tree_view,
|
||||
bx - x_pos, by - y_pos,
|
||||
&path, &tv_column, NULL, NULL);
|
||||
if (ret_val)
|
||||
if (!gtk_tree_view_get_path_at_pos (tree_view,
|
||||
bx - x_pos, by - y_pos,
|
||||
&path, &column, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
|
||||
{
|
||||
gint index, column;
|
||||
|
||||
column = get_column_number (tree_view, tv_column);
|
||||
index = get_index (tree_view, path, column);
|
||||
gtk_tree_path_free (path);
|
||||
|
||||
return gtk_tree_view_accessible_ref_child (ATK_OBJECT (component), index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
cell = peek_cell (GTK_TREE_VIEW_ACCESSIBLE (component), tree, node, column);
|
||||
if (cell == NULL)
|
||||
cell = create_cell (tree_view, GTK_TREE_VIEW_ACCESSIBLE (component), tree, node, column);
|
||||
|
||||
return g_object_ref (cell);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1434,89 +1343,6 @@ gtk_cell_accessible_parent_interface_init (GtkCellAccessibleParentIface *iface)
|
||||
iface->edit = gtk_tree_view_accessible_edit;
|
||||
}
|
||||
|
||||
/* signal handling */
|
||||
|
||||
static void
|
||||
cursor_changed (GtkTreeView *tree_view,
|
||||
GtkTreeViewAccessible *accessible)
|
||||
{
|
||||
AtkObject *cell;
|
||||
|
||||
cell = gtk_tree_view_accessible_ref_focus_cell (tree_view);
|
||||
if (cell)
|
||||
{
|
||||
if (cell != accessible->focus_cell)
|
||||
{
|
||||
if (accessible->focus_cell)
|
||||
{
|
||||
_gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_ACTIVE, FALSE);
|
||||
_gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_FOCUSED, FALSE);
|
||||
g_object_unref (accessible->focus_cell);
|
||||
accessible->focus_cell = cell;
|
||||
}
|
||||
|
||||
if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
|
||||
{
|
||||
_gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_ACTIVE, FALSE);
|
||||
_gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_FOCUSED, FALSE);
|
||||
}
|
||||
|
||||
g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
|
||||
}
|
||||
else
|
||||
g_object_unref (cell);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
focus_in (GtkWidget *widget)
|
||||
{
|
||||
GtkTreeView *tree_view;
|
||||
GtkTreeViewAccessible *accessible;
|
||||
AtkStateSet *state_set;
|
||||
AtkObject *cell;
|
||||
|
||||
tree_view = GTK_TREE_VIEW (widget);
|
||||
accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
|
||||
|
||||
if (accessible->focus_cell == NULL)
|
||||
{
|
||||
cell = gtk_tree_view_accessible_ref_focus_cell (tree_view);
|
||||
if (cell)
|
||||
{
|
||||
state_set = atk_object_ref_state_set (cell);
|
||||
if (state_set)
|
||||
{
|
||||
if (!atk_state_set_contains_state (state_set, ATK_STATE_FOCUSED))
|
||||
{
|
||||
_gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_ACTIVE, FALSE);
|
||||
accessible->focus_cell = cell;
|
||||
_gtk_cell_accessible_add_state (GTK_CELL_ACCESSIBLE (cell), ATK_STATE_FOCUSED, FALSE);
|
||||
g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
|
||||
}
|
||||
g_object_unref (state_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
focus_out (GtkWidget *widget)
|
||||
{
|
||||
GtkTreeViewAccessible *accessible;
|
||||
|
||||
accessible = GTK_TREE_VIEW_ACCESSIBLE (gtk_widget_get_accessible (widget));
|
||||
if (accessible->focus_cell)
|
||||
{
|
||||
_gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_ACTIVE, FALSE);
|
||||
_gtk_cell_accessible_remove_state (GTK_CELL_ACCESSIBLE (accessible->focus_cell), ATK_STATE_FOCUSED, FALSE);
|
||||
g_object_unref (accessible->focus_cell);
|
||||
accessible->focus_cell = NULL;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_tree_view_accessible_reorder (GtkTreeView *treeview)
|
||||
{
|
||||
@@ -1571,16 +1397,6 @@ is_cell_showing (GtkTreeView *tree_view,
|
||||
|
||||
/* Misc Private */
|
||||
|
||||
static void
|
||||
cell_destroyed (gpointer data)
|
||||
{
|
||||
GtkTreeViewAccessibleCellInfo *cell_info = data;
|
||||
|
||||
cell_info->cell = NULL;
|
||||
|
||||
g_hash_table_remove (cell_info->view->cell_infos, cell_info);
|
||||
}
|
||||
|
||||
static int
|
||||
cell_info_get_index (GtkTreeView *tree_view,
|
||||
GtkTreeViewAccessibleCellInfo *info)
|
||||
@@ -1596,7 +1412,6 @@ cell_info_get_index (GtkTreeView *tree_view,
|
||||
|
||||
static void
|
||||
cell_info_new (GtkTreeViewAccessible *accessible,
|
||||
GtkTreeModel *tree_model,
|
||||
GtkRBTree *tree,
|
||||
GtkRBNode *node,
|
||||
GtkTreeViewColumn *tv_col,
|
||||
@@ -1609,13 +1424,12 @@ cell_info_new (GtkTreeViewAccessible *accessible,
|
||||
cell_info->tree = tree;
|
||||
cell_info->node = node;
|
||||
cell_info->cell_col_ref = tv_col;
|
||||
cell_info->cell = cell;
|
||||
cell_info->cell = g_object_ref (cell);
|
||||
cell_info->view = accessible;
|
||||
|
||||
g_object_set_qdata_full (G_OBJECT (cell),
|
||||
gtk_tree_view_accessible_get_data_quark (),
|
||||
cell_info,
|
||||
cell_destroyed);
|
||||
g_object_set_qdata (G_OBJECT (cell),
|
||||
gtk_tree_view_accessible_get_data_quark (),
|
||||
cell_info);
|
||||
|
||||
g_hash_table_replace (accessible->cell_infos, cell_info, cell_info);
|
||||
}
|
||||
@@ -1650,93 +1464,6 @@ get_column_number (GtkTreeView *treeview,
|
||||
return number;
|
||||
}
|
||||
|
||||
static gint
|
||||
get_index (GtkTreeView *tree_view,
|
||||
GtkTreePath *path,
|
||||
gint actual_column)
|
||||
{
|
||||
gint depth = 0;
|
||||
gint index = 1;
|
||||
gint *indices = NULL;
|
||||
|
||||
if (path)
|
||||
{
|
||||
depth = gtk_tree_path_get_depth (path);
|
||||
indices = gtk_tree_path_get_indices (path);
|
||||
}
|
||||
|
||||
if (depth > 1)
|
||||
{
|
||||
GtkTreePath *copy_path;
|
||||
GtkTreeModel *model;
|
||||
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
copy_path = gtk_tree_path_copy (path);
|
||||
gtk_tree_path_up (copy_path);
|
||||
count_rows (model, NULL, copy_path, &index, 0, depth);
|
||||
gtk_tree_path_free (copy_path);
|
||||
}
|
||||
|
||||
if (path)
|
||||
index += indices[depth - 1];
|
||||
index *= get_n_columns (tree_view);
|
||||
index += actual_column;
|
||||
return index;
|
||||
}
|
||||
|
||||
/* The function count_rows counts the number of rows starting at iter
|
||||
* and ending at end_path. The value of level is the depth of iter and
|
||||
* the value of depth is the depth of end_path. Rows at depth before
|
||||
* end_path are counted. This functions counts rows which are not visible
|
||||
* because an ancestor is collapsed.
|
||||
*/
|
||||
static void
|
||||
count_rows (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkTreePath *end_path,
|
||||
gint *count,
|
||||
gint level,
|
||||
gint depth)
|
||||
{
|
||||
GtkTreeIter child_iter;
|
||||
|
||||
if (!model)
|
||||
return;
|
||||
|
||||
level++;
|
||||
*count += gtk_tree_model_iter_n_children (model, iter);
|
||||
|
||||
if (gtk_tree_model_get_flags (model) & GTK_TREE_MODEL_LIST_ONLY)
|
||||
return;
|
||||
|
||||
if (level >= depth)
|
||||
return;
|
||||
|
||||
if (gtk_tree_model_iter_children (model, &child_iter, iter))
|
||||
{
|
||||
gboolean ret_val = TRUE;
|
||||
|
||||
while (ret_val)
|
||||
{
|
||||
if (level == depth - 1)
|
||||
{
|
||||
GtkTreePath *iter_path;
|
||||
gboolean finished = FALSE;
|
||||
|
||||
iter_path = gtk_tree_model_get_path (model, &child_iter);
|
||||
if (end_path && gtk_tree_path_compare (iter_path, end_path) >= 0)
|
||||
finished = TRUE;
|
||||
gtk_tree_path_free (iter_path);
|
||||
if (finished)
|
||||
break;
|
||||
}
|
||||
if (gtk_tree_model_iter_has_child (model, &child_iter))
|
||||
count_rows (model, &child_iter, end_path, count, level, depth);
|
||||
ret_val = gtk_tree_model_iter_next (model, &child_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_rbtree_column_from_index (GtkTreeView *tree_view,
|
||||
gint index,
|
||||
@@ -2080,6 +1807,60 @@ _gtk_tree_view_accessible_toggle_visibility (GtkTreeView *treeview,
|
||||
id);
|
||||
}
|
||||
|
||||
GtkTreeViewColumn *
|
||||
get_effective_focus_column (GtkTreeView *treeview,
|
||||
GtkTreeViewColumn *column)
|
||||
{
|
||||
if (column == NULL)
|
||||
column = get_visible_column (treeview, 0);
|
||||
|
||||
return column;
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_tree_view_accessible_update_focus_column (GtkTreeView *treeview,
|
||||
GtkTreeViewColumn *old_focus,
|
||||
GtkTreeViewColumn *new_focus)
|
||||
{
|
||||
GtkTreeViewAccessible *accessible;
|
||||
AtkObject *obj;
|
||||
GtkRBTree *cursor_tree;
|
||||
GtkRBNode *cursor_node;
|
||||
GtkCellAccessible *cell;
|
||||
|
||||
old_focus = get_effective_focus_column (treeview, old_focus);
|
||||
new_focus = get_effective_focus_column (treeview, new_focus);
|
||||
if (old_focus == new_focus)
|
||||
return;
|
||||
|
||||
obj = _gtk_widget_peek_accessible (GTK_WIDGET (treeview));
|
||||
if (obj == NULL)
|
||||
return;
|
||||
|
||||
accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
|
||||
|
||||
if (!_gtk_tree_view_get_cursor_node (treeview, &cursor_tree, &cursor_node))
|
||||
return;
|
||||
|
||||
if (old_focus)
|
||||
{
|
||||
cell = peek_cell (accessible, cursor_tree, cursor_node, old_focus);
|
||||
if (cell != NULL)
|
||||
_gtk_cell_accessible_state_changed (cell, GTK_CELL_RENDERER_FOCUSED, 0);
|
||||
}
|
||||
|
||||
if (new_focus)
|
||||
{
|
||||
cell = peek_cell (accessible, cursor_tree, cursor_node, new_focus);
|
||||
if (cell != NULL)
|
||||
_gtk_cell_accessible_state_changed (cell, 0, GTK_CELL_RENDERER_FOCUSED);
|
||||
else
|
||||
cell = create_cell (treeview, accessible, cursor_tree, cursor_node, new_focus);
|
||||
|
||||
g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_gtk_tree_view_accessible_add_state (GtkTreeView *treeview,
|
||||
GtkRBTree *tree,
|
||||
@@ -2096,6 +1877,28 @@ _gtk_tree_view_accessible_add_state (GtkTreeView *treeview,
|
||||
|
||||
accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
|
||||
|
||||
if (state == GTK_CELL_RENDERER_FOCUSED)
|
||||
{
|
||||
GtkTreeViewColumn *focus_column;
|
||||
|
||||
focus_column = get_effective_focus_column (treeview, _gtk_tree_view_get_focus_column (treeview));
|
||||
|
||||
if (focus_column)
|
||||
{
|
||||
GtkCellAccessible *cell;
|
||||
|
||||
cell = peek_cell (accessible, tree, node, focus_column);
|
||||
if (cell != NULL)
|
||||
_gtk_cell_accessible_state_changed (cell, 0, state);
|
||||
else
|
||||
cell = create_cell (treeview, accessible, tree, node, focus_column);
|
||||
|
||||
g_signal_emit_by_name (accessible, "active-descendant-changed", cell);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
|
||||
{
|
||||
GtkCellAccessible *cell = peek_cell (accessible,
|
||||
@@ -2128,6 +1931,25 @@ _gtk_tree_view_accessible_remove_state (GtkTreeView *treeview,
|
||||
|
||||
accessible = GTK_TREE_VIEW_ACCESSIBLE (obj);
|
||||
|
||||
if (state == GTK_CELL_RENDERER_FOCUSED)
|
||||
{
|
||||
GtkTreeViewColumn *focus_column;
|
||||
|
||||
focus_column = get_effective_focus_column (treeview, _gtk_tree_view_get_focus_column (treeview));
|
||||
|
||||
if (focus_column)
|
||||
{
|
||||
GtkCellAccessible *cell = peek_cell (accessible,
|
||||
tree, node,
|
||||
focus_column);
|
||||
|
||||
if (cell != NULL)
|
||||
_gtk_cell_accessible_state_changed (cell, 0, state);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
|
||||
{
|
||||
GtkCellAccessible *cell = peek_cell (accessible,
|
||||
|
||||
@@ -40,7 +40,6 @@ struct _GtkTreeViewAccessible
|
||||
GtkContainerAccessible parent;
|
||||
|
||||
GHashTable *cell_infos;
|
||||
AtkObject *focus_cell;
|
||||
};
|
||||
|
||||
struct _GtkTreeViewAccessibleClass
|
||||
@@ -74,6 +73,10 @@ void _gtk_tree_view_accessible_reorder_column(GtkTreeView *tree
|
||||
void _gtk_tree_view_accessible_toggle_visibility
|
||||
(GtkTreeView *treeview,
|
||||
GtkTreeViewColumn *column);
|
||||
void _gtk_tree_view_accessible_update_focus_column
|
||||
(GtkTreeView *treeview,
|
||||
GtkTreeViewColumn *old_focus,
|
||||
GtkTreeViewColumn *new_focus);
|
||||
|
||||
void _gtk_tree_view_accessible_add_state (GtkTreeView *treeview,
|
||||
GtkRBTree *tree,
|
||||
|
||||
@@ -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:
|
||||
* |[
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
@define-color error_bg_color rgb (237, 54, 54);
|
||||
|
||||
* {
|
||||
background-color: @bg_color;
|
||||
color: @fg_color;
|
||||
border-color: shade (@bg_color, 0.6);
|
||||
padding: 2;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
GtkWindow, .button, .slider {
|
||||
background-color: @bg_color;
|
||||
}
|
||||
|
||||
*:prelight {
|
||||
@@ -120,7 +121,7 @@ GtkTreeView.view.expander:selected:prelight {
|
||||
background-color: alpha (@fg_color, 0.25);
|
||||
border-color: @fg_color;
|
||||
border-style: solid;
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.tooltip,
|
||||
@@ -128,14 +129,14 @@ GtkTreeView.view.expander:selected:prelight {
|
||||
background-color: @tooltip_bg_color;
|
||||
color: @tooltip_fg_color;
|
||||
border-color: @tooltip_fg_color;
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.button,
|
||||
.slider {
|
||||
border-style: outset;
|
||||
border-width: 2;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.button:active {
|
||||
@@ -153,13 +154,13 @@ GtkTreeView.view.expander:selected:prelight {
|
||||
.trough {
|
||||
background-color: darker (@bg_color);
|
||||
border-style: inset;
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.entry {
|
||||
border-style: inset;
|
||||
border-width: 2;
|
||||
border-width: 2px;
|
||||
background-color: @base_color;
|
||||
color: @text_color;
|
||||
}
|
||||
@@ -180,7 +181,7 @@ GtkTreeView.view.expander:selected:prelight {
|
||||
border-color: shade (@selected_bg_color, 0.7);
|
||||
color: @selected_fg_color;
|
||||
border-style: outset;
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
GtkCheckButton:hover,
|
||||
@@ -194,7 +195,7 @@ GtkRadioButton:selected {
|
||||
.cell.check, .cell.radio,
|
||||
.cell.check:hover, .cell.radio:hover {
|
||||
border-style: solid;
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
background-color: @base_color;
|
||||
border-color: @fg_color;
|
||||
}
|
||||
@@ -224,22 +225,22 @@ GtkRadioButton:selected {
|
||||
|
||||
.popup {
|
||||
border-style: outset;
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.viewport {
|
||||
border-style: inset;
|
||||
border-width: 2;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.notebook {
|
||||
border-style: outset;
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.frame {
|
||||
border-style: inset;
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
GtkScrolledWindow.frame {
|
||||
@@ -250,7 +251,7 @@ GtkScrolledWindow.frame {
|
||||
.menubar,
|
||||
.toolbar {
|
||||
border-style: outset;
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.menu:hover,
|
||||
@@ -263,7 +264,7 @@ GtkScrolledWindow.frame {
|
||||
}
|
||||
|
||||
GtkSpinButton.button {
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.scale.slider:hover,
|
||||
@@ -329,9 +330,9 @@ GtkLabel:selected:focused {
|
||||
color: #fff;
|
||||
}
|
||||
GtkCalendar.view {
|
||||
border-width: 1;
|
||||
border-width: 1px;
|
||||
border-style: inset;
|
||||
padding: 1;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
GtkCalendar.view:inconsistent {
|
||||
@@ -341,7 +342,7 @@ GtkCalendar.view:inconsistent {
|
||||
GtkCalendar.header {
|
||||
background-color: @bg_color;
|
||||
border-style: outset;
|
||||
border-width: 2;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
GtkCalendar.highlight {
|
||||
@@ -359,5 +360,11 @@ GtkCalendar.button:hover {
|
||||
|
||||
.menu * {
|
||||
border-width: 0;
|
||||
padding: 2;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.press-and-hold {
|
||||
background-color: alpha (@bg_color, 0.5);
|
||||
color: alpha (lighter (@selected_bg_color), 0.8);
|
||||
border-width: 10;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,123 @@
|
||||
@define-color bg_color -gtk-win32-color(button, 15);
|
||||
@define-color text_color -gtk-win32-color(button, 18);
|
||||
@define-color base_color #fff;
|
||||
@define-color selected_bg_color -gtk-win32-color(button, 13);
|
||||
@define-color selected_fg_color -gtk-win32-color(button, 14);
|
||||
@define-color info_fg_color rgb (181, 171, 156);
|
||||
@define-color info_bg_color rgb (252, 252, 189);
|
||||
@define-color warning_fg_color rgb (173, 120, 41);
|
||||
@define-color warning_bg_color rgb (250, 173, 61);
|
||||
@define-color question_fg_color rgb (97, 122, 214);
|
||||
@define-color question_bg_color rgb (138, 173, 212);
|
||||
@define-color error_fg_color rgb (166, 38, 38);
|
||||
@define-color error_bg_color rgb (237, 54, 54);
|
||||
|
||||
GtkWindow,
|
||||
GtkViewport {
|
||||
background-color: @bg_color;
|
||||
}
|
||||
|
||||
* {
|
||||
color: -gtk-win32-color(button, 9);
|
||||
-GtkWidget-link-color: -gtk-win32-color(button, 26);
|
||||
-GtkWidget-visited-link-color: -gtk-win32-color(button, 26);
|
||||
border-color: shade (@bg_color, 0.6);
|
||||
}
|
||||
|
||||
GtkFrame {
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
background-color: transparent;
|
||||
border-image: -gtk-win32-theme-part(button, 4 1) 2 2 2 2 stretch;
|
||||
}
|
||||
|
||||
*:insensitive {
|
||||
color: -gtk-win32-color(button, 17);
|
||||
}
|
||||
|
||||
*:selected,
|
||||
*:selected:focus {
|
||||
background-color: @selected_bg_color;
|
||||
color: @selected_fg_color;
|
||||
}
|
||||
|
||||
.info {
|
||||
background-color: @info_bg_color;
|
||||
color: @info_fg_color;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: @warning_bg_color;
|
||||
color: @warning_fg_color;
|
||||
}
|
||||
|
||||
.question {
|
||||
background-color: @question_bg_color;
|
||||
color: @question_fg_color;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: @error_bg_color;
|
||||
color: @error_fg_color;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: @selected_bg_color;
|
||||
color: @selected_fg_color;
|
||||
}
|
||||
|
||||
.light-area-focus {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.dark-area-focus {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.view {
|
||||
border-width: 0;
|
||||
border-radius: 0;
|
||||
background-color: @base_color;
|
||||
color: @text_color;
|
||||
}
|
||||
|
||||
.view:selected {
|
||||
background-color: shade (@bg_color, 0.9);
|
||||
color: @fg_color;
|
||||
}
|
||||
|
||||
.view:selected:focused {
|
||||
background-color: @selected_bg_color;
|
||||
color: @selected_fg_color;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
background-color: -gtk-win32-color(button, 24);
|
||||
color: -gtk-win32-color(button, 23);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.tooltip * {
|
||||
color: -gtk-win32-color(button, 23);
|
||||
}
|
||||
|
||||
GtkAssistant .sidebar .highlight {
|
||||
font: bold;
|
||||
color: -gtk-win32-color(button, 9);
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
.button {
|
||||
color: -gtk-win32-color(button, 18);
|
||||
background-color: transparent;
|
||||
background-image: -gtk-win32-theme-part(button, 1 1);
|
||||
border-width: 0;
|
||||
-GtkWidget-focus-line-width: 1;
|
||||
-GtkWidget-focus-padding: 3;
|
||||
-GtkButton-interior-focuse: true;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.button:insensitive {
|
||||
@@ -227,6 +336,7 @@
|
||||
background-color: black;
|
||||
border-width: 0;
|
||||
background-image: -gtk-win32-theme-part(edit, 1 1);
|
||||
padding: 2px;
|
||||
}
|
||||
.entry:insensitive {
|
||||
background-image: -gtk-win32-theme-part(edit, 1 4);
|
||||
@@ -240,7 +350,7 @@
|
||||
.spinbutton.button,
|
||||
.spinbutton.button:focused {
|
||||
background-color: transparent;
|
||||
border-width: 1 1 0 0;
|
||||
border-width: 1px 1px 0 0;
|
||||
border-style: none;
|
||||
background-image: -gtk-win32-theme-part(spin, 1 1);
|
||||
color: rgba(0, 0, 0, 0);
|
||||
@@ -265,7 +375,7 @@
|
||||
|
||||
.spinbutton.button.bottom,
|
||||
.spinbutton.button.bottom:focused {
|
||||
border-width: 0 1 1 0;
|
||||
border-width: 0 1px 1px 0;
|
||||
background-image: -gtk-win32-theme-part(spin, 2 1);
|
||||
color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
@@ -462,6 +572,7 @@ GtkEntry.progressbar {
|
||||
|
||||
GtkProgressBar.progressbar.pulse,
|
||||
GtkEntry.progressbar.pulse {
|
||||
background-color: transparent;
|
||||
background-image: -gtk-win32-theme-part(progress, 8 1);
|
||||
}
|
||||
|
||||
@@ -479,28 +590,43 @@ GtkProgressBar.trough.vertical {
|
||||
|
||||
/* Menus */
|
||||
|
||||
.menu {
|
||||
background-color: -gtk-win32-color(button, 4);
|
||||
border-color: shade (-gtk-win32-color(button, 4), 0.6);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.menuitem {
|
||||
color: -gtk-win32-color(button, 7);
|
||||
}
|
||||
|
||||
.menubar {
|
||||
background-color: transparent;
|
||||
border-width: 0;
|
||||
background-image: -gtk-win32-theme-part(menu, 7 1);
|
||||
}
|
||||
|
||||
.menubar .menuitem {
|
||||
.menubar > .menuitem {
|
||||
background-color: transparent;
|
||||
border-width: 0;
|
||||
background-image: -gtk-win32-theme-part(menu, 8 1);
|
||||
padding: 3px 5px;
|
||||
}
|
||||
|
||||
.menubar .menuitem:prelight {
|
||||
.menubar > .menuitem:prelight {
|
||||
background-color: transparent;
|
||||
border-width: 0;
|
||||
background-image: -gtk-win32-theme-part(menu, 8 3);
|
||||
}
|
||||
|
||||
.menuitem:prelight {
|
||||
background-color: transparent;
|
||||
background-image: -gtk-win32-theme-part(menu, 14 2);
|
||||
}
|
||||
|
||||
.menuitem:prelight:insensitive {
|
||||
background-image: -gtk-win32-theme-part(menu, 14 4);
|
||||
}
|
||||
|
||||
.menuitem.radio,
|
||||
@@ -588,8 +714,8 @@ GtkComboBox.combobox-entry .button:insensitive {
|
||||
/* Notebook */
|
||||
|
||||
.notebook {
|
||||
background-color: transparent;
|
||||
border-width: 1 3 2 2;
|
||||
background-color: @base_color;
|
||||
border-width: 1px 3px 2px 2px;
|
||||
border-style: solid;
|
||||
background-origin: padding-box;
|
||||
background-clip: border-box;
|
||||
@@ -607,7 +733,7 @@ GtkComboBox.combobox-entry .button:insensitive {
|
||||
|
||||
.notebook tab:active {
|
||||
background-image: -gtk-win32-theme-part(tab, 1 3, margins(0 0 -1 0));
|
||||
padding: 4;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.notebook tab:last-child {
|
||||
@@ -673,3 +799,27 @@ column-header .button:active:focus,
|
||||
column-header .button:active:prelight:focus {
|
||||
background-image: -gtk-win32-theme-part(header, 1 3);
|
||||
}
|
||||
|
||||
GtkSwitch {
|
||||
font: bold condensed 10;
|
||||
color: -gtk-win32-color(button, 18);
|
||||
}
|
||||
|
||||
GtkSwitch.slider {
|
||||
padding: 4px;
|
||||
background-color: transparent;
|
||||
background-image: -gtk-win32-theme-part(scrollbar, 2 1, over (8 1));
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
GtkSwitch.trough:insensitive {
|
||||
background-image: -gtk-win32-theme-part(button, 1 4);
|
||||
}
|
||||
|
||||
GtkSwitch.trough {
|
||||
background-image: -gtk-win32-theme-part(button, 1 1);
|
||||
}
|
||||
|
||||
GtkSwitch.trough:active {
|
||||
background-image: -gtk-win32-theme-part(button, 1 2);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
/*
|
||||
* This theme is the default theme if no other theme is selected.
|
||||
*/
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gtk/libgtk">
|
||||
<file>gtk-default.css</file>
|
||||
<file alias="Raleigh.css">gtk-default.css</file>
|
||||
<file>gtk-win32.css</file>
|
||||
<file alias="cursor/dnd-ask.png">cursor_dnd_ask.png</file>
|
||||
<file alias="cursor/dnd-link.png">cursor_dnd_link.png</file>
|
||||
|
||||
11
gtk/gtk.h
11
gtk/gtk.h
@@ -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
|
||||
|
||||
@@ -103,7 +103,7 @@ static GdkColor default_visited_link_color = { 0, 0x5555, 0x1a1a, 0x8b8b };
|
||||
/* Translators: this is the license preamble; the string at the end
|
||||
* contains the URL of the license.
|
||||
*/
|
||||
static const gchar *gtk_license_preamble = N_("This program comes with ABSOLUTELY NO WARRANTY; for details, visit <a href=\"%s\">%s</a>");
|
||||
static const gchar *gtk_license_preamble = N_("This program comes with ABSOLUTELY NO WARRANTY;\nfor details, visit <a href=\"%s\">%s</a>");
|
||||
|
||||
/* URLs for each GtkLicense type; keep in the same order as the enumeration */
|
||||
static const gchar *gtk_license_urls[] = {
|
||||
@@ -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);
|
||||
|
||||
@@ -130,13 +130,13 @@ gtk_accessible_real_widget_unset (GtkAccessible *accessible)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_accessible_finalize (GObject *object)
|
||||
gtk_accessible_dispose (GObject *object)
|
||||
{
|
||||
GtkAccessible *accessible = GTK_ACCESSIBLE (object);
|
||||
|
||||
gtk_accessible_set_widget (accessible, NULL);
|
||||
|
||||
G_OBJECT_CLASS (gtk_accessible_parent_class)->finalize (object);
|
||||
G_OBJECT_CLASS (gtk_accessible_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -152,7 +152,7 @@ gtk_accessible_class_init (GtkAccessibleClass *klass)
|
||||
atkobject_class->ref_state_set = gtk_accessible_ref_state_set;
|
||||
gobject_class->get_property = gtk_accessible_get_property;
|
||||
gobject_class->set_property = gtk_accessible_set_property;
|
||||
gobject_class->finalize = gtk_accessible_finalize;
|
||||
gobject_class->dispose = gtk_accessible_dispose;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_WIDGET,
|
||||
|
||||
@@ -1406,7 +1406,8 @@ dgettext_swapped (const gchar *msgid,
|
||||
/**
|
||||
* gtk_action_group_set_translation_domain:
|
||||
* @action_group: a #GtkActionGroup
|
||||
* @domain: the translation domain to use for g_dgettext() calls
|
||||
* @domain: (allow-none): the translation domain to use for g_dgettext()
|
||||
* calls, or %NULL to use the domain set with textdomain()
|
||||
*
|
||||
* Sets the translation domain and uses g_dgettext() for translating the
|
||||
* @label and @tooltip of #GtkActionEntry<!-- -->s added by
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -80,6 +80,7 @@ struct _GtkAppChooserDialogPrivate {
|
||||
GCancellable *online_cancellable;
|
||||
|
||||
gboolean show_more_clicked;
|
||||
gboolean dismissed;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -129,6 +130,9 @@ search_for_mimetype_ready_cb (GObject *source,
|
||||
|
||||
_gtk_app_chooser_online_search_for_mimetype_finish (online, res, &error);
|
||||
|
||||
if (self->priv->dismissed)
|
||||
goto out;
|
||||
|
||||
if (error != NULL &&
|
||||
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
@@ -141,7 +145,10 @@ search_for_mimetype_ready_cb (GObject *source,
|
||||
gtk_app_chooser_refresh (GTK_APP_CHOOSER (self->priv->app_chooser_widget));
|
||||
}
|
||||
|
||||
out:
|
||||
g_clear_object (&self->priv->online_cancellable);
|
||||
g_clear_error (&error);
|
||||
g_object_unref (self);
|
||||
|
||||
gdk_threads_leave ();
|
||||
}
|
||||
@@ -160,7 +167,7 @@ online_button_clicked_cb (GtkButton *b,
|
||||
GTK_WINDOW (self),
|
||||
self->priv->online_cancellable,
|
||||
search_for_mimetype_ready_cb,
|
||||
self);
|
||||
g_object_ref (self));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -174,7 +181,8 @@ app_chooser_online_get_default_ready_cb (GObject *source,
|
||||
|
||||
self->priv->online = _gtk_app_chooser_online_get_default_finish (source, res);
|
||||
|
||||
if (self->priv->online != NULL)
|
||||
if (self->priv->online != NULL &&
|
||||
!self->priv->dismissed)
|
||||
{
|
||||
GtkWidget *action_area;
|
||||
|
||||
@@ -194,13 +202,16 @@ app_chooser_online_get_default_ready_cb (GObject *source,
|
||||
gtk_widget_show (self->priv->online_button);
|
||||
}
|
||||
|
||||
g_object_unref (self);
|
||||
|
||||
gdk_threads_leave ();
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_online_button (GtkAppChooserDialog *self)
|
||||
{
|
||||
_gtk_app_chooser_online_get_default_async (app_chooser_online_get_default_ready_cb, self);
|
||||
_gtk_app_chooser_online_get_default_async (app_chooser_online_get_default_ready_cb,
|
||||
g_object_ref (self));
|
||||
}
|
||||
|
||||
/* An application is valid if:
|
||||
@@ -286,6 +297,16 @@ add_or_find_application (GtkAppChooserDialog *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cancel_and_clear_cancellable (GtkAppChooserDialog *self)
|
||||
{
|
||||
if (self->priv->online_cancellable != NULL)
|
||||
{
|
||||
g_cancellable_cancel (self->priv->online_cancellable);
|
||||
g_clear_object (&self->priv->online_cancellable);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_app_chooser_dialog_response (GtkDialog *dialog,
|
||||
gint response_id,
|
||||
@@ -298,6 +319,10 @@ gtk_app_chooser_dialog_response (GtkDialog *dialog,
|
||||
case GTK_RESPONSE_OK:
|
||||
add_or_find_application (self);
|
||||
break;
|
||||
case GTK_RESPONSE_CANCEL:
|
||||
case GTK_RESPONSE_DELETE_EVENT:
|
||||
cancel_and_clear_cancellable (self);
|
||||
self->priv->dismissed = TRUE;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
@@ -618,14 +643,9 @@ gtk_app_chooser_dialog_dispose (GObject *object)
|
||||
GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object);
|
||||
|
||||
g_clear_object (&self->priv->gfile);
|
||||
cancel_and_clear_cancellable (self);
|
||||
g_clear_object (&self->priv->online);
|
||||
|
||||
if (self->priv->online_cancellable != NULL)
|
||||
{
|
||||
g_cancellable_cancel (self->priv->online_cancellable);
|
||||
g_clear_object (&self->priv->online_cancellable);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ install_mime_types_ready_cb (GObject *source,
|
||||
}
|
||||
|
||||
g_simple_async_result_complete (self->priv->result);
|
||||
g_clear_object (&self->priv->result);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
|
||||
@@ -106,8 +106,12 @@ gtk_builder_menu_start_element (GMarkupParseContext *context,
|
||||
{
|
||||
GMenuItem *item;
|
||||
|
||||
item = g_menu_item_new (NULL, NULL);
|
||||
gtk_builder_menu_push_frame (state, NULL, item);
|
||||
if (COLLECT (G_MARKUP_COLLECT_INVALID, NULL))
|
||||
{
|
||||
item = g_menu_item_new (NULL, NULL);
|
||||
gtk_builder_menu_push_frame (state, NULL, item);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -243,7 +247,7 @@ gtk_builder_menu_end_element (GMarkupParseContext *context,
|
||||
state->string = NULL;
|
||||
|
||||
/* do the translation if necessary */
|
||||
if (state->translatable && state->parser_data->domain)
|
||||
if (state->translatable)
|
||||
{
|
||||
const gchar *translated;
|
||||
|
||||
|
||||
@@ -26,15 +26,15 @@
|
||||
|
||||
/**
|
||||
* SECTION:gtkbutton
|
||||
* @Short_description: A widget that creates a signal when clicked on
|
||||
* @Short_description: A widget that emits a signal when clicked on
|
||||
* @Title: GtkButton
|
||||
*
|
||||
* The #GtkButton widget is generally used to attach a function to that is
|
||||
* The #GtkButton widget is generally used to trigger a callback function that is
|
||||
* called when the button is pressed. The various signals and how to use them
|
||||
* are outlined below.
|
||||
*
|
||||
* The #GtkButton widget can hold any valid child widget. That is it can hold
|
||||
* most any other standard #GtkWidget. The most commonly used child is the
|
||||
* The #GtkButton widget can hold any valid child widget. That is, it can hold
|
||||
* almost any other standard #GtkWidget. The most commonly used child is the
|
||||
* #GtkLabel.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -865,6 +865,8 @@ gtk_cell_renderer_start_editing (GtkCellRenderer *cell,
|
||||
(GdkRectangle *) background_area,
|
||||
(GdkRectangle *) cell_area,
|
||||
flags);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (editable)),
|
||||
GTK_STYLE_CLASS_CELL);
|
||||
|
||||
g_signal_emit (cell,
|
||||
cell_renderer_signals[EDITING_STARTED], 0,
|
||||
|
||||
@@ -1981,7 +1981,6 @@ gtk_cell_renderer_text_start_editing (GtkCellRenderer *cell,
|
||||
const GdkRectangle *cell_area,
|
||||
GtkCellRendererState flags)
|
||||
{
|
||||
GtkRequisition requisition;
|
||||
GtkCellRendererText *celltext;
|
||||
GtkCellRendererTextPrivate *priv;
|
||||
gfloat xalign, yalign;
|
||||
@@ -2005,33 +2004,6 @@ gtk_cell_renderer_text_start_editing (GtkCellRenderer *cell,
|
||||
|
||||
gtk_editable_select_region (GTK_EDITABLE (priv->entry), 0, -1);
|
||||
|
||||
gtk_widget_get_preferred_size (priv->entry, &requisition, NULL);
|
||||
if (requisition.height < cell_area->height)
|
||||
{
|
||||
GtkBorder *style_border;
|
||||
GtkBorder border;
|
||||
|
||||
gtk_widget_style_get (priv->entry,
|
||||
"inner-border", &style_border,
|
||||
NULL);
|
||||
|
||||
if (style_border)
|
||||
{
|
||||
border = *style_border;
|
||||
g_boxed_free (GTK_TYPE_BORDER, style_border);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Since boxed style properties can't have default values ... */
|
||||
border.left = 2;
|
||||
border.right = 2;
|
||||
}
|
||||
|
||||
border.top = (cell_area->height - requisition.height) / 2;
|
||||
border.bottom = (cell_area->height - requisition.height) / 2;
|
||||
gtk_entry_set_inner_border (GTK_ENTRY (priv->entry), &border);
|
||||
}
|
||||
|
||||
priv->in_entry_menu = FALSE;
|
||||
if (priv->entry_menu_popdown_timeout)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
258
gtk/gtkcolorchooser.c
Normal file
258
gtk/gtkcolorchooser.c
Normal file
@@ -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;
|
||||
}
|
||||
82
gtk/gtkcolorchooser.h
Normal file
82
gtk/gtkcolorchooser.h
Normal file
@@ -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__ */
|
||||
303
gtk/gtkcolorchooserdialog.c
Normal file
303
gtk/gtkcolorchooserdialog.c
Normal file
@@ -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);
|
||||
}
|
||||
68
gtk/gtkcolorchooserdialog.h
Normal file
68
gtk/gtkcolorchooserdialog.h
Normal file
@@ -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__ */
|
||||
34
gtk/gtkcolorchooserprivate.h
Normal file
34
gtk/gtkcolorchooserprivate.h
Normal file
@@ -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__ */
|
||||
803
gtk/gtkcolorchooserwidget.c
Normal file
803
gtk/gtkcolorchooserwidget.c
Normal file
@@ -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: */
|
||||
71
gtk/gtkcolorchooserwidget.h
Normal file
71
gtk/gtkcolorchooserwidget.h
Normal file
@@ -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__ */
|
||||
655
gtk/gtkcoloreditor.c
Normal file
655
gtk/gtkcoloreditor.c
Normal file
@@ -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);
|
||||
}
|
||||
70
gtk/gtkcoloreditorprivate.h
Normal file
70
gtk/gtkcoloreditorprivate.h
Normal file
@@ -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__ */
|
||||
449
gtk/gtkcolorplane.c
Normal file
449
gtk/gtkcolorplane.c
Normal file
@@ -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;
|
||||
}
|
||||
72
gtk/gtkcolorplaneprivate.h
Normal file
72
gtk/gtkcolorplaneprivate.h
Normal file
@@ -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__ */
|
||||
362
gtk/gtkcolorscale.c
Normal file
362
gtk/gtkcolorscale.c
Normal file
@@ -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);
|
||||
}
|
||||
80
gtk/gtkcolorscaleprivate.h
Normal file
80
gtk/gtkcolorscaleprivate.h
Normal file
@@ -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__ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user