shoes 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. data/.gitignore +12 -0
  2. data/CHANGELOG +29 -0
  3. data/COPYING +30 -0
  4. data/README.md +76 -0
  5. data/README.old +117 -0
  6. data/Rakefile +130 -0
  7. data/Rakefile.bk +651 -0
  8. data/app.yaml +7 -0
  9. data/bin/main.skel +104 -0
  10. data/bugs/issue-012e9468ddc7b0cb7e1503413a8a11c4f8707b67.yaml +21 -0
  11. data/bugs/issue-0711ff8b67baa63586f11d0096fee9dd4436bf58.yaml +23 -0
  12. data/bugs/issue-07f87998d93eb401e22395c11085676389b935c4.yaml +22 -0
  13. data/bugs/issue-0bff2d80008803cbc7efbcdacdc60ef2163664d2.yaml +22 -0
  14. data/bugs/issue-0c66f223d19efbca7b692f3b91961f407ad7abec.yaml +24 -0
  15. data/bugs/issue-183bc3c7a8f575aff2b24e0bf22aa0dfcc8e4fc2.yaml +29 -0
  16. data/bugs/issue-1bad1e60a04cb3adb6a8f3ded128af2e16b56ffe.yaml +18 -0
  17. data/bugs/issue-1f1d43f76bf4de79d7f94adbae6dd506a9d81633.yaml +41 -0
  18. data/bugs/issue-320924117cadb045cc91f2a6fca922b4d81d4bb5.yaml +20 -0
  19. data/bugs/issue-33e5c8355fbf65252ea9e939714651df8bd8cb3b.yaml +25 -0
  20. data/bugs/issue-36f7c8262a72bcd5e28cfa4ed29328b8237ea79b.yaml +20 -0
  21. data/bugs/issue-39bf04ee50c3bef67b89b8e9beb28657805587ce.yaml +18 -0
  22. data/bugs/issue-3e28ba7754f73d02ef416eef989af707a8c00f01.yaml +23 -0
  23. data/bugs/issue-3f638cc03f41f9c3fdf217355321f1563f8fee45.yaml +22 -0
  24. data/bugs/issue-41e48e14f1ef4f6deb69be68165d7dd3ffd99156.yaml +22 -0
  25. data/bugs/issue-4c9408166a2aa5dd333bbb05520deebf4ded08e0.yaml +22 -0
  26. data/bugs/issue-55c687e108ecd5aeb8e0d0aeb4294984f84acd3e.yaml +18 -0
  27. data/bugs/issue-5811d34692cc292717a58ec1df1f8948cf30d826.yaml +28 -0
  28. data/bugs/issue-5a7c1f59a0526f9cea7fb366867cf1e6ed8ef69d.yaml +22 -0
  29. data/bugs/issue-688a2c2566bef6a03efa57a4ae1f7cfa8fc74444.yaml +21 -0
  30. data/bugs/issue-78b16c7988ade2ef96e716fa8cb9a004bd4ced65.yaml +33 -0
  31. data/bugs/issue-804ee49f9800154eddf0650690c7a9bb5626253f.yaml +27 -0
  32. data/bugs/issue-807dd1c610b2e941a5d454e26b2eac27e89a0ab4.yaml +22 -0
  33. data/bugs/issue-822ee33ec11ebd25f90ea86e8438de7891e63aee.yaml +18 -0
  34. data/bugs/issue-82ff7152cebb8a1cb065b864cb4fe22de2328146.yaml +29 -0
  35. data/bugs/issue-856afbdcdd4970ad54b8ce4a6c017fbaab45f49d.yaml +31 -0
  36. data/bugs/issue-8d49e32fb21522651c67490adb4d80076dbb14e1.yaml +24 -0
  37. data/bugs/issue-91583359653a9d530c1e32be72d874d847a306e7.yaml +21 -0
  38. data/bugs/issue-af41a5229613172764e7d3c98431172db337053d.yaml +20 -0
  39. data/bugs/issue-bd9856b3788dd429c998a5af1b2aae8221cb80b7.yaml +28 -0
  40. data/bugs/issue-be22aef5c564fb7b5e9938343136a9cd6a2edb7b.yaml +22 -0
  41. data/bugs/issue-bf8697523c77c326e7e35fc82cf3dd739ae92310.yaml +27 -0
  42. data/bugs/issue-cdd4b4795f34d6ff46e56ece10f8216a4a5456b2.yaml +25 -0
  43. data/bugs/issue-d9bfb5581d745ef9deb3b9b2e08ef74d1cd43082.yaml +20 -0
  44. data/bugs/issue-e0ce2f687cc096f35715d28b0af88589f4ab6cc6.yaml +18 -0
  45. data/bugs/issue-e4b0aca4a10a574b333aeaecaaf221dbc5ed22c6.yaml +38 -0
  46. data/bugs/issue-f263746594b95ba778455730478ee8df60ee639d.yaml +22 -0
  47. data/bugs/project.yaml +72 -0
  48. data/builddeps.sh +102 -0
  49. data/fonts/Coolvetica.ttf +0 -0
  50. data/fonts/Lacuna.ttf +0 -0
  51. data/gemlib/shoes.rb +1 -0
  52. data/lib/shoes.rb +548 -0
  53. data/lib/shoes/cache.rb +54 -0
  54. data/lib/shoes/chipmunk.rb +35 -0
  55. data/lib/shoes/data.rb +39 -0
  56. data/lib/shoes/help.rb +468 -0
  57. data/lib/shoes/image.rb +25 -0
  58. data/lib/shoes/inspect.rb +128 -0
  59. data/lib/shoes/log.rb +48 -0
  60. data/lib/shoes/minitar.rb +986 -0
  61. data/lib/shoes/override.rb +38 -0
  62. data/lib/shoes/pack.rb +543 -0
  63. data/lib/shoes/search.rb +46 -0
  64. data/lib/shoes/setup.rb +329 -0
  65. data/lib/shoes/shy.rb +131 -0
  66. data/lib/shoes/shybuilder.rb +44 -0
  67. data/lib/shoes/version.rb +3 -0
  68. data/make/darwin/deps.vlc +12 -0
  69. data/make/darwin/dylibs.shoes +22 -0
  70. data/make/darwin/dylibs.video +11 -0
  71. data/make/darwin/env.rb +81 -0
  72. data/make/darwin/tasks.rb +105 -0
  73. data/make/linux/env.rb +65 -0
  74. data/make/linux/tasks.rb +61 -0
  75. data/make/make.rb +85 -0
  76. data/make/mingw/dlls +19 -0
  77. data/make/mingw/env.rb +69 -0
  78. data/make/mingw/tasks.rb +70 -0
  79. data/make/rakefile_common.rb +8 -0
  80. data/manual-snapshots/class-book.png +0 -0
  81. data/manual-snapshots/expert-definr.png +0 -0
  82. data/manual-snapshots/expert-funnies.png +0 -0
  83. data/manual-snapshots/expert-irb.png +0 -0
  84. data/manual-snapshots/expert-minesweeper.png +0 -0
  85. data/manual-snapshots/expert-othello.png +0 -0
  86. data/manual-snapshots/expert-pong.png +0 -0
  87. data/manual-snapshots/expert-tankspank.png +0 -0
  88. data/manual-snapshots/good-arc.png +0 -0
  89. data/manual-snapshots/good-clock.png +0 -0
  90. data/manual-snapshots/good-follow.png +0 -0
  91. data/manual-snapshots/good-reminder.png +0 -0
  92. data/manual-snapshots/good-vjot.png +0 -0
  93. data/manual-snapshots/simple-accordion.png +0 -0
  94. data/manual-snapshots/simple-anim-shapes.png +0 -0
  95. data/manual-snapshots/simple-anim-text.png +0 -0
  96. data/manual-snapshots/simple-arc.png +0 -0
  97. data/manual-snapshots/simple-bounce.png +0 -0
  98. data/manual-snapshots/simple-calc.png +0 -0
  99. data/manual-snapshots/simple-chipmunk.png +0 -0
  100. data/manual-snapshots/simple-control-sizes.png +0 -0
  101. data/manual-snapshots/simple-curve.png +0 -0
  102. data/manual-snapshots/simple-dialogs.png +0 -0
  103. data/manual-snapshots/simple-downloader.png +0 -0
  104. data/manual-snapshots/simple-draw.png +0 -0
  105. data/manual-snapshots/simple-editor.png +0 -0
  106. data/manual-snapshots/simple-form.png +0 -0
  107. data/manual-snapshots/simple-mask.png +0 -0
  108. data/manual-snapshots/simple-menu.png +0 -0
  109. data/manual-snapshots/simple-menu1.png +0 -0
  110. data/manual-snapshots/simple-rubygems.png +0 -0
  111. data/manual-snapshots/simple-slide.png +0 -0
  112. data/manual-snapshots/simple-sphere.png +0 -0
  113. data/manual-snapshots/simple-sqlite3.png +0 -0
  114. data/manual-snapshots/simple-timer.png +0 -0
  115. data/manual-snapshots/simple-video.png +0 -0
  116. data/platform/mac/Info.plist +55 -0
  117. data/platform/mac/build-deps.sh +658 -0
  118. data/platform/mac/command-manual.rb +1 -0
  119. data/platform/mac/deps-osx.patch +159 -0
  120. data/platform/mac/dmg_ds_store +0 -0
  121. data/platform/mac/pangorc +2 -0
  122. data/platform/mac/pkg-dmg +1447 -0
  123. data/platform/mac/shoes +31 -0
  124. data/platform/mac/shoes-launch +7 -0
  125. data/platform/mac/stub.m +178 -0
  126. data/platform/mac/version.plist +14 -0
  127. data/platform/msw/base.nsi +644 -0
  128. data/platform/msw/installer-1.bmp +0 -0
  129. data/platform/msw/installer-2.bmp +0 -0
  130. data/platform/msw/shoes.exe.manifest +17 -0
  131. data/platform/msw/shoes.ico +0 -0
  132. data/platform/msw/stub-inject.c +59 -0
  133. data/platform/msw/stub.c +271 -0
  134. data/platform/msw/stub32.h +14 -0
  135. data/platform/msw/stub32.rc +16 -0
  136. data/platform/nix/INSTALL +56 -0
  137. data/platform/nix/Makefile +144 -0
  138. data/platform/nix/shoes.launch +20 -0
  139. data/platform/skel.rb +27 -0
  140. data/rakefile_darwin.rb +7 -0
  141. data/rakefile_linux.rb +3 -0
  142. data/rakefile_mingw.rb +7 -0
  143. data/samples/class-book.rb +43 -0
  144. data/samples/class-book.yaml +387 -0
  145. data/samples/expert-definr.rb +23 -0
  146. data/samples/expert-funnies.rb +51 -0
  147. data/samples/expert-irb.rb +112 -0
  148. data/samples/expert-minesweeper.rb +267 -0
  149. data/samples/expert-othello.rb +319 -0
  150. data/samples/expert-pong.rb +62 -0
  151. data/samples/expert-tankspank.rb +385 -0
  152. data/samples/good-arc.rb +37 -0
  153. data/samples/good-clock.rb +51 -0
  154. data/samples/good-follow.rb +26 -0
  155. data/samples/good-reminder.rb +174 -0
  156. data/samples/good-vjot.rb +56 -0
  157. data/samples/simple-accordion.rb +75 -0
  158. data/samples/simple-anim-shapes.rb +17 -0
  159. data/samples/simple-anim-text.rb +13 -0
  160. data/samples/simple-arc.rb +23 -0
  161. data/samples/simple-bounce.rb +24 -0
  162. data/samples/simple-calc.rb +70 -0
  163. data/samples/simple-chipmunk.rb +26 -0
  164. data/samples/simple-control-sizes.rb +24 -0
  165. data/samples/simple-curve.rb +26 -0
  166. data/samples/simple-dialogs.rb +29 -0
  167. data/samples/simple-downloader.rb +27 -0
  168. data/samples/simple-draw.rb +13 -0
  169. data/samples/simple-editor.rb +28 -0
  170. data/samples/simple-form.rb +28 -0
  171. data/samples/simple-form.shy +0 -0
  172. data/samples/simple-mask.rb +21 -0
  173. data/samples/simple-menu.rb +31 -0
  174. data/samples/simple-menu1.rb +35 -0
  175. data/samples/simple-rubygems.rb +29 -0
  176. data/samples/simple-slide.rb +45 -0
  177. data/samples/simple-sphere.rb +28 -0
  178. data/samples/simple-sqlite3.rb +13 -0
  179. data/samples/simple-timer.rb +13 -0
  180. data/samples/simple-video.rb +13 -0
  181. data/shoes.gemspec +21 -0
  182. data/shoes/app.c +591 -0
  183. data/shoes/app.h +110 -0
  184. data/shoes/appwin32.h +13 -0
  185. data/shoes/appwin32.rc +28 -0
  186. data/shoes/canvas.c +2202 -0
  187. data/shoes/canvas.h +682 -0
  188. data/shoes/code.h +14 -0
  189. data/shoes/config.h +232 -0
  190. data/shoes/effects.c +243 -0
  191. data/shoes/effects.h +7 -0
  192. data/shoes/http.h +44 -0
  193. data/shoes/http/common.h +86 -0
  194. data/shoes/http/curl.c +259 -0
  195. data/shoes/http/nsurl.m +274 -0
  196. data/shoes/http/windownload.c +114 -0
  197. data/shoes/http/winhttp.c +216 -0
  198. data/shoes/http/winhttp.h +19 -0
  199. data/shoes/image.c +1020 -0
  200. data/shoes/internal.c +46 -0
  201. data/shoes/internal.h +63 -0
  202. data/shoes/native.h +110 -0
  203. data/shoes/native/cocoa.h +105 -0
  204. data/shoes/native/cocoa.m +1557 -0
  205. data/shoes/native/gtk.c +1257 -0
  206. data/shoes/native/windows.c +2392 -0
  207. data/shoes/ruby.c +5221 -0
  208. data/shoes/ruby.h +299 -0
  209. data/shoes/world.c +243 -0
  210. data/shoes/world.h +63 -0
  211. data/static/Shoes.icns +0 -0
  212. data/static/avatar.png +0 -0
  213. data/static/code_highlighter.js +188 -0
  214. data/static/code_highlighter_ruby.js +26 -0
  215. data/static/icon-debug.png +0 -0
  216. data/static/icon-error.png +0 -0
  217. data/static/icon-info.png +0 -0
  218. data/static/icon-warn.png +0 -0
  219. data/static/listbox_button1.png +0 -0
  220. data/static/listbox_button2.png +0 -0
  221. data/static/man-app.png +0 -0
  222. data/static/man-builds.png +0 -0
  223. data/static/man-builds1.png +0 -0
  224. data/static/man-editor-notepad.png +0 -0
  225. data/static/man-editor-osx.png +0 -0
  226. data/static/man-ele-background.png +0 -0
  227. data/static/man-ele-border.png +0 -0
  228. data/static/man-ele-button.png +0 -0
  229. data/static/man-ele-check.png +0 -0
  230. data/static/man-ele-editbox.png +0 -0
  231. data/static/man-ele-editline.png +0 -0
  232. data/static/man-ele-image.png +0 -0
  233. data/static/man-ele-listbox.png +0 -0
  234. data/static/man-ele-progress.png +0 -0
  235. data/static/man-ele-radio.png +0 -0
  236. data/static/man-ele-shape.png +0 -0
  237. data/static/man-ele-textblock.png +0 -0
  238. data/static/man-ele-video.png +0 -0
  239. data/static/man-intro-dmg.png +0 -0
  240. data/static/man-intro-exe.png +0 -0
  241. data/static/man-look-tiger.png +0 -0
  242. data/static/man-look-ubuntu.png +0 -0
  243. data/static/man-look-vista.png +0 -0
  244. data/static/man-run-osx.png +0 -0
  245. data/static/man-run-vista.png +0 -0
  246. data/static/man-run-xp.png +0 -0
  247. data/static/man-shot1.png +0 -0
  248. data/static/manual-en.txt +3531 -0
  249. data/static/manual-ja.txt +2825 -0
  250. data/static/manual.css +167 -0
  251. data/static/menu-corner1.png +0 -0
  252. data/static/menu-corner2.png +0 -0
  253. data/static/menu-gray.png +0 -0
  254. data/static/menu-left.png +0 -0
  255. data/static/menu-right.png +0 -0
  256. data/static/menu-top.png +0 -0
  257. data/static/shoes-dmg.jpg +0 -0
  258. data/static/shoes-icon-blue.png +0 -0
  259. data/static/shoes-icon.png +0 -0
  260. data/static/shoes-manual-apps.gif +0 -0
  261. data/static/shoes_main_window.png +0 -0
  262. data/static/stripe.png +0 -0
  263. data/static/stubs/blank.exe +0 -0
  264. data/static/stubs/blank.hfz +0 -0
  265. data/static/stubs/blank.run +375 -0
  266. data/static/stubs/cocoa-install +0 -0
  267. data/static/stubs/sh-install +49 -0
  268. data/static/stubs/shoes-stub-inject.exe +0 -0
  269. data/static/stubs/shoes-stub.exe +0 -0
  270. data/static/tutor-back.png +0 -0
  271. data/test/shoes_test.rb +8 -0
  272. data/test/test_helper.rb +25 -0
  273. data/use-deps +12 -0
  274. data/use-tmp-dep +8 -0
  275. metadata +509 -0
@@ -0,0 +1,1257 @@
1
+ //
2
+ // shoes/native-gtk.c
3
+ // GTK+ code for Shoes.
4
+ //
5
+ #include "shoes/app.h"
6
+ #include "shoes/ruby.h"
7
+ #include "shoes/config.h"
8
+ #include "shoes/world.h"
9
+ #include "shoes/native.h"
10
+ #include "shoes/internal.h"
11
+
12
+ #include <fontconfig/fontconfig.h>
13
+ #include <curl/curl.h>
14
+ #include <pthread.h>
15
+
16
+ #define GTK_CHILD(child, ptr) \
17
+ GList *children = gtk_container_get_children(GTK_CONTAINER(ptr)); \
18
+ child = children->data
19
+
20
+ #define HEIGHT_PAD 0
21
+
22
+ #define SHOES_GTK_INVISIBLE_CHAR (gunichar)0x2022
23
+
24
+ static VALUE
25
+ shoes_make_font_list(FcFontSet *fonts, VALUE ary)
26
+ {
27
+ int i = 0;
28
+ for (i = 0; i < fonts->nfont; i++)
29
+ {
30
+ FcValue val;
31
+ FcPattern *p = fonts->fonts[i];
32
+ if (FcPatternGet(p, FC_FAMILY, 0, &val) == FcResultMatch)
33
+ rb_ary_push(ary, rb_str_new2((char *)val.u.s));
34
+ }
35
+ rb_funcall(ary, rb_intern("uniq!"), 0);
36
+ rb_funcall(ary, rb_intern("sort!"), 0);
37
+ return ary;
38
+ }
39
+
40
+ VALUE
41
+ shoes_font_list()
42
+ {
43
+ VALUE ary = rb_ary_new();
44
+ FcConfig *fc = FcConfigGetCurrent();
45
+ FcFontSet *fonts = FcConfigGetFonts(fc, FcSetApplication);
46
+ if (fonts) shoes_make_font_list(fonts, ary);
47
+ fonts = FcConfigGetFonts(fc, FcSetSystem);
48
+ if (fonts) shoes_make_font_list(fonts, ary);
49
+ return ary;
50
+ }
51
+
52
+ VALUE
53
+ shoes_load_font(const char *filename)
54
+ {
55
+ FcConfig *fc = FcConfigGetCurrent();
56
+ FcFontSet *fonts = FcFontSetCreate();
57
+ if (!FcFileScan(fonts, NULL, NULL, NULL, (const FcChar8 *)filename, FcTrue))
58
+ return Qnil;
59
+
60
+ VALUE ary = rb_ary_new();
61
+ shoes_make_font_list(fonts, ary);
62
+ FcFontSetDestroy(fonts);
63
+
64
+ if (!FcConfigAppFontAddFile(fc, (const FcChar8 *)filename))
65
+ return Qnil;
66
+
67
+ // refresh the FONTS list
68
+ shoes_update_fonts(shoes_font_list());
69
+ return ary;
70
+ }
71
+
72
+ void shoes_native_init()
73
+ {
74
+ curl_global_init(CURL_GLOBAL_ALL);
75
+ gtk_init(NULL, NULL);
76
+ }
77
+
78
+ void shoes_native_cleanup(shoes_world_t *world)
79
+ {
80
+ curl_global_cleanup();
81
+ }
82
+
83
+ void shoes_native_quit()
84
+ {
85
+ gtk_main_quit();
86
+ }
87
+
88
+ void shoes_get_time(SHOES_TIME *ts)
89
+ {
90
+ clock_gettime(CLOCK_REALTIME, ts);
91
+ }
92
+
93
+ unsigned long shoes_diff_time(SHOES_TIME *start, SHOES_TIME *end)
94
+ {
95
+ unsigned long usec;
96
+ if ((end->tv_nsec-start->tv_nsec)<0) {
97
+ usec = (end->tv_sec-start->tv_sec - 1) * 1000;
98
+ usec += (1000000000 + end->tv_nsec - start->tv_nsec) / 1000000;
99
+ } else {
100
+ usec = (end->tv_sec - start->tv_sec) * 1000;
101
+ usec += (end->tv_nsec - start->tv_nsec) / 1000000;
102
+ }
103
+ return usec;
104
+ }
105
+
106
+ typedef struct {
107
+ unsigned int name;
108
+ VALUE obj;
109
+ void *data;
110
+ pthread_mutex_t mutex;
111
+ pthread_cond_t cond;
112
+ int ret;
113
+ } shoes_gtk_msg;
114
+
115
+ static gboolean
116
+ shoes_gtk_catch_message(gpointer user) {
117
+ shoes_gtk_msg *msg = (shoes_gtk_msg *)user;
118
+ pthread_mutex_lock(&msg->mutex);
119
+ msg->ret = shoes_catch_message(msg->name, msg->obj, msg->data);
120
+ pthread_cond_signal(&msg->cond);
121
+ pthread_mutex_unlock(&msg->mutex);
122
+ return FALSE;
123
+ }
124
+
125
+ int shoes_throw_message(unsigned int name, VALUE obj, void *data)
126
+ {
127
+ int ret;
128
+ shoes_gtk_msg *msg = SHOE_ALLOC(shoes_gtk_msg);
129
+ msg->name = name;
130
+ msg->obj = obj;
131
+ msg->data = data;
132
+ pthread_mutex_init(&msg->mutex, NULL);
133
+ pthread_cond_init(&msg->cond, NULL);
134
+ msg->ret = 0;
135
+
136
+ pthread_mutex_lock(&msg->mutex);
137
+ g_idle_add_full(G_PRIORITY_DEFAULT, shoes_gtk_catch_message, msg, NULL);
138
+ pthread_cond_wait(&msg->cond, &msg->mutex);
139
+ ret = msg->ret;
140
+ pthread_mutex_unlock(&msg->mutex);
141
+
142
+ free(msg);
143
+ return ret;
144
+ }
145
+
146
+ void shoes_native_slot_mark(SHOES_SLOT_OS *slot) {}
147
+ void shoes_native_slot_reset(SHOES_SLOT_OS *slot) {}
148
+ void shoes_native_slot_clear(shoes_canvas *canvas)
149
+ {
150
+ if (canvas->slot->vscroll)
151
+ {
152
+ GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(canvas->slot->vscroll));
153
+ gtk_adjustment_set_value(adj, adj->lower);
154
+ }
155
+ }
156
+
157
+ void shoes_native_slot_paint(SHOES_SLOT_OS *slot)
158
+ {
159
+ gtk_widget_queue_draw(slot->canvas);
160
+ }
161
+
162
+ void shoes_native_slot_lengthen(SHOES_SLOT_OS *slot, int height, int endy)
163
+ {
164
+ if (slot->vscroll)
165
+ {
166
+ GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(slot->vscroll));
167
+ if (adj->upper != (gdouble)endy)
168
+ {
169
+ gtk_range_set_range(GTK_RANGE(slot->vscroll), 0., (gdouble)endy);
170
+ if (adj->page_size >= adj->upper)
171
+ gtk_widget_hide(slot->vscroll);
172
+ else
173
+ gtk_widget_show(slot->vscroll);
174
+ }
175
+ }
176
+ }
177
+
178
+ void shoes_native_slot_scroll_top(SHOES_SLOT_OS *slot)
179
+ {
180
+ if (slot->vscroll)
181
+ gtk_range_set_value(GTK_RANGE(slot->vscroll), slot->scrolly);
182
+ }
183
+
184
+ int shoes_native_slot_gutter(SHOES_SLOT_OS *slot)
185
+ {
186
+ if (slot->vscroll)
187
+ {
188
+ GtkRequisition req;
189
+ gtk_widget_size_request(slot->vscroll, &req);
190
+ return req.width;
191
+ }
192
+ return 0;
193
+ }
194
+
195
+ void shoes_native_remove_item(SHOES_SLOT_OS *slot, VALUE item, char c)
196
+ {
197
+ }
198
+
199
+ //
200
+ // Window-level events
201
+ //
202
+ static gboolean
203
+ shoes_app_gtk_motion(GtkWidget *widget, GdkEventMotion *event, gpointer data)
204
+ {
205
+ GdkModifierType state;
206
+ shoes_app *app = (shoes_app *)data;
207
+ if (!event->is_hint)
208
+ {
209
+ shoes_canvas *canvas;
210
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
211
+ state = (GdkModifierType)event->state;
212
+ shoes_app_motion(app, (int)event->x, (int)event->y + canvas->slot->scrolly);
213
+ }
214
+ return TRUE;
215
+ }
216
+
217
+ static gboolean
218
+ shoes_app_gtk_button(GtkWidget *widget, GdkEventButton *event, gpointer data)
219
+ {
220
+ shoes_app *app = (shoes_app *)data;
221
+ shoes_canvas *canvas;
222
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
223
+ if (event->type == GDK_BUTTON_PRESS)
224
+ {
225
+ shoes_app_click(app, event->button, event->x, event->y + canvas->slot->scrolly);
226
+ }
227
+ else if (event->type == GDK_BUTTON_RELEASE)
228
+ {
229
+ shoes_app_release(app, event->button, event->x, event->y + canvas->slot->scrolly);
230
+ }
231
+ return TRUE;
232
+ }
233
+
234
+ static gboolean
235
+ shoes_app_gtk_wheel(GtkWidget *widget, GdkEventScroll *event, gpointer data)
236
+ {
237
+ ID wheel;
238
+ shoes_app *app = (shoes_app *)data;
239
+ switch (event->direction)
240
+ {
241
+ case GDK_SCROLL_UP: wheel = s_up; break;
242
+ case GDK_SCROLL_DOWN: wheel = s_down; break;
243
+ case GDK_SCROLL_LEFT: wheel = s_left; break;
244
+ case GDK_SCROLL_RIGHT: wheel = s_right; break;
245
+ default: return TRUE;
246
+ }
247
+
248
+ shoes_app_wheel(app, wheel, event->x, event->y);
249
+ return TRUE;
250
+ }
251
+
252
+ static void
253
+ shoes_app_gtk_paint (GtkWidget *widget, GdkEventExpose *event, gpointer data)
254
+ {
255
+ shoes_app *app = (shoes_app *)data;
256
+ gtk_window_get_size(GTK_WINDOW(app->os.window), &app->width, &app->height);
257
+ shoes_canvas_size(app->canvas, app->width, app->height);
258
+ }
259
+
260
+ #define KEY_SYM(name, sym) \
261
+ else if (event->keyval == GDK_##name) \
262
+ v = ID2SYM(rb_intern("" # sym))
263
+
264
+ static gboolean
265
+ shoes_app_gtk_keypress (GtkWidget *widget, GdkEventKey *event, gpointer data)
266
+ {
267
+ VALUE v = Qnil;
268
+ guint modifiers = event->state;
269
+ shoes_app *app = (shoes_app *)data;
270
+ if (event->keyval == GDK_Return)
271
+ {
272
+ v = rb_str_new2("\n");
273
+ }
274
+ KEY_SYM(Escape, escape);
275
+ else if (event->length > 0)
276
+ {
277
+ if ((event->state & GDK_CONTROL_MASK) || (event->state & GDK_MOD1_MASK))
278
+ {
279
+ gint len;
280
+ gunichar ch;
281
+ char chbuf[7] = {0};
282
+
283
+ ch = gdk_keyval_to_unicode(event->keyval);
284
+ len = g_unichar_to_utf8(ch, chbuf);
285
+ chbuf[len] = '\0';
286
+
287
+ v = ID2SYM(rb_intern(chbuf));
288
+ if (modifiers & GDK_SHIFT_MASK) modifiers ^= GDK_SHIFT_MASK;
289
+ }
290
+ else
291
+ {
292
+ if (event->string[0] == '\r' && event->length == 1)
293
+ v = rb_str_new2("\n");
294
+ else
295
+ v = rb_str_new(event->string, event->length);
296
+ }
297
+ }
298
+ KEY_SYM(Insert, insert);
299
+ KEY_SYM(Delete, delete);
300
+ KEY_SYM(BackSpace, backspace);
301
+ KEY_SYM(Tab, tab);
302
+ KEY_SYM(ISO_Left_Tab, tab);
303
+ KEY_SYM(Page_Up, page_up);
304
+ KEY_SYM(Page_Down, page_down);
305
+ KEY_SYM(Home, home);
306
+ KEY_SYM(End, end);
307
+ KEY_SYM(Left, left);
308
+ KEY_SYM(Up, up);
309
+ KEY_SYM(Right, right);
310
+ KEY_SYM(Down, down);
311
+ KEY_SYM(F1, f1);
312
+ KEY_SYM(F2, f2);
313
+ KEY_SYM(F3, f3);
314
+ KEY_SYM(F4, f4);
315
+ KEY_SYM(F5, f5);
316
+ KEY_SYM(F6, f6);
317
+ KEY_SYM(F7, f7);
318
+ KEY_SYM(F8, f8);
319
+ KEY_SYM(F9, f9);
320
+ KEY_SYM(F10, f10);
321
+ KEY_SYM(F11, f11);
322
+ KEY_SYM(F12, f12);
323
+
324
+ if (v != Qnil) {
325
+ if (event->type == GDK_KEY_PRESS) {
326
+ shoes_app_keydown(app, v);
327
+
328
+ if (event->keyval == GDK_Return)
329
+ if ((event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0)
330
+ v = ID2SYM(rb_intern("enter"));
331
+
332
+ if (SYMBOL_P(v))
333
+ {
334
+ if (modifiers & GDK_MOD1_MASK)
335
+ KEY_STATE(alt);
336
+ if (modifiers & GDK_SHIFT_MASK)
337
+ KEY_STATE(shift);
338
+ if (modifiers & GDK_CONTROL_MASK)
339
+ KEY_STATE(control);
340
+ }
341
+
342
+ shoes_app_keypress(app, v);
343
+ } else {
344
+ shoes_app_keyup(app, v);
345
+ }
346
+ }
347
+
348
+ return FALSE;
349
+ }
350
+
351
+ static gboolean
352
+ shoes_app_gtk_quit(GtkWidget *widget, GdkEvent *event, gpointer data)
353
+ {
354
+ shoes_app *app = (shoes_app *)data;
355
+ if (shoes_app_remove(app))
356
+ gtk_main_quit();
357
+ return FALSE;
358
+ }
359
+
360
+ static void
361
+ shoes_canvas_gtk_paint_children(GtkWidget *widget, gpointer data)
362
+ {
363
+ shoes_canvas *canvas = (shoes_canvas *)data;
364
+ gtk_container_propagate_expose(GTK_CONTAINER(canvas->slot->canvas), widget, canvas->slot->expose);
365
+ }
366
+
367
+ static void
368
+ shoes_canvas_gtk_paint(GtkWidget *widget, GdkEventExpose *event, gpointer data)
369
+ {
370
+ VALUE c = (VALUE)data;
371
+ shoes_canvas *canvas;
372
+ INFO("EXPOSE: (%d, %d) (%d, %d) %lu, %d, %d\n", event->area.x, event->area.y,
373
+ event->area.width, event->area.height, c, (int)event->send_event, event->count);
374
+ Data_Get_Struct(c, shoes_canvas, canvas);
375
+
376
+ //
377
+ // Since I'm using a GtkFixed container, I need to force it to be clipped on its boundaries.
378
+ // This could be done by using a whole lot of gdk_window_begin_paint_region calls, but that
379
+ // would also mean masking every region for every element... This approach is simple. Clip
380
+ // the expose region and pass it on.
381
+ //
382
+ canvas->slot->expose = event;
383
+ GdkRegion *region = event->region;
384
+ GdkRectangle rect = event->area;
385
+ event->region = gdk_region_rectangle(&canvas->slot->canvas->allocation);
386
+ gdk_region_intersect(event->region, region);
387
+ gdk_region_get_clipbox(event->region, &event->area);
388
+
389
+ shoes_canvas_paint(c);
390
+ gtk_container_forall(GTK_CONTAINER(widget), shoes_canvas_gtk_paint_children, canvas);
391
+
392
+ //
393
+ // Restore the full region to the event.
394
+ //
395
+ gdk_region_destroy(event->region);
396
+ event->region = region;
397
+ event->area = rect;
398
+ canvas->slot->expose = NULL;
399
+ }
400
+
401
+ static void
402
+ shoes_canvas_gtk_size(GtkWidget *widget, GtkAllocation *size, gpointer data)
403
+ {
404
+ VALUE c = (VALUE)data;
405
+ shoes_canvas *canvas;
406
+ Data_Get_Struct(c, shoes_canvas, canvas);
407
+ if (canvas->slot->vscroll &&
408
+ (size->height != canvas->slot->scrollh || size->width != canvas->slot->scrollw))
409
+ {
410
+ GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(canvas->slot->vscroll));
411
+ gtk_widget_set_size_request(canvas->slot->vscroll, -1, size->height);
412
+ gtk_fixed_move(GTK_FIXED(canvas->slot->canvas), canvas->slot->vscroll,
413
+ size->width - canvas->slot->vscroll->allocation.width, 0);
414
+ adj->page_size = size->height;
415
+ adj->page_increment = size->height - 32;
416
+ if (adj->page_size >= adj->upper)
417
+ gtk_widget_hide(canvas->slot->vscroll);
418
+ else
419
+ gtk_widget_show(canvas->slot->vscroll);
420
+ canvas->slot->scrollh = size->height;
421
+ canvas->slot->scrollw = size->width;
422
+ }
423
+ }
424
+
425
+ static void
426
+ shoes_canvas_gtk_scroll(GtkRange *r, gpointer data)
427
+ {
428
+ VALUE c = (VALUE)data;
429
+ shoes_canvas *canvas;
430
+ Data_Get_Struct(c, shoes_canvas, canvas);
431
+ canvas->slot->scrolly = (int)gtk_range_get_value(r);
432
+ shoes_slot_repaint(canvas->app->slot);
433
+ }
434
+
435
+ static gint
436
+ shoes_app_g_poll (GPollFD *fds, guint nfds, gint timeout)
437
+ {
438
+ struct timeval tv;
439
+ fd_set rset, wset, xset;
440
+ GPollFD *f;
441
+ int ready;
442
+ int maxfd = 0;
443
+
444
+ FD_ZERO (&rset);
445
+ FD_ZERO (&wset);
446
+ FD_ZERO (&xset);
447
+
448
+ for (f = fds; f < &fds[nfds]; ++f)
449
+ if (f->fd >= 0)
450
+ {
451
+ if (f->events & G_IO_IN)
452
+ FD_SET (f->fd, &rset);
453
+ if (f->events & G_IO_OUT)
454
+ FD_SET (f->fd, &wset);
455
+ if (f->events & G_IO_PRI)
456
+ FD_SET (f->fd, &xset);
457
+ if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI)))
458
+ maxfd = f->fd;
459
+ }
460
+
461
+ //
462
+ // If we poll indefinitely, then the window updates will
463
+ // pile up for as long as Ruby is churning away.
464
+ //
465
+ // Give Ruby half-seconds in which to work, in order to
466
+ // keep it from completely blocking the GUI.
467
+ //
468
+ if (timeout == -1 || timeout > 500)
469
+ timeout = 500;
470
+
471
+ tv.tv_sec = timeout / 1000;
472
+ tv.tv_usec = (timeout % 1000) * 1000;
473
+
474
+ ready = rb_thread_select (maxfd + 1, &rset, &wset, &xset, &tv);
475
+ if (ready > 0)
476
+ for (f = fds; f < &fds[nfds]; ++f)
477
+ {
478
+ f->revents = 0;
479
+ if (f->fd >= 0)
480
+ {
481
+ if (FD_ISSET (f->fd, &rset))
482
+ f->revents |= G_IO_IN;
483
+ if (FD_ISSET (f->fd, &wset))
484
+ f->revents |= G_IO_OUT;
485
+ if (FD_ISSET (f->fd, &xset))
486
+ f->revents |= G_IO_PRI;
487
+ }
488
+ }
489
+
490
+ return ready;
491
+ }
492
+
493
+ shoes_code
494
+ shoes_app_cursor(shoes_app *app, ID cursor)
495
+ {
496
+ if (app->os.window == NULL || app->os.window->window == NULL || app->cursor == cursor)
497
+ goto done;
498
+
499
+ GdkCursor *c;
500
+ if (cursor == s_hand || cursor == s_link)
501
+ {
502
+ c = gdk_cursor_new(GDK_HAND2);
503
+ }
504
+ else if (cursor == s_arrow)
505
+ {
506
+ c = gdk_cursor_new(GDK_ARROW);
507
+ }
508
+ else if (cursor == s_text)
509
+ {
510
+ c = gdk_cursor_new(GDK_XTERM);
511
+ }
512
+ else
513
+ goto done;
514
+
515
+ gdk_window_set_cursor(app->os.window->window, c);
516
+
517
+ app->cursor = cursor;
518
+
519
+ done:
520
+ return SHOES_OK;
521
+ }
522
+
523
+ void
524
+ shoes_native_app_resized(shoes_app *app)
525
+ {
526
+ if (app->os.window != NULL)
527
+ gtk_widget_set_size_request(app->os.window, app->width, app->height);
528
+ }
529
+
530
+ void
531
+ shoes_native_app_title(shoes_app *app, char *msg)
532
+ {
533
+ gtk_window_set_title(GTK_WINDOW(app->os.window), _(msg));
534
+ }
535
+
536
+ void
537
+ shoes_native_app_fullscreen(shoes_app *app, char yn)
538
+ {
539
+ gtk_window_set_keep_above(GTK_WINDOW(app->os.window), (gboolean)yn);
540
+ if (yn)
541
+ gtk_window_fullscreen(GTK_WINDOW(app->os.window));
542
+ else
543
+ gtk_window_unfullscreen(GTK_WINDOW(app->os.window));
544
+ }
545
+
546
+ shoes_code
547
+ shoes_native_app_open(shoes_app *app, char *path, int dialog)
548
+ {
549
+ char icon_path[SHOES_BUFSIZE];
550
+ shoes_app_gtk *gk = &app->os;
551
+
552
+ sprintf(icon_path, "%s/static/app-icon.png", shoes_world->path);
553
+ gtk_window_set_default_icon_from_file(icon_path, NULL);
554
+ gk->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
555
+ gtk_window_set_position(GTK_WINDOW(gk->window), GTK_WIN_POS_CENTER);
556
+ if (app->minwidth < app->width || app->minheight < app->height)
557
+ {
558
+ GdkGeometry hints;
559
+ hints.min_width = app->minwidth;
560
+ hints.min_height = app->minheight;
561
+ gtk_window_set_geometry_hints(GTK_WINDOW(gk->window), NULL,
562
+ &hints, GDK_HINT_MIN_SIZE);
563
+ }
564
+ if (!app->resizable)
565
+ gtk_window_set_resizable(GTK_WINDOW(gk->window), FALSE);
566
+ if (app->fullscreen)
567
+ shoes_native_app_fullscreen(app, 1);
568
+ gtk_widget_set_events(gk->window, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
569
+ g_signal_connect(G_OBJECT(gk->window), "size-allocate",
570
+ G_CALLBACK(shoes_app_gtk_paint), app);
571
+ g_signal_connect(G_OBJECT(gk->window), "motion-notify-event",
572
+ G_CALLBACK(shoes_app_gtk_motion), app);
573
+ g_signal_connect(G_OBJECT(gk->window), "button-press-event",
574
+ G_CALLBACK(shoes_app_gtk_button), app);
575
+ g_signal_connect(G_OBJECT(gk->window), "button-release-event",
576
+ G_CALLBACK(shoes_app_gtk_button), app);
577
+ g_signal_connect(G_OBJECT(gk->window), "scroll-event",
578
+ G_CALLBACK(shoes_app_gtk_wheel), app);
579
+ g_signal_connect(G_OBJECT(gk->window), "key-press-event",
580
+ G_CALLBACK(shoes_app_gtk_keypress), app);
581
+ g_signal_connect(G_OBJECT(gk->window), "key-release-event",
582
+ G_CALLBACK(shoes_app_gtk_keypress), app);
583
+ g_signal_connect(G_OBJECT(gk->window), "delete-event",
584
+ G_CALLBACK(shoes_app_gtk_quit), app);
585
+ app->slot->canvas = gk->window;
586
+ return SHOES_OK;
587
+ }
588
+
589
+ void
590
+ shoes_native_app_show(shoes_app *app)
591
+ {
592
+ gtk_widget_show_all(app->os.window);
593
+ }
594
+
595
+ void
596
+ shoes_native_loop()
597
+ {
598
+ g_main_set_poll_func(shoes_app_g_poll);
599
+ gtk_main();
600
+ }
601
+
602
+ void
603
+ shoes_native_app_close(shoes_app *app)
604
+ {
605
+ shoes_app_gtk_quit(app->os.window, NULL, (gpointer)app);
606
+ gtk_widget_destroy(app->os.window);
607
+ app->os.window = NULL;
608
+ }
609
+
610
+ void
611
+ shoes_browser_open(char *url)
612
+ {
613
+ VALUE browser = rb_str_new2("/etc/alternatives/x-www-browser '");
614
+ rb_str_cat2(browser, url);
615
+ rb_str_cat2(browser, "' 2>/dev/null &");
616
+ shoes_sys(RSTRING_PTR(browser), 1);
617
+ }
618
+
619
+ void
620
+ shoes_slot_init(VALUE c, SHOES_SLOT_OS *parent, int x, int y, int width, int height, int scrolls, int toplevel)
621
+ {
622
+ shoes_canvas *canvas;
623
+ SHOES_SLOT_OS *slot;
624
+ Data_Get_Struct(c, shoes_canvas, canvas);
625
+
626
+ slot = shoes_slot_alloc(canvas, parent, toplevel);
627
+ slot->canvas = gtk_fixed_new();
628
+ INFO("shoes_slot_init(%lu)\n", c);
629
+ g_signal_connect(G_OBJECT(slot->canvas), "expose-event",
630
+ G_CALLBACK(shoes_canvas_gtk_paint), (gpointer)c);
631
+ g_signal_connect(G_OBJECT(slot->canvas), "size-allocate",
632
+ G_CALLBACK(shoes_canvas_gtk_size), (gpointer)c);
633
+ if (toplevel)
634
+ gtk_container_add(GTK_CONTAINER(parent->canvas), slot->canvas);
635
+ else
636
+ gtk_fixed_put(GTK_FIXED(parent->canvas), slot->canvas, x, y);
637
+
638
+ slot->scrollh = slot->scrollw = 0;
639
+ slot->vscroll = NULL;
640
+ if (scrolls)
641
+ {
642
+ slot->vscroll = gtk_vscrollbar_new(NULL);
643
+ gtk_range_get_adjustment(GTK_RANGE(slot->vscroll))->step_increment = 16;
644
+ gtk_range_get_adjustment(GTK_RANGE(slot->vscroll))->page_increment = height - 32;
645
+ g_signal_connect(G_OBJECT(slot->vscroll), "value-changed",
646
+ G_CALLBACK(shoes_canvas_gtk_scroll), (gpointer)c);
647
+ gtk_fixed_put(GTK_FIXED(slot->canvas), slot->vscroll, -100, -100);
648
+ }
649
+
650
+ gtk_widget_set_size_request(slot->canvas, width, height);
651
+ slot->expose = NULL;
652
+ if (toplevel) shoes_canvas_size(c, width, height);
653
+ else
654
+ {
655
+ gtk_widget_show_all(slot->canvas);
656
+ canvas->width = 100;
657
+ canvas->height = 100;
658
+ }
659
+ }
660
+
661
+ void
662
+ shoes_slot_destroy(shoes_canvas *canvas, shoes_canvas *pc)
663
+ {
664
+ if (canvas->slot->vscroll)
665
+ gtk_container_remove(GTK_CONTAINER(canvas->slot->canvas), canvas->slot->vscroll);
666
+ gtk_container_remove(GTK_CONTAINER(pc->slot->canvas), canvas->slot->canvas);
667
+ }
668
+
669
+ cairo_t *
670
+ shoes_cairo_create(shoes_canvas *canvas)
671
+ {
672
+ cairo_t *cr = gdk_cairo_create(canvas->slot->canvas->window);
673
+ if (canvas->slot->expose != NULL)
674
+ {
675
+ GdkRegion *region = gdk_region_rectangle(&canvas->slot->canvas->allocation);
676
+ gdk_region_intersect(region, canvas->slot->expose->region);
677
+ gdk_cairo_region(cr, region);
678
+ gdk_region_destroy(region);
679
+ cairo_clip(cr);
680
+ cairo_translate(cr, canvas->slot->canvas->allocation.x, canvas->slot->canvas->allocation.y - canvas->slot->scrolly);
681
+ }
682
+ return cr;
683
+ }
684
+
685
+ void
686
+ shoes_cairo_destroy(shoes_canvas *canvas)
687
+ {
688
+ }
689
+
690
+ void
691
+ shoes_group_clear(SHOES_GROUP_OS *group)
692
+ {
693
+ group->radios = NULL;
694
+ group->layout = NULL;
695
+ }
696
+
697
+ void
698
+ shoes_native_canvas_place(shoes_canvas *self_t, shoes_canvas *pc)
699
+ {
700
+ int x, y, newy;
701
+ GtkAllocation *a = &self_t->slot->canvas->allocation;
702
+ gtk_widget_translate_coordinates(self_t->slot->canvas, pc->slot->canvas, 0, 0, &x, &y);
703
+ newy = (self_t->place.iy + self_t->place.dy) - pc->slot->scrolly;
704
+
705
+ if (x != self_t->place.ix + self_t->place.dx || y != newy)
706
+ gtk_fixed_move(GTK_FIXED(pc->slot->canvas), self_t->slot->canvas,
707
+ self_t->place.ix + self_t->place.dx, newy);
708
+
709
+ if (a->width != self_t->place.iw || a->height != self_t->place.ih)
710
+ gtk_widget_set_size_request(self_t->slot->canvas, self_t->place.iw, self_t->place.ih);
711
+ }
712
+
713
+ void
714
+ shoes_native_canvas_resize(shoes_canvas *canvas)
715
+ {
716
+ }
717
+
718
+ static void
719
+ shoes_widget_changed(GtkWidget *ref, gpointer data)
720
+ {
721
+ VALUE self = (VALUE)data;
722
+ shoes_control_send(self, s_change);
723
+ }
724
+
725
+ void
726
+ shoes_native_control_hide(SHOES_CONTROL_REF ref)
727
+ {
728
+ gtk_widget_hide(ref);
729
+ }
730
+
731
+ void
732
+ shoes_native_control_show(SHOES_CONTROL_REF ref)
733
+ {
734
+ gtk_widget_show(ref);
735
+ }
736
+
737
+ void
738
+ shoes_native_control_position(SHOES_CONTROL_REF ref, shoes_place *p1, VALUE self,
739
+ shoes_canvas *canvas, shoes_place *p2)
740
+ {
741
+ PLACE_COORDS();
742
+ gtk_widget_set_size_request(ref, p2->iw, p2->ih);
743
+ gtk_fixed_put(GTK_FIXED(canvas->slot->canvas),
744
+ ref, p2->ix + p2->dx, p2->iy + p2->dy);
745
+ gtk_widget_show_all(ref);
746
+ }
747
+
748
+ void
749
+ shoes_native_control_repaint(SHOES_CONTROL_REF ref, shoes_place *p1,
750
+ shoes_canvas *canvas, shoes_place *p2)
751
+ {
752
+ p2->iy -= canvas->slot->scrolly;
753
+ if (CHANGED_COORDS()) {
754
+ PLACE_COORDS();
755
+ gtk_fixed_move(GTK_FIXED(canvas->slot->canvas),
756
+ ref, p2->ix + p2->dx, p2->iy + p2->dy);
757
+ gtk_widget_set_size_request(ref, p2->iw, p2->ih);
758
+ }
759
+ p2->iy += canvas->slot->scrolly;
760
+ }
761
+
762
+ void
763
+ shoes_native_control_focus(SHOES_CONTROL_REF ref)
764
+ {
765
+ if (GTK_WIDGET_CAN_FOCUS(ref)) gtk_widget_grab_focus(ref);
766
+ }
767
+
768
+ void
769
+ shoes_native_control_state(SHOES_CONTROL_REF ref, gboolean sensitive, gboolean setting)
770
+ {
771
+ gtk_widget_set_sensitive(ref, sensitive);
772
+ if (GTK_IS_EDITABLE(ref))
773
+ gtk_editable_set_editable(GTK_EDITABLE(ref), setting);
774
+ else if (GTK_IS_SCROLLED_WINDOW(ref))
775
+ {
776
+ GtkWidget *textview;
777
+ GTK_CHILD(textview, ref);
778
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), setting);
779
+ }
780
+ }
781
+
782
+ void
783
+ shoes_native_control_remove(SHOES_CONTROL_REF ref, shoes_canvas *canvas)
784
+ {
785
+ gtk_container_remove(GTK_CONTAINER(canvas->slot->canvas), ref);
786
+ }
787
+
788
+ void
789
+ shoes_native_control_free(SHOES_CONTROL_REF ref)
790
+ {
791
+ //
792
+ // no need to free gtk widgets, since gtk seems
793
+ // to garbage collect them fine. and memory
794
+ // addresses often get reused.
795
+ //
796
+ }
797
+
798
+ SHOES_SURFACE_REF
799
+ shoes_native_surface_new(shoes_canvas *canvas, VALUE self, shoes_place *place)
800
+ {
801
+ return gtk_drawing_area_new();
802
+ }
803
+
804
+ void
805
+ shoes_native_surface_position(SHOES_SURFACE_REF ref, shoes_place *p1,
806
+ VALUE self, shoes_canvas *canvas, shoes_place *p2)
807
+ {
808
+ shoes_native_control_position(ref, p1, self, canvas, p2);
809
+ }
810
+
811
+ void
812
+ shoes_native_surface_hide(SHOES_SURFACE_REF ref)
813
+ {
814
+ shoes_native_control_hide(ref);
815
+ }
816
+
817
+ void
818
+ shoes_native_surface_show(SHOES_SURFACE_REF ref)
819
+ {
820
+ shoes_native_control_show(ref);
821
+ }
822
+
823
+ void
824
+ shoes_native_surface_remove(shoes_canvas *canvas, SHOES_SURFACE_REF ref)
825
+ {
826
+ gtk_container_remove(GTK_CONTAINER(canvas->slot->canvas), ref);
827
+ }
828
+
829
+ static gboolean
830
+ shoes_button_gtk_clicked(GtkButton *button, gpointer data)
831
+ {
832
+ VALUE self = (VALUE)data;
833
+ shoes_control_send(self, s_click);
834
+ return TRUE;
835
+ }
836
+
837
+ SHOES_CONTROL_REF
838
+ shoes_native_button(VALUE self, shoes_canvas *canvas, shoes_place *place, char *msg)
839
+ {
840
+ SHOES_CONTROL_REF ref = gtk_button_new_with_label(_(msg));
841
+ g_signal_connect(G_OBJECT(ref), "clicked",
842
+ G_CALLBACK(shoes_button_gtk_clicked),
843
+ (gpointer)self);
844
+ return ref;
845
+ }
846
+
847
+ void
848
+ shoes_native_secrecy(SHOES_CONTROL_REF ref)
849
+ {
850
+ gtk_entry_set_visibility(GTK_ENTRY(ref), FALSE);
851
+ gtk_entry_set_invisible_char(GTK_ENTRY(ref), SHOES_GTK_INVISIBLE_CHAR);
852
+ }
853
+
854
+ SHOES_CONTROL_REF
855
+ shoes_native_edit_line(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
856
+ {
857
+ SHOES_CONTROL_REF ref = gtk_entry_new();
858
+ if (RTEST(ATTR(attr, secret))) shoes_native_secrecy(ref);
859
+ gtk_entry_set_text(GTK_ENTRY(ref), _(msg));
860
+ g_signal_connect(G_OBJECT(ref), "changed",
861
+ G_CALLBACK(shoes_widget_changed),
862
+ (gpointer)self);
863
+ return ref;
864
+ }
865
+
866
+ VALUE
867
+ shoes_native_edit_line_get_text(SHOES_CONTROL_REF ref)
868
+ {
869
+ return rb_str_new2(gtk_entry_get_text(GTK_ENTRY(ref)));
870
+ }
871
+
872
+ void
873
+ shoes_native_edit_line_set_text(SHOES_CONTROL_REF ref, char *msg)
874
+ {
875
+ gtk_entry_set_text(GTK_ENTRY(ref), _(msg));
876
+ }
877
+
878
+ SHOES_CONTROL_REF
879
+ shoes_native_edit_box(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
880
+ {
881
+ GtkTextBuffer *buffer;
882
+ GtkWidget* textview = gtk_text_view_new();
883
+ SHOES_CONTROL_REF ref = gtk_scrolled_window_new(NULL, NULL);
884
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview), GTK_WRAP_WORD);
885
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
886
+ gtk_text_buffer_set_text(buffer, _(msg), -1);
887
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ref),
888
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
889
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ref), GTK_SHADOW_IN);
890
+ gtk_container_add(GTK_CONTAINER(ref), textview);
891
+ g_signal_connect(G_OBJECT(buffer), "changed",
892
+ G_CALLBACK(shoes_widget_changed),
893
+ (gpointer)self);
894
+ return ref;
895
+ }
896
+
897
+ VALUE
898
+ shoes_native_edit_box_get_text(SHOES_CONTROL_REF ref)
899
+ {
900
+ GtkWidget *textview;
901
+ GTK_CHILD(textview, ref);
902
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
903
+ GtkTextIter begin, end;
904
+ gtk_text_buffer_get_bounds(buffer, &begin, &end);
905
+ return rb_str_new2(gtk_text_buffer_get_text(buffer, &begin, &end, TRUE));
906
+ }
907
+
908
+ void
909
+ shoes_native_edit_box_set_text(SHOES_CONTROL_REF ref, char *msg)
910
+ {
911
+ GtkWidget *textview;
912
+ GTK_CHILD(textview, ref);
913
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
914
+ gtk_text_buffer_set_text(buffer, _(msg), -1);
915
+ }
916
+
917
+ SHOES_CONTROL_REF
918
+ shoes_native_list_box(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
919
+ {
920
+ SHOES_CONTROL_REF ref = gtk_combo_box_new_text();
921
+ g_signal_connect(G_OBJECT(ref), "changed",
922
+ G_CALLBACK(shoes_widget_changed),
923
+ (gpointer)self);
924
+ return ref;
925
+ }
926
+
927
+ void
928
+ shoes_native_list_box_update(SHOES_CONTROL_REF combo, VALUE ary)
929
+ {
930
+ long i;
931
+ gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo))));
932
+ for (i = 0; i < RARRAY_LEN(ary); i++)
933
+ {
934
+ VALUE msg = shoes_native_to_s(rb_ary_entry(ary, i));
935
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _(RSTRING_PTR(msg)));
936
+ }
937
+ }
938
+
939
+ VALUE
940
+ shoes_native_list_box_get_active(SHOES_CONTROL_REF ref, VALUE items)
941
+ {
942
+ int sel = gtk_combo_box_get_active(GTK_COMBO_BOX(ref));
943
+ if (sel >= 0)
944
+ return rb_ary_entry(items, sel);
945
+ return Qnil;
946
+ }
947
+
948
+ void
949
+ shoes_native_list_box_set_active(SHOES_CONTROL_REF combo, VALUE ary, VALUE item)
950
+ {
951
+ int idx = rb_ary_index_of(ary, item);
952
+ if (idx < 0) return;
953
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combo), idx);
954
+ }
955
+
956
+ SHOES_CONTROL_REF
957
+ shoes_native_progress(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
958
+ {
959
+ SHOES_CONTROL_REF ref = gtk_progress_bar_new();
960
+ gtk_progress_bar_set_text(GTK_PROGRESS_BAR(ref), _(msg));
961
+ return ref;
962
+ }
963
+
964
+ double
965
+ shoes_native_progress_get_fraction(SHOES_CONTROL_REF ref)
966
+ {
967
+ return gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(ref));
968
+ }
969
+
970
+ void
971
+ shoes_native_progress_set_fraction(SHOES_CONTROL_REF ref, double perc)
972
+ {
973
+ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(ref), perc);
974
+ }
975
+
976
+ SHOES_CONTROL_REF
977
+ shoes_native_slider(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
978
+ {
979
+ SHOES_CONTROL_REF ref = gtk_hscale_new_with_range(0., 1., 0.01);
980
+ gtk_scale_set_draw_value(GTK_SCALE(ref), FALSE);
981
+ g_signal_connect(G_OBJECT(ref), "value-changed",
982
+ G_CALLBACK(shoes_widget_changed), (gpointer)self);
983
+ return ref;
984
+ }
985
+
986
+ double
987
+ shoes_native_slider_get_fraction(SHOES_CONTROL_REF ref)
988
+ {
989
+ return gtk_range_get_value(GTK_RANGE(ref));
990
+ }
991
+
992
+ void
993
+ shoes_native_slider_set_fraction(SHOES_CONTROL_REF ref, double perc)
994
+ {
995
+ gtk_range_set_value(GTK_RANGE(ref), perc);
996
+ }
997
+
998
+ SHOES_CONTROL_REF
999
+ shoes_native_check(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
1000
+ {
1001
+ SHOES_CONTROL_REF ref = gtk_check_button_new();
1002
+ g_signal_connect(G_OBJECT(ref), "clicked",
1003
+ G_CALLBACK(shoes_button_gtk_clicked),
1004
+ (gpointer)self);
1005
+ return ref;
1006
+ }
1007
+
1008
+ VALUE
1009
+ shoes_native_check_get(SHOES_CONTROL_REF ref)
1010
+ {
1011
+ return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ref)) ? Qtrue : Qfalse;
1012
+ }
1013
+
1014
+ void
1015
+ shoes_native_check_set(SHOES_CONTROL_REF ref, int on)
1016
+ {
1017
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ref), on ? TRUE : FALSE);
1018
+ }
1019
+
1020
+ SHOES_CONTROL_REF
1021
+ shoes_native_radio(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, VALUE group)
1022
+ {
1023
+ SHOES_CONTROL_REF ref;
1024
+ GSList *list = NULL;
1025
+ if (!NIL_P(group))
1026
+ {
1027
+ shoes_control *lctrl;
1028
+ VALUE leader = rb_ary_entry(group, 0);
1029
+ Data_Get_Struct(leader, shoes_control, lctrl);
1030
+ list = gtk_radio_button_get_group(GTK_RADIO_BUTTON(lctrl->ref));
1031
+ }
1032
+ ref = gtk_radio_button_new(list);
1033
+ g_signal_connect(G_OBJECT(ref), "clicked",
1034
+ G_CALLBACK(shoes_button_gtk_clicked),
1035
+ (gpointer)self);
1036
+ return ref;
1037
+ }
1038
+
1039
+ static gboolean
1040
+ shoes_gtk_animate(gpointer data)
1041
+ {
1042
+ VALUE timer = (VALUE)data;
1043
+ shoes_timer *self_t;
1044
+ Data_Get_Struct(timer, shoes_timer, self_t);
1045
+ if (self_t->started == ANIM_STARTED)
1046
+ shoes_timer_call(timer);
1047
+ return self_t->started == ANIM_STARTED;
1048
+ }
1049
+
1050
+ void
1051
+ shoes_native_timer_remove(shoes_canvas *canvas, SHOES_TIMER_REF ref)
1052
+ {
1053
+ g_source_remove(ref);
1054
+ }
1055
+
1056
+ SHOES_TIMER_REF
1057
+ shoes_native_timer_start(VALUE self, shoes_canvas *canvas, unsigned int interval)
1058
+ {
1059
+ return g_timeout_add(interval, shoes_gtk_animate, (gpointer)self);
1060
+ }
1061
+
1062
+ VALUE
1063
+ shoes_native_clipboard_get(shoes_app *app)
1064
+ {
1065
+ GtkClipboard *primary = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
1066
+ if (gtk_clipboard_wait_is_text_available(primary))
1067
+ {
1068
+ gchar *string = gtk_clipboard_wait_for_text(primary);
1069
+ return rb_str_new2(string);
1070
+ }
1071
+ return Qnil;
1072
+ }
1073
+
1074
+ void
1075
+ shoes_native_clipboard_set(shoes_app *app, VALUE string)
1076
+ {
1077
+ GtkClipboard *primary = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
1078
+ gtk_clipboard_set_text(primary, RSTRING_PTR(string), RSTRING_LEN(string));
1079
+ }
1080
+
1081
+ VALUE
1082
+ shoes_native_to_s(VALUE text)
1083
+ {
1084
+ text = rb_funcall(text, s_to_s, 0);
1085
+ return text;
1086
+ }
1087
+
1088
+ VALUE
1089
+ shoes_native_window_color(shoes_app *app)
1090
+ {
1091
+ GtkStyle *style = gtk_widget_get_style(GTK_WIDGET(APP_WINDOW(app)));
1092
+ GdkColor bg = style->bg[GTK_STATE_NORMAL];
1093
+ return shoes_color_new(bg.red / 257, bg.green / 257, bg.blue / 257 , SHOES_COLOR_OPAQUE);
1094
+ }
1095
+
1096
+ VALUE
1097
+ shoes_native_dialog_color(shoes_app *app)
1098
+ {
1099
+ GtkStyle *style = gtk_widget_get_style(GTK_WIDGET(APP_WINDOW(app)));
1100
+ GdkColor bg = style->bg[GTK_STATE_NORMAL];
1101
+ return shoes_color_new(bg.red / 257, bg.green / 257, bg.blue / 257 , SHOES_COLOR_OPAQUE);
1102
+ }
1103
+
1104
+ VALUE
1105
+ shoes_dialog_alert(VALUE self, VALUE msg)
1106
+ {
1107
+ GLOBAL_APP(app);
1108
+ msg = shoes_native_to_s(msg);
1109
+ GtkWidget *dialog = gtk_message_dialog_new_with_markup(
1110
+ APP_WINDOW(app), GTK_DIALOG_MODAL,
1111
+ GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "<span size='larger'>%s</span>\n\n%s",
1112
+ _(dialog_title_says), RSTRING_PTR(msg));
1113
+ gtk_dialog_run(GTK_DIALOG(dialog));
1114
+ gtk_widget_destroy(dialog);
1115
+ return Qnil;
1116
+ }
1117
+
1118
+ VALUE
1119
+ shoes_dialog_ask(int argc, VALUE *argv, VALUE self)
1120
+ {
1121
+ rb_arg_list args;
1122
+ VALUE answer = Qnil;
1123
+ rb_parse_args(argc, argv, "s|h", &args);
1124
+ GLOBAL_APP(app);
1125
+ GtkWidget *dialog = gtk_dialog_new_with_buttons(_(dialog_title),
1126
+ APP_WINDOW(app), GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1127
+ gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
1128
+ gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 6);
1129
+ GtkWidget *question = gtk_label_new(RSTRING_PTR(args.a[0]));
1130
+ gtk_misc_set_alignment(GTK_MISC(question), 0, 0);
1131
+ GtkWidget *_answer = gtk_entry_new();
1132
+ if (RTEST(ATTR(args.a[1], secret))) shoes_native_secrecy(_answer);
1133
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), question, FALSE, FALSE, 3);
1134
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), _answer, FALSE, TRUE, 3);
1135
+ gtk_widget_show_all(dialog);
1136
+ gint result = gtk_dialog_run(GTK_DIALOG(dialog));
1137
+ if (result == GTK_RESPONSE_OK)
1138
+ {
1139
+ const gchar *txt = gtk_entry_get_text(GTK_ENTRY(_answer));
1140
+ answer = rb_str_new2(txt);
1141
+ }
1142
+ gtk_widget_destroy(dialog);
1143
+ return answer;
1144
+ }
1145
+
1146
+ VALUE
1147
+ shoes_dialog_confirm(VALUE self, VALUE quiz)
1148
+ {
1149
+ VALUE answer = Qfalse;
1150
+ GLOBAL_APP(app);
1151
+ quiz = shoes_native_to_s(quiz);
1152
+ GtkWidget *dialog = gtk_dialog_new_with_buttons(_(dialog_title),
1153
+ APP_WINDOW(app), GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1154
+ gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
1155
+ gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), 6);
1156
+ GtkWidget *question = gtk_label_new(RSTRING_PTR(quiz));
1157
+ gtk_misc_set_alignment(GTK_MISC(question), 0, 0);
1158
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), question, FALSE, FALSE, 3);
1159
+ gtk_widget_show_all(dialog);
1160
+ gint result = gtk_dialog_run(GTK_DIALOG(dialog));
1161
+ if (result == GTK_RESPONSE_OK)
1162
+ answer = Qtrue;
1163
+ gtk_widget_destroy(dialog);
1164
+ return answer;
1165
+ }
1166
+
1167
+ VALUE
1168
+ shoes_dialog_color(VALUE self, VALUE title)
1169
+ {
1170
+ VALUE color = Qnil;
1171
+ GLOBAL_APP(app);
1172
+ title = shoes_native_to_s(title);
1173
+ GtkWidget *dialog = gtk_color_selection_dialog_new(RSTRING_PTR(title));
1174
+ gint result = gtk_dialog_run(GTK_DIALOG(dialog));
1175
+ if (result == GTK_RESPONSE_OK)
1176
+ {
1177
+ GdkColor _color;
1178
+ gtk_color_selection_get_current_color(
1179
+ GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dialog)->colorsel),
1180
+ &_color);
1181
+ color = shoes_color_new(_color.red/256, _color.green/256, _color.blue/256, SHOES_COLOR_OPAQUE);
1182
+ }
1183
+ gtk_widget_destroy(dialog);
1184
+ return color;
1185
+ }
1186
+
1187
+ static VALUE
1188
+ shoes_dialog_chooser(VALUE self, char *title, GtkFileChooserAction act, const gchar *button, VALUE attr)
1189
+ {
1190
+ VALUE path = Qnil;
1191
+ GLOBAL_APP(app);
1192
+ GtkWidget *dialog = gtk_file_chooser_dialog_new(title, APP_WINDOW(app),
1193
+ act, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, button, GTK_RESPONSE_ACCEPT, NULL);
1194
+ if (act == GTK_FILE_CHOOSER_ACTION_SAVE)
1195
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
1196
+ if(RTEST(shoes_hash_get(attr, rb_intern("save"))))
1197
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
1198
+ RSTRING_PTR(shoes_hash_get(attr, rb_intern("save"))));
1199
+ if(RTEST(shoes_hash_get(attr, rb_intern("types"))) && TYPE(shoes_hash_get(attr, rb_intern("types"))) == T_HASH) {
1200
+ VALUE hsh = shoes_hash_get(attr, rb_intern("types"));
1201
+ VALUE keys = rb_funcall(hsh, s_keys, 0);
1202
+ int i;
1203
+ for(i = 0; i < RARRAY_LEN(keys); i++) {
1204
+ VALUE key = rb_ary_entry(keys, i);
1205
+ VALUE val = rb_hash_aref(hsh, key);
1206
+ GtkFileFilter *ff = gtk_file_filter_new();
1207
+ gtk_file_filter_set_name(ff, RSTRING_PTR(key));
1208
+ gtk_file_filter_add_pattern(ff, RSTRING_PTR(val));
1209
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), ff);
1210
+ }
1211
+ }
1212
+ gint result = gtk_dialog_run(GTK_DIALOG(dialog));
1213
+ if (result == GTK_RESPONSE_ACCEPT)
1214
+ {
1215
+ char *filename;
1216
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1217
+ path = rb_str_new2(filename);
1218
+ }
1219
+ gtk_widget_destroy(dialog);
1220
+ return path;
1221
+ }
1222
+
1223
+ VALUE
1224
+ shoes_dialog_open(int argc, VALUE *argv, VALUE self)
1225
+ {
1226
+ rb_arg_list args;
1227
+ rb_parse_args(argc, argv, "|h", &args);
1228
+ return shoes_dialog_chooser(self, "Open file...", GTK_FILE_CHOOSER_ACTION_OPEN,
1229
+ GTK_STOCK_OPEN, args.a[0]);
1230
+ }
1231
+
1232
+ VALUE
1233
+ shoes_dialog_save(int argc, VALUE *argv, VALUE self)
1234
+ {
1235
+ rb_arg_list args;
1236
+ rb_parse_args(argc, argv, "|h", &args);
1237
+ return shoes_dialog_chooser(self, "Save file...", GTK_FILE_CHOOSER_ACTION_SAVE,
1238
+ GTK_STOCK_SAVE, args.a[0]);
1239
+ }
1240
+
1241
+ VALUE
1242
+ shoes_dialog_open_folder(int argc, VALUE *argv, VALUE self)
1243
+ {
1244
+ rb_arg_list args;
1245
+ rb_parse_args(argc, argv, "|h", &args);
1246
+ return shoes_dialog_chooser(self, "Open folder...", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
1247
+ GTK_STOCK_OPEN, args.a[0]);
1248
+ }
1249
+
1250
+ VALUE
1251
+ shoes_dialog_save_folder(int argc, VALUE *argv, VALUE self)
1252
+ {
1253
+ rb_arg_list args;
1254
+ rb_parse_args(argc, argv, "|h", &args);
1255
+ return shoes_dialog_chooser(self, "Save folder...", GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER,
1256
+ GTK_STOCK_SAVE, args.a[0]);
1257
+ }