shoes 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,2392 @@
1
+ //
2
+ // shoes/native/windows.c
3
+ // Windows-specific 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
+ #include "shoes/appwin32.h"
12
+ #include <commdlg.h>
13
+ #include <shlobj.h>
14
+ #include <ctype.h>
15
+
16
+ #define HEIGHT_PAD 6
17
+
18
+ #ifndef IDC_HAND
19
+ #define IDC_HAND MAKEINTRESOURCE(32649)
20
+ #endif
21
+
22
+ #ifndef BIF_NONEWFOLDERBUTTON
23
+ #define BIF_NONEWFOLDERBUTTON 0x200
24
+ #endif
25
+
26
+ static WNDPROC shoes_original_edit_line_proc = NULL;
27
+ HHOOK hhook;
28
+ VALUE kh_up_v = (VALUE)NULL;
29
+ VALUE kh_down_v = (VALUE)NULL;
30
+
31
+ shoes_code shoes_classex_init();
32
+ LRESULT CALLBACK shoes_app_win32proc(HWND, UINT, WPARAM, LPARAM);
33
+ LRESULT CALLBACK shoes_slot_win32proc(HWND, UINT, WPARAM, LPARAM);
34
+ LRESULT CALLBACK shoes_edit_line_win32proc(HWND, UINT, WPARAM, LPARAM);
35
+ LRESULT CALLBACK shoes_keyhook(int, WPARAM, LPARAM);
36
+
37
+ #define KEYUPDOWN \
38
+ if (vk == VK_LCONTROL) \
39
+ v = ID2SYM(rb_intern("left_ctrl")); \
40
+ else if (vk == VK_RCONTROL) \
41
+ v = ID2SYM(rb_intern("right_ctrl")); \
42
+ else if (vk == VK_LMENU) \
43
+ v = ID2SYM(rb_intern("left_alt")); \
44
+ else if (vk == VK_RMENU) \
45
+ v = ID2SYM(rb_intern("right_alt")); \
46
+ else if (vk == VK_LSHIFT) \
47
+ v = ID2SYM(rb_intern("left_shift")); \
48
+ else if (vk == VK_RSHIFT) \
49
+ v = ID2SYM(rb_intern("right_shift")); \
50
+ else if (vk == VK_ESCAPE) \
51
+ v = ID2SYM(rb_intern("escape")); \
52
+ else if (vk == VK_INSERT) \
53
+ v = ID2SYM(rb_intern("insert")); \
54
+ else if (vk == VK_DELETE) \
55
+ v = ID2SYM(rb_intern("delete")); \
56
+ else if (vk == VK_PRIOR) \
57
+ v = ID2SYM(rb_intern("page_up")); \
58
+ else if (vk == VK_NEXT) \
59
+ v = ID2SYM(rb_intern("page_down")); \
60
+ else if (vk == VK_HOME) \
61
+ v = ID2SYM(rb_intern("home")); \
62
+ else if (vk == VK_END) \
63
+ v = ID2SYM(rb_intern("end")); \
64
+ else if (vk == VK_LEFT) \
65
+ v = ID2SYM(rb_intern("left")); \
66
+ else if (vk == VK_UP) \
67
+ v = ID2SYM(rb_intern("up")); \
68
+ else if (vk == VK_RIGHT) \
69
+ v = ID2SYM(rb_intern("right")); \
70
+ else if (vk == VK_DOWN) \
71
+ v = ID2SYM(rb_intern("down")); \
72
+ else if (vk == VK_F1) \
73
+ v = ID2SYM(rb_intern("f1")); \
74
+ else if (vk == VK_F2) \
75
+ v = ID2SYM(rb_intern("f2")); \
76
+ else if (vk == VK_F2) \
77
+ v = ID2SYM(rb_intern("f2")); \
78
+ else if (vk == VK_F3) \
79
+ v = ID2SYM(rb_intern("f3")); \
80
+ else if (vk == VK_F4) \
81
+ v = ID2SYM(rb_intern("f4")); \
82
+ else if (vk == VK_F5) \
83
+ v = ID2SYM(rb_intern("f5")); \
84
+ else if (vk == VK_F6) \
85
+ v = ID2SYM(rb_intern("f6")); \
86
+ else if (vk == VK_F7) \
87
+ v = ID2SYM(rb_intern("f7")); \
88
+ else if (vk == VK_F8) \
89
+ v = ID2SYM(rb_intern("f8")); \
90
+ else if (vk == VK_F9) \
91
+ v = ID2SYM(rb_intern("f9")); \
92
+ else if (vk == VK_F10) \
93
+ v = ID2SYM(rb_intern("f10")); \
94
+ else if (vk == VK_F11) \
95
+ v = ID2SYM(rb_intern("f11")); \
96
+ else if (vk == VK_F12) \
97
+ v = ID2SYM(rb_intern("f12")); \
98
+ else if (vk == 186) \
99
+ { \
100
+ letter = ':'; \
101
+ v = rb_str_new(&letter, 1); \
102
+ } \
103
+ else if (vk == 187) \
104
+ { \
105
+ letter = ';'; \
106
+ v = rb_str_new(&letter, 1); \
107
+ } \
108
+ else if (vk == 188) \
109
+ { \
110
+ letter = ','; \
111
+ v = rb_str_new(&letter, 1); \
112
+ } \
113
+ else if (vk == 189) \
114
+ { \
115
+ letter = '-'; \
116
+ v = rb_str_new(&letter, 1); \
117
+ } \
118
+ else if (vk == 190) \
119
+ { \
120
+ letter = '.'; \
121
+ v = rb_str_new(&letter, 1); \
122
+ } \
123
+ else if (vk == 191) \
124
+ { \
125
+ letter = '/'; \
126
+ v = rb_str_new(&letter, 1); \
127
+ } \
128
+ else if (vk == 192) \
129
+ { \
130
+ letter = '@'; \
131
+ v = rb_str_new(&letter, 1); \
132
+ } \
133
+ else if (vk == 219) \
134
+ { \
135
+ letter = '['; \
136
+ v = rb_str_new(&letter, 1); \
137
+ } \
138
+ else if (vk == 220) \
139
+ { \
140
+ letter = '_'; \
141
+ v = rb_str_new(&letter, 1); \
142
+ } \
143
+ else if (vk == 221) \
144
+ { \
145
+ letter = ']'; \
146
+ v = rb_str_new(&letter, 1); \
147
+ } \
148
+ else if (vk == 222) \
149
+ { \
150
+ letter = '^'; \
151
+ v = rb_str_new(&letter, 1); \
152
+ } \
153
+ else if (vk == 226) \
154
+ { \
155
+ letter = '\\'; \
156
+ v = rb_str_new(&letter, 1); \
157
+ } \
158
+ else if (vk == 0x08) \
159
+ v = ID2SYM(rb_intern("backspace")); \
160
+ else if (vk == 0x09) \
161
+ v = ID2SYM(rb_intern("tab")); \
162
+ else if (vk == 0x0D) \
163
+ v = ID2SYM(rb_intern("enter")); \
164
+ else \
165
+ { \
166
+ letter = tolower(letter); \
167
+ v = rb_str_new(&letter, 1); \
168
+ }
169
+
170
+ static WCHAR *
171
+ shoes_wchar(char *utf8)
172
+ {
173
+ WCHAR *buffer = NULL;
174
+ LONG wlen = 0;
175
+ if (utf8 == NULL) return NULL;
176
+ wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
177
+ if (!wlen) return NULL;
178
+ buffer = SHOE_ALLOC_N(WCHAR, wlen);
179
+ if (!buffer) return NULL;
180
+ MultiByteToWideChar(CP_UTF8, 0, utf8, -1, buffer, wlen);
181
+ return buffer;
182
+ }
183
+
184
+ static char *
185
+ shoes_utf8(WCHAR *buffer)
186
+ {
187
+ char *utf8 = NULL;
188
+ LONG i8 = 0;
189
+ if (buffer == NULL) return NULL;
190
+ i8 = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
191
+ if (!i8) return NULL;
192
+ utf8 = SHOE_ALLOC_N(char, i8);
193
+ if (!utf8) return NULL;
194
+ WideCharToMultiByte(CP_UTF8, 0, buffer, -1, utf8, i8, NULL, NULL);
195
+ return utf8;
196
+ }
197
+
198
+ static void
199
+ shoes_win32_center(HWND hwnd)
200
+ {
201
+ RECT rc;
202
+
203
+ GetWindowRect(hwnd, &rc);
204
+
205
+ SetWindowPos(hwnd, 0,
206
+ (GetSystemMetrics(SM_CXSCREEN) - rc.right)/2,
207
+ (GetSystemMetrics(SM_CYSCREEN) - rc.bottom)/2,
208
+ 0, 0, SWP_NOZORDER|SWP_NOSIZE );
209
+ }
210
+
211
+ int
212
+ shoes_win32_cmdvector(const char *cmdline, char ***argv)
213
+ {
214
+ return rb_w32_cmdvector(cmdline, argv);
215
+ }
216
+
217
+ VALUE
218
+ shoes_load_font(const char *filename)
219
+ {
220
+ VALUE allfonts, newfonts, oldfonts;
221
+ int fonts = AddFontResourceEx(filename, FR_PRIVATE, 0);
222
+ if (!fonts) return Qnil;
223
+ allfonts = shoes_font_list();
224
+ oldfonts = rb_const_get(cShoes, rb_intern("FONTS"));
225
+ newfonts = rb_funcall(allfonts, rb_intern("-"), 1, oldfonts);
226
+ shoes_update_fonts(allfonts);
227
+ return newfonts;
228
+ }
229
+
230
+ static int CALLBACK
231
+ shoes_font_list_iter(const ENUMLOGFONTEX *font, const NEWTEXTMETRICA *pfont, DWORD type, LPARAM l)
232
+ {
233
+ rb_ary_push(l, rb_str_new2(font->elfLogFont.lfFaceName));
234
+ return TRUE;
235
+ }
236
+
237
+ VALUE
238
+ shoes_font_list()
239
+ {
240
+ LOGFONT font = {0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, ""};
241
+ VALUE ary = rb_ary_new();
242
+ HDC dc = GetDC(NULL);
243
+ EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)shoes_font_list_iter, (LPARAM)ary, 0);
244
+ ReleaseDC(NULL, dc);
245
+ rb_funcall(ary, rb_intern("uniq!"), 0);
246
+ rb_funcall(ary, rb_intern("sort!"), 0);
247
+ return ary;
248
+ }
249
+
250
+ void shoes_native_init()
251
+ {
252
+ INITCOMMONCONTROLSEX InitCtrlEx;
253
+ InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
254
+ InitCtrlEx.dwICC = ICC_PROGRESS_CLASS;
255
+ InitCommonControlsEx(&InitCtrlEx);
256
+ shoes_classex_init();
257
+ shoes_world->os.hidden = CreateWindow(SHOES_HIDDENCLS, SHOES_HIDDENCLS, WS_OVERLAPPEDWINDOW,
258
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, shoes_world->os.instance, NULL);
259
+
260
+ // Detect Windows Vista
261
+ OSVERSIONINFOEXW osvi = { 0 };
262
+ BOOL ret;
263
+
264
+ // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
265
+ // If that fails, try using the OSVERSIONINFO structure.
266
+
267
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
268
+ ret = GetVersionExW ((OSVERSIONINFOW*)&osvi);
269
+
270
+ shoes_world->os.doublebuffer = FALSE;
271
+
272
+ // Fallback to old version info struct if necessary.
273
+ if (!ret)
274
+ {
275
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
276
+ ret = GetVersionExW((OSVERSIONINFOW*)&osvi);
277
+ }
278
+
279
+ if (!ret)
280
+ {
281
+ // Error. Cannot detect version. Assume the worst: it is Vista.
282
+ shoes_world->os.doublebuffer = TRUE;
283
+ }
284
+ else if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) {
285
+ // Detected Windows "6.0", that is, Vista
286
+ shoes_world->os.doublebuffer = TRUE;
287
+ }
288
+
289
+ hhook = SetWindowsHookEx(WH_KEYBOARD_LL, shoes_keyhook, shoes_world->os.instance, 0);
290
+ }
291
+
292
+ LRESULT CALLBACK shoes_keyhook(int n, WPARAM w, LPARAM l)
293
+ {
294
+ VALUE v;
295
+ WPARAM vk;
296
+
297
+ kh_up_v = (VALUE)NULL;
298
+ kh_down_v = (VALUE)NULL;
299
+
300
+ if (n == HC_ACTION)
301
+ {
302
+ KBDLLHOOKSTRUCT *kbdHS = (KBDLLHOOKSTRUCT *)l;
303
+ switch (w)
304
+ {
305
+ case WM_SYSKEYUP:
306
+ case WM_KEYUP:
307
+ {
308
+ vk = kbdHS->vkCode;
309
+ char letter = vk;
310
+ KEYUPDOWN
311
+ kh_up_v = v;
312
+ }
313
+ break;
314
+
315
+ case WM_SYSKEYDOWN:
316
+ case WM_KEYDOWN:
317
+ {
318
+ vk = kbdHS->vkCode;
319
+ char letter = vk;
320
+ KEYUPDOWN
321
+ kh_down_v = v;
322
+ }
323
+ break;
324
+ }
325
+ }
326
+
327
+ return CallNextHookEx(hhook, n, w, l);
328
+ }
329
+
330
+ void shoes_native_cleanup(shoes_world_t *world)
331
+ {
332
+ UnhookWindowsHookEx(hhook);
333
+ }
334
+
335
+ void shoes_native_quit()
336
+ {
337
+ PostQuitMessage(0);
338
+ }
339
+
340
+ int shoes_throw_message(unsigned int name, VALUE obj, void *data)
341
+ {
342
+ return SendMessage(shoes_world->os.hidden, SHOES_WM_MESSAGE + name, obj, (LPARAM)data);
343
+ }
344
+
345
+ void shoes_native_slot_mark(SHOES_SLOT_OS *slot)
346
+ {
347
+ rb_gc_mark_maybe(slot->controls);
348
+ rb_gc_mark_maybe(slot->focus);
349
+ }
350
+
351
+ void shoes_native_slot_reset(SHOES_SLOT_OS *slot)
352
+ {
353
+ slot->controls = rb_ary_new();
354
+ rb_gc_register_address(&slot->controls);
355
+ }
356
+
357
+ void shoes_native_slot_clear(shoes_canvas *canvas)
358
+ {
359
+ rb_ary_clear(canvas->slot->controls);
360
+ }
361
+
362
+ void shoes_native_slot_paint(SHOES_SLOT_OS *slot)
363
+ {
364
+ if (shoes_world->os.doublebuffer && slot->parent != NULL)
365
+ {
366
+ HWND parentWindow = GetWindow(slot->window, GW_OWNER);
367
+
368
+ if (parentWindow != HWND_DESKTOP && parentWindow != NULL)
369
+ {
370
+ VALUE c = (VALUE)GetWindowLong(slot->window, GWL_USERDATA);
371
+
372
+ if (c != (VALUE)NULL)
373
+ {
374
+ shoes_canvas *canvas;
375
+ Data_Get_Struct(c, shoes_canvas, canvas);
376
+ RedrawWindow(canvas->slot->window, NULL, NULL, RDW_INVALIDATE|RDW_ALLCHILDREN);
377
+ return;
378
+ }
379
+ }
380
+ }
381
+
382
+ RedrawWindow(slot->window, NULL, NULL, RDW_INVALIDATE|RDW_ALLCHILDREN);
383
+ }
384
+
385
+ void shoes_native_slot_lengthen(SHOES_SLOT_OS *slot, int height, int endy)
386
+ {
387
+ SCROLLINFO si;
388
+ si.cbSize = sizeof(SCROLLINFO);
389
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
390
+ si.nMin = 0;
391
+ si.nMax = endy - 1;
392
+ si.nPage = height;
393
+ si.nPos = slot->scrolly;
394
+ INFO("SetScrollInfo(%d, nMin: %d, nMax: %d, nPage: %d)\n",
395
+ si.nPos, si.nMin, si.nMax, si.nPage);
396
+ SetScrollInfo(slot->window, SB_VERT, &si, TRUE);
397
+ }
398
+
399
+ void shoes_native_slot_scroll_top(SHOES_SLOT_OS *slot)
400
+ {
401
+ SetScrollPos(slot->window, SB_VERT, slot->scrolly, TRUE);
402
+ }
403
+
404
+ int shoes_native_slot_gutter(SHOES_SLOT_OS *slot)
405
+ {
406
+ return GetSystemMetrics(SM_CXVSCROLL);
407
+ }
408
+
409
+ void shoes_native_remove_item(SHOES_SLOT_OS *slot, VALUE item, char c)
410
+ {
411
+ if (c)
412
+ {
413
+ long i = rb_ary_index_of(slot->controls, item);
414
+ if (i >= 0)
415
+ rb_ary_insert_at(slot->controls, i, 1, Qnil);
416
+ if (item == slot->focus)
417
+ slot->focus = Qnil;
418
+ }
419
+ }
420
+
421
+ //
422
+ // Window-level events
423
+ //
424
+ #define WINDOW_STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
425
+ #define WINDOW_STYLE_FULLSCREEN WS_POPUP | WS_VSCROLL | ES_AUTOVSCROLL
426
+
427
+ #define WM_POINTS() \
428
+ POINT p; \
429
+ p.x = LOWORD(l); \
430
+ p.y = HIWORD(l)
431
+ #define WM_POINTS2() \
432
+ WM_POINTS(); \
433
+ ClientToScreen(win, &p); \
434
+ ScreenToClient(canvas->app->slot->window, &p); \
435
+
436
+ #define KEY_SYM(sym) shoes_app_keypress(app, ID2SYM(rb_intern("" # sym)))
437
+ #define KEYPRESS(name, sym) \
438
+ else if (w == VK_##name) { \
439
+ VALUE v = ID2SYM(rb_intern("" # sym)); \
440
+ if (app->os.altkey) \
441
+ KEY_STATE(alt); \
442
+ if (app->os.shiftkey) \
443
+ KEY_STATE(shift); \
444
+ if (app->os.ctrlkey) \
445
+ KEY_STATE(control); \
446
+ shoes_app_keypress(app, v); \
447
+ }
448
+
449
+ static void
450
+ shoes_canvas_win32_vscroll(shoes_canvas *canvas, int code, int pos)
451
+ {
452
+ SCROLLINFO si;
453
+ SHOE_MEMZERO(&si, SCROLLINFO, 1);
454
+ si.cbSize = sizeof(SCROLLINFO);
455
+ si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
456
+ GetScrollInfo(canvas->slot->window, SB_VERT, &si);
457
+
458
+ switch (code)
459
+ {
460
+ case SB_LINEUP:
461
+ si.nPos -= 16;
462
+ break;
463
+ case SB_LINEDOWN:
464
+ si.nPos += 16;
465
+ break;
466
+ case SB_PAGEUP:
467
+ si.nPos -= si.nPage - 32;
468
+ break;
469
+ case SB_PAGEDOWN:
470
+ si.nPos += si.nPage - 32;
471
+ break;
472
+ case SB_THUMBTRACK:
473
+ si.nPos = pos;
474
+ break;
475
+ default:
476
+ return;
477
+ }
478
+
479
+ if (si.nPos < 0)
480
+ si.nPos = 0;
481
+ else if (si.nPos > (si.nMax - si.nPage))
482
+ si.nPos = si.nMax - si.nPage;
483
+
484
+ SetScrollInfo(canvas->slot->window, SB_VERT, &si, TRUE);
485
+ canvas->slot->scrolly = si.nPos;
486
+ if (canvas->app->slot->dc == canvas->slot->dc) canvas->app->slot->scrolly = si.nPos;
487
+ shoes_native_slot_paint(canvas->slot);
488
+ }
489
+
490
+ LRESULT CALLBACK
491
+ shoes_slot_win32proc(
492
+ HWND win,
493
+ UINT msg,
494
+ WPARAM w,
495
+ LPARAM l)
496
+ {
497
+ shoes_canvas *canvas;
498
+ VALUE c = (VALUE)GetWindowLong(win, GWL_USERDATA);
499
+
500
+ if (c != (VALUE)NULL)
501
+ {
502
+ Data_Get_Struct(c, shoes_canvas, canvas);
503
+
504
+ switch (msg)
505
+ {
506
+ case WM_ERASEBKGND:
507
+ return 1;
508
+
509
+ case WM_SIZE:
510
+ if (shoes_world->os.doublebuffer)
511
+ {
512
+ // On Vista, flickering still happens due to a bug in Vista's compositing
513
+ // engine. We circumvent using some old school software double buffering.
514
+ // Yes. It sucks. Like shifting gears in an automatic... poorly.
515
+
516
+ RECT rc;
517
+ GetClientRect(win, &rc);
518
+
519
+ DeleteDC(canvas->slot->dc);
520
+
521
+ HDC windowDC = GetDC(canvas->slot->window);
522
+ canvas->slot->dc = CreateCompatibleDC(windowDC);
523
+
524
+ HBITMAP hbmp = CreateCompatibleBitmap(windowDC, rc.right, rc.bottom);
525
+ SelectObject(canvas->slot->dc, hbmp);
526
+ DeleteObject(hbmp);
527
+
528
+ ReleaseDC(canvas->slot->window, windowDC);
529
+
530
+ HBRUSH bg = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
531
+ FillRect(canvas->slot->dc, &rc, bg);
532
+ DeleteObject(bg);
533
+ }
534
+ break;
535
+
536
+ case WM_PAINT:
537
+ INFO("WM_PAINT(slot, %lu)\n", win);
538
+ if (c != canvas->app->canvas)
539
+ shoes_canvas_paint(c);
540
+ return 1;
541
+
542
+ case WM_VSCROLL:
543
+ shoes_canvas_win32_vscroll(canvas, LOWORD(w), HIWORD(w));
544
+ break;
545
+
546
+ case WM_LBUTTONDOWN:
547
+ {
548
+ WM_POINTS2();
549
+ shoes_app_click(canvas->app, 1, p.x, p.y + canvas->app->slot->scrolly);
550
+ }
551
+ break;
552
+
553
+ case WM_RBUTTONDOWN:
554
+ {
555
+ WM_POINTS2();
556
+ shoes_app_click(canvas->app, 2, p.x, p.y + canvas->app->slot->scrolly);
557
+ }
558
+ break;
559
+
560
+ case WM_MBUTTONDOWN:
561
+ {
562
+ WM_POINTS2();
563
+ shoes_app_click(canvas->app, 3, p.x, p.y + canvas->app->slot->scrolly);
564
+ }
565
+ break;
566
+
567
+ case WM_LBUTTONUP:
568
+ {
569
+ WM_POINTS2();
570
+ shoes_app_release(canvas->app, 1, p.x, p.y + canvas->app->slot->scrolly);
571
+ }
572
+ break;
573
+
574
+ case WM_RBUTTONUP:
575
+ {
576
+ WM_POINTS2();
577
+ shoes_app_release(canvas->app, 2, p.x, p.y + canvas->app->slot->scrolly);
578
+ }
579
+ break;
580
+
581
+ case WM_MBUTTONUP:
582
+ {
583
+ WM_POINTS2();
584
+ shoes_app_release(canvas->app, 3, p.x, p.y + canvas->app->slot->scrolly);
585
+ }
586
+ break;
587
+
588
+ case WM_MOUSEMOVE:
589
+ {
590
+ WM_POINTS2();
591
+ shoes_app_motion(canvas->app, p.x, p.y + canvas->app->slot->scrolly);
592
+ }
593
+ return 1;
594
+
595
+ case WM_ACTIVATE:
596
+ if (LOWORD(w) == WA_INACTIVE)
597
+ {
598
+ int i;
599
+ HWND newFocus = GetFocus();
600
+ for (i = 0; i < RARRAY_LEN(canvas->slot->controls); i++)
601
+ {
602
+ VALUE ctrl = rb_ary_entry(canvas->slot->controls, i);
603
+ if (rb_obj_is_kind_of(ctrl, cNative))
604
+ {
605
+ shoes_control *self_t;
606
+ Data_Get_Struct(ctrl, shoes_control, self_t);
607
+ if (self_t->ref == newFocus)
608
+ {
609
+ canvas->slot->focus = ctrl;
610
+ break;
611
+ }
612
+ }
613
+ }
614
+ }
615
+ break;
616
+
617
+ case WM_SETFOCUS:
618
+ if (!NIL_P(canvas->slot->focus) && TYPE(canvas->slot->focus) != T_FALSE)
619
+ {
620
+ shoes_control_focus(canvas->slot->focus);
621
+ }
622
+ break;
623
+
624
+ /* TODO: use to make controls clear
625
+ case WM_CTLCOLOREDIT:
626
+ case WM_CTLCOLORSTATIC:
627
+ {
628
+ HDC hdc = (HDC) w;
629
+ HBRUSH hbrBkcolor = (HBRUSH)GetStockObject(NULL_BRUSH);
630
+
631
+ SetBkMode(hdc, TRANSPARENT);
632
+ return (LRESULT) hbrBkcolor;
633
+ }
634
+ break;
635
+ */
636
+
637
+ case WM_HSCROLL:
638
+ {
639
+ if (LOWORD(w) == TB_THUMBTRACK)
640
+ {
641
+ int id = GetDlgCtrlID((HWND)l);
642
+ VALUE control = rb_ary_entry(canvas->slot->controls, id - SHOES_CONTROL1);
643
+ if (!NIL_P(control))
644
+ shoes_control_send(control, s_change);
645
+ }
646
+ }
647
+ break;
648
+
649
+ case WM_COMMAND:
650
+ if ((HWND)l)
651
+ {
652
+ switch (HIWORD(w))
653
+ {
654
+ case BN_CLICKED:
655
+ {
656
+ int id = LOWORD(w);
657
+ VALUE control = rb_ary_entry(canvas->slot->controls, id - SHOES_CONTROL1);
658
+ if (!NIL_P(control))
659
+ shoes_button_send_click(control);
660
+ }
661
+ break;
662
+
663
+ case CBN_SELCHANGE:
664
+ case EN_CHANGE:
665
+ {
666
+ int id = LOWORD(w);
667
+ VALUE control = rb_ary_entry(canvas->slot->controls, id - SHOES_CONTROL1);
668
+ if (!NIL_P(control))
669
+ shoes_control_send(control, s_change);
670
+ }
671
+ break;
672
+ }
673
+ }
674
+ break;
675
+ }
676
+ }
677
+ return DefWindowProc(win, msg, w, l);
678
+ }
679
+
680
+ LRESULT CALLBACK
681
+ shoes_hidden_win32proc(HWND win, UINT msg, WPARAM w, LPARAM l)
682
+ {
683
+ if (msg > SHOES_WM_MESSAGE && msg < SHOES_WM_MESSAGE + SHOES_MAX_MESSAGE)
684
+ return shoes_catch_message(msg - SHOES_WM_MESSAGE, (VALUE)w, (void *)l);
685
+ return DefWindowProc(win, msg, w, l);
686
+ }
687
+
688
+ static void
689
+ shoes_app_decor(HWND win, int *width, int *height)
690
+ {
691
+ RECT rect, wrect;
692
+ GetClientRect(win, &rect);
693
+ GetWindowRect(win, &wrect);
694
+ *width = ((wrect.right - wrect.left) - (rect.right - rect.left)) - 2;
695
+ *height = ((wrect.bottom - wrect.top) - (rect.bottom - rect.top)) - 2;
696
+ }
697
+
698
+ LRESULT CALLBACK
699
+ shoes_app_win32proc(
700
+ HWND win,
701
+ UINT msg,
702
+ WPARAM w,
703
+ LPARAM l)
704
+ {
705
+ shoes_app *app = (shoes_app *)GetWindowLong(win, GWL_USERDATA);
706
+
707
+ switch (msg)
708
+ {
709
+ case WM_DESTROY:
710
+ if (shoes_app_remove(app))
711
+ PostQuitMessage(0);
712
+ return 0;
713
+
714
+ case WM_ERASEBKGND:
715
+ return 1;
716
+
717
+ case WM_SIZE:
718
+ if (shoes_world->os.doublebuffer)
719
+ {
720
+ // On Vista, flickering still happens due to a bug in Vista's compositing
721
+ // engine. We circumvent using some old school software double buffering.
722
+ // Yes. It sucks. Like shifting gears in an automatic... poorly.
723
+
724
+ RECT rc;
725
+ GetClientRect(win, &rc);
726
+
727
+ if (app->slot->dc != NULL)
728
+ DeleteDC(app->slot->dc);
729
+
730
+ HDC windowDC = GetDC(app->slot->window);
731
+ app->slot->dc = CreateCompatibleDC(windowDC);
732
+
733
+ HBITMAP hbmp = CreateCompatibleBitmap(windowDC, rc.right, rc.bottom);
734
+ SelectObject(app->slot->dc, hbmp);
735
+ DeleteObject(hbmp);
736
+
737
+ ReleaseDC(app->slot->window, windowDC);
738
+
739
+ HBRUSH bg = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
740
+ FillRect(app->slot->dc, &rc, bg);
741
+ DeleteObject(bg);
742
+ }
743
+ break;
744
+
745
+ //
746
+ // On Windows, I have to ensure the scrollbar's width is added
747
+ // to the client area width. In Shoes, the toplevel slot size is
748
+ // always obscured by the scrollbar when it appears, rather than
749
+ // resizing the width of the slot->
750
+ //
751
+ case WM_PAINT:
752
+ {
753
+ RECT rect;
754
+ int edgew, edgeh;
755
+ int scrollwidth = GetSystemMetrics(SM_CXVSCROLL);
756
+ GetClientRect(win, &rect);
757
+
758
+ shoes_app_decor(win, &edgew, &edgeh);
759
+ if (edgew > scrollwidth)
760
+ rect.right += scrollwidth;
761
+ app->width = rect.right;
762
+ app->height = rect.bottom;
763
+ shoes_canvas_size(app->canvas, app->width, app->height);
764
+ INFO("WM_PAINT(app, %lu)\n", win);
765
+
766
+ shoes_app_paint(app);
767
+ }
768
+ break;
769
+
770
+ case WM_GETMINMAXINFO:
771
+ if (app != NULL)
772
+ {
773
+ int edgew, edgeh;
774
+ int scrollwidth = GetSystemMetrics(SM_CXVSCROLL);
775
+ MINMAXINFO *size = (MINMAXINFO *)l;
776
+ shoes_app_decor(win, &edgew, &edgeh);
777
+ if (edgew > scrollwidth)
778
+ edgew -= scrollwidth;
779
+ size->ptMinTrackSize.x = app->minwidth + edgew;
780
+ size->ptMinTrackSize.y = app->minheight + edgeh;
781
+ }
782
+ return 0;
783
+
784
+ case WM_LBUTTONDOWN:
785
+ {
786
+ shoes_canvas *canvas;
787
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
788
+ WM_POINTS();
789
+ shoes_app_click(app, 1, p.x, p.y + canvas->slot->scrolly);
790
+ }
791
+ break;
792
+
793
+ case WM_RBUTTONDOWN:
794
+ {
795
+ shoes_canvas *canvas;
796
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
797
+ WM_POINTS();
798
+ shoes_app_click(app, 2, p.x, p.y + canvas->slot->scrolly);
799
+ }
800
+ break;
801
+
802
+ case WM_MBUTTONDOWN:
803
+ {
804
+ shoes_canvas *canvas;
805
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
806
+ WM_POINTS();
807
+ shoes_app_click(app, 3, p.x, p.y + canvas->slot->scrolly);
808
+ }
809
+ break;
810
+
811
+ case WM_LBUTTONUP:
812
+ {
813
+ shoes_canvas *canvas;
814
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
815
+ WM_POINTS();
816
+ shoes_app_release(app, 1, p.x, p.y + canvas->slot->scrolly);
817
+ }
818
+ break;
819
+
820
+ case WM_RBUTTONUP:
821
+ {
822
+ shoes_canvas *canvas;
823
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
824
+ WM_POINTS();
825
+ shoes_app_release(app, 2, p.x, p.y + canvas->slot->scrolly);
826
+ }
827
+ break;
828
+
829
+ case WM_MBUTTONUP:
830
+ {
831
+ shoes_canvas *canvas;
832
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
833
+ WM_POINTS();
834
+ shoes_app_release(app, 3, p.x, p.y + canvas->slot->scrolly);
835
+ }
836
+ break;
837
+
838
+ case WM_MOUSEMOVE:
839
+ {
840
+ shoes_canvas *canvas;
841
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
842
+ WM_POINTS();
843
+ shoes_app_motion(app, p.x, p.y + canvas->slot->scrolly);
844
+ }
845
+ return 1;
846
+
847
+ case WM_CHAR:
848
+ switch(w)
849
+ {
850
+ case 0x08:
851
+ KEY_SYM(backspace);
852
+ break;
853
+
854
+ case 0x09:
855
+ KEY_SYM(tab);
856
+ break;
857
+
858
+ case 0x0D:
859
+ shoes_app_keypress(app, rb_str_new2("\n"));
860
+ break;
861
+
862
+ default:
863
+ {
864
+ VALUE v;
865
+ WCHAR _str = w;
866
+ CHAR str[10];
867
+ DWORD len = WideCharToMultiByte(CP_UTF8, 0, &_str, 1, (LPSTR)str, 10, NULL, NULL);
868
+ str[len] = '\0';
869
+ v = rb_str_new(str, len);
870
+ shoes_app_keypress(app, v);
871
+ }
872
+ }
873
+ break;
874
+
875
+ case WM_KEYDOWN:
876
+ app->os.altkey = FALSE;
877
+ case WM_SYSKEYDOWN:
878
+ shoes_app_keydown(app, kh_down_v);
879
+ if (w == VK_CONTROL)
880
+ app->os.ctrlkey = TRUE;
881
+ else if (w == VK_MENU)
882
+ app->os.altkey = TRUE;
883
+ else if (w == VK_SHIFT)
884
+ app->os.shiftkey = TRUE;
885
+ KEYPRESS(ESCAPE, escape)
886
+ KEYPRESS(INSERT, insert)
887
+ KEYPRESS(DELETE, delete)
888
+ KEYPRESS(PRIOR, page_up)
889
+ KEYPRESS(NEXT, page_down)
890
+ KEYPRESS(HOME, home)
891
+ KEYPRESS(END, end)
892
+ KEYPRESS(LEFT, left)
893
+ KEYPRESS(UP, up)
894
+ KEYPRESS(RIGHT, right)
895
+ KEYPRESS(DOWN, down)
896
+ KEYPRESS(F1, f1)
897
+ KEYPRESS(F2, f2)
898
+ KEYPRESS(F3, f3)
899
+ KEYPRESS(F4, f4)
900
+ KEYPRESS(F5, f5)
901
+ KEYPRESS(F6, f6)
902
+ KEYPRESS(F7, f7)
903
+ KEYPRESS(F8, f8)
904
+ KEYPRESS(F9, f9)
905
+ KEYPRESS(F10, f10)
906
+ KEYPRESS(F11, f11)
907
+ KEYPRESS(F12, f12)
908
+ else if ((w >= 'A' && w <= 'Z') || w == 191 || w == 190) {
909
+ VALUE v;
910
+ char letter = w;
911
+ if (w == 191)
912
+ {
913
+ if (app->os.shiftkey)
914
+ letter = '?';
915
+ else
916
+ letter = '/';
917
+ }
918
+ else if (w == 190)
919
+ {
920
+ if (app->os.shiftkey)
921
+ letter = '>';
922
+ else
923
+ letter = '.';
924
+ }
925
+ else
926
+ {
927
+ if (!app->os.shiftkey)
928
+ letter += 32;
929
+ }
930
+ v = rb_str_new(&letter, 1);
931
+ if (app->os.altkey) {
932
+ KEY_STATE(alt);
933
+ shoes_app_keypress(app, v);
934
+ }
935
+ }
936
+ break;
937
+
938
+ case WM_SYSKEYUP:
939
+ case WM_KEYUP:
940
+ shoes_app_keyup(app, kh_up_v);
941
+ if (w == VK_CONTROL)
942
+ app->os.ctrlkey = FALSE;
943
+ else if (w == VK_MENU)
944
+ app->os.altkey = FALSE;
945
+ else if (w == VK_SHIFT)
946
+ app->os.shiftkey = FALSE;
947
+ break;
948
+
949
+ case WM_MOUSEWHEEL:
950
+ {
951
+ shoes_canvas *canvas;
952
+ int lines = 0, scode = 0;
953
+ int notch = ((int)w >> 16) / WHEEL_DELTA;
954
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines, 0);
955
+ if (lines == WHEEL_PAGESCROLL)
956
+ scode = (int)w < 0 ? SB_PAGEDOWN : SB_PAGEUP;
957
+ else
958
+ {
959
+ scode = (int)w < 0 ? SB_LINEDOWN : SB_LINEUP;
960
+ notch *= lines;
961
+ }
962
+
963
+ INFO("WM_MOUSEWHEEL: %d (%d, %d) %lu\n", w, scode, notch, lines);
964
+ notch = abs(notch);
965
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
966
+ while (notch--)
967
+ shoes_canvas_win32_vscroll(canvas, scode, 0);
968
+ }
969
+ break;
970
+
971
+ case WM_VSCROLL:
972
+ {
973
+ shoes_canvas *canvas;
974
+ Data_Get_Struct(app->canvas, shoes_canvas, canvas);
975
+ shoes_canvas_win32_vscroll(canvas, LOWORD(w), HIWORD(w));
976
+ }
977
+ break;
978
+
979
+ case WM_TIMER:
980
+ {
981
+ int id = LOWORD(w);
982
+ VALUE timer = rb_ary_entry(app->extras, id - SHOES_CONTROL1);
983
+ if (!NIL_P(timer))
984
+ {
985
+ if (rb_obj_is_kind_of(timer, cTimer))
986
+ KillTimer(win, id);
987
+ shoes_timer_call(timer);
988
+ }
989
+ }
990
+ break;
991
+
992
+ case WM_ACTIVATE:
993
+ if (LOWORD(w) == WA_INACTIVE)
994
+ {
995
+ int i;
996
+ HWND newFocus = GetFocus();
997
+ for (i = 0; i < RARRAY_LEN(app->slot->controls); i++)
998
+ {
999
+ VALUE ctrl = rb_ary_entry(app->slot->controls, i);
1000
+ if (rb_obj_is_kind_of(ctrl, cNative))
1001
+ {
1002
+ shoes_control *self_t;
1003
+ Data_Get_Struct(ctrl, shoes_control, self_t);
1004
+ if (self_t->ref == newFocus)
1005
+ {
1006
+ app->slot->focus = ctrl;
1007
+ break;
1008
+ }
1009
+ }
1010
+ }
1011
+ }
1012
+ break;
1013
+
1014
+ case WM_SETFOCUS:
1015
+ if (!NIL_P(app->slot->focus))
1016
+ {
1017
+ shoes_control_focus(app->slot->focus);
1018
+ }
1019
+ break;
1020
+
1021
+ case WM_HSCROLL:
1022
+ {
1023
+ if (LOWORD(w) == TB_THUMBTRACK)
1024
+ {
1025
+ int id = GetDlgCtrlID((HWND)l);
1026
+ VALUE control = rb_ary_entry(app->slot->controls, id - SHOES_CONTROL1);
1027
+ if (!NIL_P(control))
1028
+ shoes_control_send(control, s_change);
1029
+ }
1030
+ }
1031
+ break;
1032
+
1033
+ case WM_COMMAND:
1034
+ if ((HWND)l)
1035
+ {
1036
+ switch (HIWORD(w))
1037
+ {
1038
+ case BN_CLICKED:
1039
+ {
1040
+ int id = LOWORD(w);
1041
+ VALUE control = rb_ary_entry(app->slot->controls, id - SHOES_CONTROL1);
1042
+ if (!NIL_P(control))
1043
+ shoes_button_send_click(control);
1044
+ }
1045
+ break;
1046
+
1047
+ case CBN_SELCHANGE:
1048
+ case EN_CHANGE:
1049
+ {
1050
+ int id = LOWORD(w);
1051
+ VALUE control = rb_ary_entry(app->slot->controls, id - SHOES_CONTROL1);
1052
+ if (!NIL_P(control))
1053
+ shoes_control_send(control, s_change);
1054
+ }
1055
+ break;
1056
+ }
1057
+ }
1058
+ break;
1059
+ }
1060
+
1061
+ return DefWindowProc(win, msg, w, l);
1062
+ }
1063
+
1064
+ shoes_code
1065
+ shoes_app_cursor(shoes_app *app, ID cursor)
1066
+ {
1067
+ HCURSOR c;
1068
+ if (app->slot == NULL || app->slot->window == NULL)
1069
+ goto done;
1070
+
1071
+ if (cursor == s_hand || cursor == s_link)
1072
+ {
1073
+ c = LoadCursor(NULL, IDC_HAND);
1074
+ }
1075
+ else if (cursor == s_arrow)
1076
+ {
1077
+ c = LoadCursor(NULL, IDC_ARROW);
1078
+ }
1079
+ else if (cursor == s_text)
1080
+ {
1081
+ c = LoadCursor(NULL, IDC_IBEAM);
1082
+ }
1083
+ else
1084
+ goto done;
1085
+
1086
+ SetCursor(c);
1087
+
1088
+ app->cursor = cursor;
1089
+
1090
+ done:
1091
+ return SHOES_OK;
1092
+ }
1093
+
1094
+ shoes_code
1095
+ shoes_classex_init()
1096
+ {
1097
+ shoes_code code = SHOES_OK;
1098
+
1099
+ shoes_world->os.hiddenex.cbSize = sizeof(WNDCLASSEX);
1100
+ shoes_world->os.hiddenex.style = 0;
1101
+ shoes_world->os.hiddenex.lpfnWndProc = (WNDPROC)shoes_hidden_win32proc;
1102
+ shoes_world->os.hiddenex.cbClsExtra = 0;
1103
+ shoes_world->os.hiddenex.cbWndExtra = 0;
1104
+ shoes_world->os.hiddenex.hInstance = shoes_world->os.instance;
1105
+ shoes_world->os.hiddenex.hIcon = NULL;
1106
+ shoes_world->os.hiddenex.hCursor = NULL;
1107
+ shoes_world->os.hiddenex.hbrBackground = NULL;
1108
+ shoes_world->os.hiddenex.lpszMenuName = NULL;
1109
+ shoes_world->os.hiddenex.lpszClassName = SHOES_HIDDENCLS;
1110
+ shoes_world->os.hiddenex.hIconSm = NULL;
1111
+
1112
+ if (!RegisterClassEx(&shoes_world->os.hiddenex))
1113
+ {
1114
+ QUIT("Couldn't register Shoes hidden window class.");
1115
+ }
1116
+
1117
+
1118
+ shoes_world->os.classex.hInstance = shoes_world->os.instance;
1119
+ shoes_world->os.classex.lpszClassName = SHOES_SHORTNAME;
1120
+ shoes_world->os.classex.lpfnWndProc = shoes_app_win32proc;
1121
+ shoes_world->os.classex.style = 0;
1122
+ shoes_world->os.classex.cbSize = sizeof(WNDCLASSEX);
1123
+ shoes_world->os.classex.hIcon = LoadIcon(shoes_world->os.instance, IDI_APPLICATION);
1124
+ shoes_world->os.classex.hIconSm = LoadIcon(shoes_world->os.instance, IDI_APPLICATION);
1125
+ shoes_world->os.classex.hCursor = LoadCursor(NULL, IDC_ARROW);
1126
+ shoes_world->os.classex.lpszMenuName = NULL;
1127
+ shoes_world->os.classex.cbClsExtra = 0;
1128
+ shoes_world->os.classex.cbWndExtra = 0;
1129
+ shoes_world->os.classex.hbrBackground = (HBRUSH)COLOR_WINDOW;
1130
+
1131
+ shoes_world->os.classatom = RegisterClassEx(&shoes_world->os.classex);
1132
+ if (!shoes_world->os.classatom)
1133
+ {
1134
+ QUIT("Couldn't register WIN32 window class.");
1135
+ }
1136
+
1137
+ shoes_world->os.vlclassex.hInstance = shoes_world->os.slotex.hInstance = shoes_world->os.instance;
1138
+ shoes_world->os.vlclassex.lpszClassName = SHOES_VLCLASS;
1139
+ shoes_world->os.slotex.lpszClassName = SHOES_SLOTCLASS;
1140
+ shoes_world->os.vlclassex.style = shoes_world->os.slotex.style = CS_NOCLOSE;
1141
+ shoes_world->os.vlclassex.lpfnWndProc = DefWindowProc;
1142
+ shoes_world->os.slotex.lpfnWndProc = shoes_slot_win32proc;
1143
+ shoes_world->os.vlclassex.cbSize = shoes_world->os.slotex.cbSize = sizeof(WNDCLASSEX);
1144
+ shoes_world->os.vlclassex.hIcon = shoes_world->os.slotex.hIcon = NULL;
1145
+ shoes_world->os.vlclassex.hIconSm = shoes_world->os.slotex.hIconSm = NULL;
1146
+ shoes_world->os.vlclassex.hCursor = shoes_world->os.slotex.hCursor = LoadCursor(NULL, IDC_ARROW);
1147
+ shoes_world->os.vlclassex.lpszMenuName = shoes_world->os.slotex.lpszMenuName = NULL;
1148
+ shoes_world->os.vlclassex.cbClsExtra = shoes_world->os.slotex.cbClsExtra = 0;
1149
+ shoes_world->os.vlclassex.cbWndExtra = shoes_world->os.slotex.cbWndExtra = 0;
1150
+ shoes_world->os.vlclassex.hbrBackground = shoes_world->os.slotex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
1151
+
1152
+ if (!RegisterClassEx(&shoes_world->os.slotex) || !RegisterClassEx(&shoes_world->os.vlclassex))
1153
+ {
1154
+ QUIT("Couldn't register VLC window class.");
1155
+ }
1156
+
1157
+ quit:
1158
+ return code;
1159
+ }
1160
+
1161
+ void
1162
+ shoes_native_app_resized(shoes_app *app)
1163
+ {
1164
+ if (app->slot->window != NULL)
1165
+ {
1166
+ RECT r;
1167
+ GetWindowRect(app->slot->window, &r);
1168
+ r.right = r.left + app->width;
1169
+ r.bottom = r.top + app->height;
1170
+ AdjustWindowRect(&r, WINDOW_STYLE, FALSE);
1171
+
1172
+ MoveWindow(app->slot->window, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
1173
+ }
1174
+ }
1175
+
1176
+ void
1177
+ shoes_native_app_title(shoes_app *app, char *msg)
1178
+ {
1179
+ WCHAR *buffer = shoes_wchar(msg);
1180
+ if (buffer != NULL)
1181
+ {
1182
+ SetWindowTextW(app->slot->window, buffer);
1183
+ SHOE_FREE(buffer);
1184
+ }
1185
+ }
1186
+
1187
+ void
1188
+ shoes_native_app_fullscreen(shoes_app *app, char yn)
1189
+ {
1190
+ if (yn)
1191
+ GetWindowRect(app->slot->window, &app->os.normal);
1192
+ SetWindowLong(app->slot->window, GWL_STYLE, yn ? WINDOW_STYLE_FULLSCREEN : app->os.style);
1193
+ ShowWindow(FindWindow("Shell_TrayWnd", NULL), yn ? SW_HIDE : SW_SHOW);
1194
+ if (!yn)
1195
+ MoveWindow(app->slot->window, app->os.normal.left, app->os.normal.top,
1196
+ app->os.normal.right - app->os.normal.left, app->os.normal.bottom - app->os.normal.top, TRUE);
1197
+ ShowWindow(app->slot->window, yn ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL);
1198
+ }
1199
+
1200
+ shoes_code
1201
+ shoes_native_app_open(shoes_app *app, char *path, int dialog)
1202
+ {
1203
+ shoes_code code = SHOES_OK;
1204
+ LONG style;
1205
+ DWORD exStyle = dialog ? WS_EX_WINDOWEDGE : WS_EX_CLIENTEDGE;
1206
+
1207
+ app->slot->controls = Qnil;
1208
+ app->slot->focus = Qnil;
1209
+ app->slot->parent = NULL;
1210
+ app->os.ctrlkey = FALSE;
1211
+ app->os.altkey = FALSE;
1212
+ app->os.shiftkey = FALSE;
1213
+
1214
+ // remove the menu
1215
+ app->os.normal.left = 0;
1216
+ app->os.normal.top = 0;
1217
+ app->os.normal.right = app->width;
1218
+ app->os.normal.bottom = app->height;
1219
+ AdjustWindowRectEx(&app->os.normal, WINDOW_STYLE, FALSE, exStyle);
1220
+
1221
+ if (!shoes_world->os.doublebuffer)
1222
+ {
1223
+ if (rb_eval_string("$NOLAYERED == 1"))
1224
+ exStyle |= WS_EX_COMPOSITED;
1225
+ else
1226
+ exStyle |= WS_EX_COMPOSITED|WS_EX_LAYERED;
1227
+ }
1228
+ else
1229
+ exStyle |= WS_EX_COMPOSITED;
1230
+
1231
+ style = app->os.style = WINDOW_STYLE |
1232
+ (app->resizable ? (WS_THICKFRAME | WS_MAXIMIZEBOX) : WS_DLGFRAME) |
1233
+ WS_VSCROLL | ES_AUTOVSCROLL;
1234
+ if (app->fullscreen)
1235
+ style = WINDOW_STYLE_FULLSCREEN;
1236
+
1237
+ if (shoes_world->os.doublebuffer)
1238
+ style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
1239
+
1240
+ app->slot->window = CreateWindowEx(
1241
+ exStyle, SHOES_SHORTNAME, SHOES_APPNAME, style,
1242
+ CW_USEDEFAULT, CW_USEDEFAULT,
1243
+ app->os.normal.right-app->os.normal.left, app->os.normal.bottom-app->os.normal.top,
1244
+ HWND_DESKTOP,
1245
+ NULL,
1246
+ shoes_world->os.instance,
1247
+ NULL);
1248
+
1249
+ SetWindowLong(app->slot->window, GWL_USERDATA, (long)app);
1250
+ shoes_win32_center(app->slot->window);
1251
+
1252
+ SCROLLINFO si;
1253
+ si.cbSize = sizeof(SCROLLINFO);
1254
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
1255
+ si.nMin = 0;
1256
+ si.nMax = 0;
1257
+ si.nPage = 0;
1258
+ si.nPos = 0;
1259
+ SetScrollInfo(app->slot->window, SB_VERT, &si, TRUE);
1260
+
1261
+ return code;
1262
+ }
1263
+
1264
+ void
1265
+ shoes_native_app_show(shoes_app *app)
1266
+ {
1267
+ // TODO: disable parent windows of dialogs
1268
+ // if (dialog && !NIL_P(app->owner))
1269
+ // {
1270
+ // shoes_app *owner;
1271
+ // Data_Get_Struct(app->owner, shoes_app, owner);
1272
+ // EnableWindow(owner->slot->window, FALSE);
1273
+ // }
1274
+ ShowWindow(app->slot->window, SW_SHOWNORMAL);
1275
+ }
1276
+
1277
+ void shoes_tab_focus(shoes_app *app)
1278
+ {
1279
+ int i, j, n;
1280
+ HWND newFocus = GetFocus();
1281
+ n = RARRAY_LEN(app->slot->controls);
1282
+
1283
+ for (i = 0; i < n; i++)
1284
+ {
1285
+ if (app->os.shiftkey)
1286
+ {
1287
+ if (i == 0)
1288
+ j = n - 1;
1289
+ else
1290
+ j = i - 1;
1291
+ }
1292
+ else
1293
+ {
1294
+ if (i == n - 1)
1295
+ j = 0;
1296
+ else
1297
+ j = i + 1;
1298
+ }
1299
+
1300
+ VALUE ctrl = rb_ary_entry(app->slot->controls, i);
1301
+ VALUE nctrl = rb_ary_entry(app->slot->controls, j);
1302
+
1303
+ if (rb_obj_is_kind_of(ctrl, cNative))
1304
+ {
1305
+ shoes_control *self_t;
1306
+ Data_Get_Struct(ctrl, shoes_control, self_t);
1307
+ if (self_t->ref == newFocus)
1308
+ {
1309
+ app->slot->focus = nctrl;
1310
+ shoes_control_focus(app->slot->focus);
1311
+ break;
1312
+ }
1313
+ else
1314
+ {
1315
+ if (i == n - 1)
1316
+ {
1317
+ if (app->os.shiftkey)
1318
+ nctrl = rb_ary_entry(app->slot->controls, n - 1);
1319
+ else
1320
+ nctrl = rb_ary_entry(app->slot->controls, 0);
1321
+ app->slot->focus = nctrl;
1322
+ shoes_control_focus(app->slot->focus);
1323
+ break;
1324
+ }
1325
+ }
1326
+ }
1327
+ }
1328
+ }
1329
+
1330
+ void
1331
+ shoes_native_loop()
1332
+ {
1333
+ MSG msgs;
1334
+ while (msgs.message != WM_QUIT)
1335
+ {
1336
+ BOOL msg = PeekMessage(&msgs, NULL, 0, 0, PM_REMOVE);
1337
+ if (msg)
1338
+ {
1339
+ HWND focused = GetForegroundWindow();
1340
+ shoes_app *appk = (shoes_app *)GetWindowLong(focused, GWL_USERDATA);
1341
+ if (msgs.message == WM_KEYDOWN || msgs.message == WM_KEYUP)
1342
+ {
1343
+ ATOM wndatom = GetClassLong(focused, GCW_ATOM);
1344
+ if (appk != NULL && wndatom == shoes_world->os.classatom && RARRAY_LEN(appk->slot->controls) > 0)
1345
+ {
1346
+ switch (msgs.wParam)
1347
+ {
1348
+ case VK_SHIFT:
1349
+ if (msgs.message == WM_KEYDOWN)
1350
+ appk->os.shiftkey = TRUE;
1351
+ else
1352
+ appk->os.shiftkey = FALSE;
1353
+ msg = FALSE;
1354
+ break;
1355
+ case VK_TAB:
1356
+ if (msgs.message == WM_KEYUP) shoes_tab_focus(appk);
1357
+ msg = FALSE;
1358
+ break;
1359
+ case VK_UP: case VK_LEFT: case VK_DOWN:
1360
+ case VK_RIGHT: case VK_PRIOR: case VK_NEXT:
1361
+ break;
1362
+ default:
1363
+ msg = FALSE;
1364
+ }
1365
+ }
1366
+ else msg = FALSE;
1367
+ }
1368
+ else if (msgs.message == WM_SYSCHAR || msgs.message == WM_CHAR)
1369
+ msg = FALSE;
1370
+ else if (msgs.message == WM_MOUSEMOVE && focused == GetActiveWindow())
1371
+ shoes_app_cursor(appk, appk->cursor);
1372
+
1373
+ if (msg)
1374
+ msg = IsDialogMessage(focused, &msgs);
1375
+
1376
+ if (!msg)
1377
+ {
1378
+ TranslateMessage(&msgs);
1379
+ DispatchMessage(&msgs);
1380
+ }
1381
+ }
1382
+ else
1383
+ {
1384
+ rb_eval_string("sleep(0.001)");
1385
+ }
1386
+ }
1387
+ }
1388
+
1389
+ void
1390
+ shoes_native_app_close(shoes_app *app)
1391
+ {
1392
+ SendMessage(APP_WINDOW(app), WM_CLOSE, 0, 0);
1393
+ }
1394
+
1395
+ void
1396
+ shoes_browser_open(char *url)
1397
+ {
1398
+ ShellExecute(0, "open", url, 0, 0, 0);
1399
+ }
1400
+
1401
+ void
1402
+ shoes_slot_init(VALUE c, SHOES_SLOT_OS *parent, int x, int y, int width, int height, int scrolls, int toplevel)
1403
+ {
1404
+ shoes_canvas *canvas;
1405
+ SHOES_SLOT_OS *slot;
1406
+ Data_Get_Struct(c, shoes_canvas, canvas);
1407
+ slot = shoes_slot_alloc(canvas, parent, toplevel);
1408
+ slot->parent = parent;
1409
+ slot->vscroll = scrolls;
1410
+
1411
+ if (toplevel)
1412
+ {
1413
+ slot->dc = parent->dc;
1414
+ slot->window = parent->window;
1415
+ slot->controls = parent->controls;
1416
+ }
1417
+ else
1418
+ {
1419
+ slot->controls = rb_ary_new();
1420
+ slot->dc = NULL;
1421
+
1422
+ DWORD exStyle = WS_EX_TRANSPARENT;
1423
+
1424
+ if (shoes_world->os.doublebuffer)
1425
+ exStyle = WS_EX_COMPOSITED;
1426
+
1427
+ slot->window = CreateWindowEx(exStyle, SHOES_SLOTCLASS, "Shoes Slot Window",
1428
+ WS_CHILD | WS_TABSTOP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
1429
+ x, y, width, height, parent->window, NULL,
1430
+ (HINSTANCE)GetWindowLong(parent->window, GWL_HINSTANCE), NULL);
1431
+
1432
+ SetWindowPos(slot->window, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
1433
+ SetWindowLong(slot->window, GWL_USERDATA, (long)c);
1434
+ }
1435
+ if (toplevel) shoes_canvas_size(c, width, height);
1436
+ }
1437
+
1438
+ void
1439
+ shoes_slot_destroy(shoes_canvas *canvas, shoes_canvas *pc)
1440
+ {
1441
+ if (shoes_world->os.doublebuffer)
1442
+ DeleteDC(canvas->slot->dc);
1443
+
1444
+ DestroyWindow(canvas->slot->window);
1445
+ }
1446
+
1447
+ cairo_t *
1448
+ shoes_cairo_create(shoes_canvas *canvas)
1449
+ {
1450
+ if (canvas->slot->surface != NULL)
1451
+ return NULL;
1452
+
1453
+ RECT rc;
1454
+ GetClientRect(canvas->slot->window, &rc);
1455
+
1456
+ if (shoes_world->os.doublebuffer)
1457
+ {
1458
+ if (canvas->slot->window == canvas->app->slot->window)
1459
+ {
1460
+ canvas->slot->dc = canvas->app->slot->dc;
1461
+ }
1462
+
1463
+ // So that siblings see the changes, we must copy from siblings beneath us
1464
+ if (canvas->slot->window != canvas->app->slot->window)
1465
+ {
1466
+ HANDLE current = canvas->slot->window;
1467
+ current = GetWindow(current, GW_HWNDLAST);
1468
+
1469
+ RECT canvas_rcw;
1470
+ GetWindowRect(canvas->slot->window, &canvas_rcw);
1471
+ while(current != canvas->slot->window)
1472
+ {
1473
+ shoes_canvas *sibling_canvas;
1474
+ VALUE c = (VALUE)GetWindowLong(current, GWL_USERDATA);
1475
+
1476
+ if (c == (VALUE)NULL)
1477
+ {
1478
+ break;
1479
+ }
1480
+
1481
+ Data_Get_Struct(c, shoes_canvas, sibling_canvas);
1482
+
1483
+ RECT sibling_rc;
1484
+ RECT sibling_rcw;
1485
+ GetClientRect(sibling_canvas->slot->window, &sibling_rc);
1486
+ GetWindowRect(sibling_canvas->slot->window, &sibling_rcw);
1487
+
1488
+ BitBlt(canvas->slot->dc, sibling_rcw.left-canvas_rcw.left, sibling_rcw.top-canvas_rcw.top, sibling_rc.right, sibling_rc.bottom, sibling_canvas->slot->dc, 0, 0, SRCCOPY);
1489
+ current = GetWindow(current, GW_HWNDPREV);
1490
+ }
1491
+ }
1492
+ }
1493
+ else
1494
+ {
1495
+ canvas->slot->dc = BeginPaint(canvas->slot->window, &canvas->slot->ps);
1496
+ }
1497
+
1498
+ if (canvas->slot->window == canvas->app->slot->window)
1499
+ {
1500
+ HBRUSH bg = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
1501
+ FillRect(canvas->slot->dc, &rc, bg);
1502
+ DeleteObject(bg);
1503
+ }
1504
+
1505
+ canvas->slot->surface = cairo_win32_surface_create(canvas->slot->dc);
1506
+
1507
+ cairo_t *cr = cairo_create(canvas->slot->surface);
1508
+ cairo_translate(cr, 0, -canvas->slot->scrolly);
1509
+ return cr;
1510
+ }
1511
+
1512
+ void shoes_cairo_destroy(shoes_canvas *canvas)
1513
+ {
1514
+ RECT rc;
1515
+ GetClientRect(canvas->slot->window, &rc);
1516
+
1517
+ cairo_surface_destroy(canvas->slot->surface);
1518
+ canvas->slot->surface = NULL;
1519
+
1520
+ if (shoes_world->os.doublebuffer)
1521
+ {
1522
+ // We are manually double buffering in Vista, so we need to copy the
1523
+ // image over to the actual display.
1524
+ BeginPaint(canvas->slot->window, &canvas->slot->ps);
1525
+
1526
+ if (canvas->slot->window == canvas->app->slot->window)
1527
+ {
1528
+ canvas->slot->dc = canvas->app->slot->dc;
1529
+ }
1530
+
1531
+ BitBlt(canvas->slot->ps.hdc,
1532
+ 0, 0, rc.right, rc.bottom,
1533
+ canvas->slot->dc,
1534
+ 0, 0, SRCCOPY);
1535
+
1536
+ RECT rcw;
1537
+ GetWindowRect(canvas->slot->window, &rcw);
1538
+
1539
+ // So children see the changes, we copy to each child
1540
+ HANDLE current;
1541
+
1542
+ current = canvas->slot->window;
1543
+ current = GetWindow(current, GW_CHILD);
1544
+
1545
+ while(current != NULL)
1546
+ {
1547
+ shoes_canvas *child_canvas;
1548
+ VALUE c = (VALUE)GetWindowLong(current, GWL_USERDATA);
1549
+
1550
+ if (c == (VALUE)NULL)
1551
+ break;
1552
+
1553
+ Data_Get_Struct(c, shoes_canvas, child_canvas);
1554
+
1555
+ RECT child_rc;
1556
+ RECT child_rcw;
1557
+ GetClientRect(child_canvas->slot->window, &child_rc);
1558
+ GetWindowRect(child_canvas->slot->window, &child_rcw);
1559
+
1560
+ if (canvas->slot->window == canvas->app->slot->window)
1561
+ {
1562
+ POINT p = {0};
1563
+ ClientToScreen(child_canvas->app->slot->window, &p);
1564
+ BitBlt(child_canvas->slot->dc, 0, 0, child_rc.right, child_rc.bottom, canvas->slot->dc, child_rcw.left-p.x, child_rcw.top-p.y, SRCCOPY);
1565
+ }
1566
+ else
1567
+ {
1568
+ BitBlt(child_canvas->slot->dc, 0, 0, child_rc.right, child_rc.bottom, canvas->slot->dc, child_rcw.left-rcw.left, child_rcw.top-rcw.top, SRCCOPY);
1569
+ }
1570
+ current = GetWindow(current, GW_HWNDNEXT);
1571
+ }
1572
+
1573
+ // update parents
1574
+ SHOES_SLOT_OS *child = canvas->slot;
1575
+
1576
+ while (child->window != canvas->app->slot->window)
1577
+ {
1578
+ SHOES_SLOT_OS *parent;
1579
+ parent = (SHOES_SLOT_OS*)child->parent;
1580
+
1581
+ RECT parent_rcw;
1582
+ RECT canvas_rc;
1583
+ RECT canvas_rcw;
1584
+
1585
+ GetWindowRect(parent->window, &parent_rcw);
1586
+
1587
+ GetClientRect(child->window, &canvas_rc);
1588
+ GetWindowRect(child->window, &canvas_rcw);
1589
+
1590
+ BitBlt(parent->dc, canvas_rcw.left-parent_rcw.left, canvas_rcw.top-parent_rcw.top, canvas_rc.right, canvas_rc.bottom, child->dc, 0, 0, SRCCOPY);
1591
+ child = parent;
1592
+ }
1593
+ }
1594
+
1595
+ EndPaint(canvas->slot->window, &canvas->slot->ps);
1596
+ }
1597
+
1598
+ void
1599
+ shoes_group_clear(SHOES_GROUP_OS *group)
1600
+ {
1601
+ }
1602
+
1603
+ void
1604
+ shoes_native_canvas_place(shoes_canvas *self_t, shoes_canvas *pc)
1605
+ {
1606
+ RECT r;
1607
+ GetWindowRect(self_t->slot->window, &r);
1608
+ if (r.left != self_t->place.ix + self_t->place.dx ||
1609
+ r.top != (self_t->place.iy + self_t->place.dy) - pc->slot->scrolly ||
1610
+ r.right - r.left != self_t->place.iw ||
1611
+ r.bottom - r.top != self_t->place.ih)
1612
+ {
1613
+ MoveWindow(self_t->slot->window, self_t->place.ix + self_t->place.dx,
1614
+ (self_t->place.iy + self_t->place.dy) - pc->slot->scrolly, self_t->place.iw,
1615
+ self_t->place.ih, TRUE);
1616
+ }
1617
+ }
1618
+
1619
+ void
1620
+ shoes_native_canvas_resize(shoes_canvas *canvas)
1621
+ {
1622
+ if (shoes_world->os.doublebuffer)
1623
+ {
1624
+ RECT rc;
1625
+ GetClientRect(canvas->slot->window, &rc);
1626
+
1627
+ HDC windowDC = GetDC(canvas->slot->window);
1628
+ canvas->slot->dc = CreateCompatibleDC(windowDC);
1629
+
1630
+ HBITMAP hbmp = CreateCompatibleBitmap(windowDC, rc.right, rc.bottom);
1631
+ SelectObject(canvas->slot->dc, hbmp);
1632
+ DeleteObject(hbmp);
1633
+
1634
+ ReleaseDC(canvas->slot->window, windowDC);
1635
+ }
1636
+ }
1637
+
1638
+ void
1639
+ shoes_native_control_hide(SHOES_CONTROL_REF ref)
1640
+ {
1641
+ ShowWindow(ref, SW_HIDE);
1642
+ }
1643
+
1644
+ void
1645
+ shoes_native_control_show(SHOES_CONTROL_REF ref)
1646
+ {
1647
+ ShowWindow(ref, SW_SHOW);
1648
+ }
1649
+
1650
+ void
1651
+ shoes_native_control_position(SHOES_CONTROL_REF ref, shoes_place *p1, VALUE self,
1652
+ shoes_canvas *canvas, shoes_place *p2)
1653
+ {
1654
+ PLACE_COORDS();
1655
+ MoveWindow(ref, p2->ix + p2->dx, p2->iy + p2->dy, p2->iw, p2->ih, TRUE);
1656
+ if (shoes_world->os.doublebuffer)
1657
+ {
1658
+ RECT rc;
1659
+ GetClientRect(canvas->slot->window, &rc);
1660
+
1661
+ // HDC windowDC = GetDC(canvas->slot->window);
1662
+ // canvas->slot->dc = CreateCompatibleDC(windowDC);
1663
+
1664
+ HBITMAP hbmp = CreateCompatibleBitmap(canvas->slot->dc, rc.right, rc.bottom);
1665
+ SelectObject(canvas->slot->dc, hbmp);
1666
+ DeleteObject(hbmp);
1667
+
1668
+ // ReleaseDC(canvas->slot->window, windowDC);
1669
+ }
1670
+ }
1671
+
1672
+ void
1673
+ shoes_native_control_position_no_pad(SHOES_CONTROL_REF ref, shoes_place *p1, VALUE self,
1674
+ shoes_canvas *canvas, shoes_place *p2)
1675
+ {
1676
+ PLACE_COORDS_NO_PAD();
1677
+ MoveWindow(ref, p2->ix + p2->dx, p2->iy + p2->dy, p2->iw, p2->ih, TRUE);
1678
+ if (shoes_world->os.doublebuffer)
1679
+ {
1680
+ RECT rc;
1681
+ GetClientRect(canvas->slot->window, &rc);
1682
+
1683
+ // HDC windowDC = GetDC(canvas->slot->window);
1684
+ // canvas->slot->dc = CreateCompatibleDC(windowDC);
1685
+
1686
+ HBITMAP hbmp = CreateCompatibleBitmap(canvas->slot->dc, rc.right, rc.bottom);
1687
+ SelectObject(canvas->slot->dc, hbmp);
1688
+ DeleteObject(hbmp);
1689
+
1690
+ // ReleaseDC(canvas->slot->window, windowDC);
1691
+ }
1692
+ }
1693
+
1694
+ void
1695
+ shoes_native_control_repaint(SHOES_CONTROL_REF ref, shoes_place *p1,
1696
+ shoes_canvas *canvas, shoes_place *p2)
1697
+ {
1698
+ p2->iy -= canvas->slot->scrolly;
1699
+ if (CHANGED_COORDS())
1700
+ shoes_native_control_position(ref, p1, Qnil, canvas, p2);
1701
+ p2->iy += canvas->slot->scrolly;
1702
+ }
1703
+
1704
+ void
1705
+ shoes_native_control_repaint_no_pad(SHOES_CONTROL_REF ref, shoes_place *p1,
1706
+ shoes_canvas *canvas, shoes_place *p2)
1707
+ {
1708
+ p2->iy -= canvas->slot->scrolly;
1709
+ if (CHANGED_COORDS_NO_PAD())
1710
+ shoes_native_control_position_no_pad(ref, p1, Qnil, canvas, p2);
1711
+ p2->iy += canvas->slot->scrolly;
1712
+ }
1713
+
1714
+ void
1715
+ shoes_native_control_state(SHOES_CONTROL_REF ref, BOOL sensitive, BOOL setting)
1716
+ {
1717
+ EnableWindow(ref, sensitive);
1718
+ SendMessage(ref, EM_SETREADONLY, !setting, 0);
1719
+ }
1720
+
1721
+ void
1722
+ shoes_native_control_focus(SHOES_CONTROL_REF ref)
1723
+ {
1724
+ SetFocus(ref);
1725
+ }
1726
+
1727
+ void
1728
+ shoes_native_control_remove(SHOES_CONTROL_REF ref, shoes_canvas *canvas)
1729
+ {
1730
+ if (GetFocus() == ref) SetFocus(canvas->app->slot->window);
1731
+ DestroyWindow(ref);
1732
+ }
1733
+
1734
+ void
1735
+ shoes_native_control_free(SHOES_CONTROL_REF ref)
1736
+ {
1737
+ }
1738
+
1739
+ inline void shoes_win32_control_font(int id, HWND hwnd)
1740
+ {
1741
+ SendDlgItemMessage(hwnd, id, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
1742
+ }
1743
+
1744
+ SHOES_SURFACE_REF
1745
+ shoes_native_surface_new(shoes_canvas *canvas, VALUE self, shoes_place *place)
1746
+ {
1747
+ int cid = SHOES_CONTROL1 + RARRAY_LEN(canvas->slot->controls);
1748
+ SHOES_SURFACE_REF ref = CreateWindowEx(WS_EX_TRANSPARENT, SHOES_VLCLASS, "Shoes VLC Window",
1749
+ WS_CHILD | WS_TABSTOP | WS_VISIBLE,
1750
+ place->ix + place->dx, place->iy + place->dy,
1751
+ place->iw, place->ih,
1752
+ canvas->slot->window, (HMENU)cid,
1753
+ (HINSTANCE)GetWindowLong(canvas->slot->window, GWL_HINSTANCE), NULL);
1754
+ SetWindowPos(ref, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
1755
+ rb_ary_push(canvas->slot->controls, self);
1756
+ return ref;
1757
+ }
1758
+
1759
+ void
1760
+ shoes_native_surface_position(SHOES_SURFACE_REF ref, shoes_place *p1,
1761
+ VALUE self, shoes_canvas *canvas, shoes_place *p2)
1762
+ {
1763
+ shoes_native_control_position(ref, p1, self, canvas, p2);
1764
+ }
1765
+
1766
+ void
1767
+ shoes_native_surface_hide(SHOES_SURFACE_REF ref)
1768
+ {
1769
+ shoes_native_control_hide(ref);
1770
+ }
1771
+
1772
+ void
1773
+ shoes_native_surface_show(SHOES_SURFACE_REF ref)
1774
+ {
1775
+ shoes_native_control_show(ref);
1776
+ }
1777
+
1778
+ void
1779
+ shoes_native_surface_remove(shoes_canvas *canvas, SHOES_SURFACE_REF ref)
1780
+ {
1781
+ DestroyWindow(ref);
1782
+ }
1783
+
1784
+ SHOES_CONTROL_REF
1785
+ shoes_native_button(VALUE self, shoes_canvas *canvas, shoes_place *place, char *msg)
1786
+ {
1787
+ int cid = SHOES_CONTROL1 + RARRAY_LEN(canvas->slot->controls);
1788
+ WCHAR *buffer = shoes_wchar(msg);
1789
+ SHOES_CONTROL_REF ref = CreateWindowExW(WS_EX_NOPARENTNOTIFY, L"BUTTON", buffer,
1790
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
1791
+ place->ix + place->dx, place->iy + place->dy, place->iw, place->ih,
1792
+ canvas->slot->window, (HMENU)cid,
1793
+ (HINSTANCE)GetWindowLong(canvas->slot->window, GWL_HINSTANCE),
1794
+ NULL);
1795
+ SetWindowPos(ref, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
1796
+ if (buffer != NULL) SHOE_FREE(buffer);
1797
+ shoes_win32_control_font(cid, canvas->slot->window);
1798
+ rb_ary_push(canvas->slot->controls, self);
1799
+ return ref;
1800
+ }
1801
+
1802
+ SHOES_CONTROL_REF
1803
+ shoes_native_edit_line(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
1804
+ {
1805
+ int cid = SHOES_CONTROL1 + RARRAY_LEN(canvas->slot->controls);
1806
+ SHOES_CONTROL_REF ref = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_TRANSPARENT, TEXT("EDIT"), NULL,
1807
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL |
1808
+ (RTEST(ATTR(attr, secret)) ? ES_PASSWORD : 0),
1809
+ place->ix + place->dx, place->iy + place->dy, place->iw, place->ih,
1810
+ canvas->slot->window, (HMENU)cid,
1811
+ (HINSTANCE)GetWindowLong(canvas->slot->window, GWL_HINSTANCE),
1812
+ NULL);
1813
+
1814
+ shoes_original_edit_line_proc = (WNDPROC)GetWindowLong(ref, GWL_WNDPROC);
1815
+ SetWindowLong(ref, GWL_WNDPROC, (LONG)shoes_edit_line_win32proc);
1816
+
1817
+ SetWindowPos(ref, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
1818
+ shoes_win32_control_font(cid, canvas->slot->window);
1819
+ shoes_native_edit_line_set_text(ref, msg);
1820
+ rb_ary_push(canvas->slot->controls, self);
1821
+ return ref;
1822
+ }
1823
+
1824
+ LRESULT CALLBACK shoes_edit_line_win32proc(HWND win, UINT msg, WPARAM w, LPARAM l)
1825
+ {
1826
+ if (msg == WM_KEYDOWN && w == VK_RETURN) rb_eval_string("Shoes.hook");
1827
+ return CallWindowProc(shoes_original_edit_line_proc, win, msg, w, l);
1828
+ }
1829
+
1830
+ VALUE
1831
+ shoes_native_edit_line_get_text(SHOES_CONTROL_REF ref)
1832
+ {
1833
+ VALUE text;
1834
+ LONG i;
1835
+ char *utf8 = NULL;
1836
+ WCHAR *buffer = NULL;
1837
+ i = (LONG)SendMessageW(ref, WM_GETTEXTLENGTH, 0, 0) + 1;
1838
+ if (!i) goto empty;
1839
+ buffer = SHOE_ALLOC_N(WCHAR, i);
1840
+ if (!buffer) goto empty;
1841
+ SendMessageW(ref, WM_GETTEXT, i, (LPARAM)buffer);
1842
+
1843
+ utf8 = shoes_utf8(buffer);
1844
+ text = rb_str_new2(utf8);
1845
+ SHOE_FREE(utf8);
1846
+ SHOE_FREE(buffer);
1847
+ return text;
1848
+ empty:
1849
+ if (buffer != NULL) SHOE_FREE(buffer);
1850
+ return rb_str_new2("");
1851
+ }
1852
+
1853
+ void
1854
+ shoes_native_edit_line_set_text(SHOES_CONTROL_REF ref, char *msg)
1855
+ {
1856
+ WCHAR *buffer = shoes_wchar(msg);
1857
+ if (buffer != NULL)
1858
+ {
1859
+ SendMessageW(ref, WM_SETTEXT, 0, (LPARAM)buffer);
1860
+ SHOE_FREE(buffer);
1861
+ }
1862
+ }
1863
+
1864
+ SHOES_CONTROL_REF
1865
+ shoes_native_edit_box(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
1866
+ {
1867
+ int cid = SHOES_CONTROL1 + RARRAY_LEN(canvas->slot->controls);
1868
+ DWORD exStyle = WS_EX_CLIENTEDGE;
1869
+ if (!shoes_world->os.doublebuffer)
1870
+ exStyle |= WS_EX_TRANSPARENT;
1871
+
1872
+ SHOES_CONTROL_REF ref = CreateWindowEx(exStyle, TEXT("EDIT"), NULL,
1873
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER | ES_LEFT |
1874
+ ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | ES_NOHIDESEL,
1875
+ place->ix + place->dx, place->iy + place->dy, place->iw, place->ih,
1876
+ canvas->slot->window, (HMENU)cid,
1877
+ (HINSTANCE)GetWindowLong(canvas->slot->window, GWL_HINSTANCE),
1878
+ NULL);
1879
+ SetWindowPos(ref, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
1880
+ shoes_win32_control_font(cid, canvas->slot->window);
1881
+ shoes_native_edit_line_set_text(ref, msg);
1882
+ rb_ary_push(canvas->slot->controls, self);
1883
+ return ref;
1884
+ }
1885
+
1886
+ VALUE
1887
+ shoes_native_edit_box_get_text(SHOES_CONTROL_REF ref)
1888
+ {
1889
+ return shoes_native_edit_line_get_text(ref);
1890
+ }
1891
+
1892
+ void
1893
+ shoes_native_edit_box_set_text(SHOES_CONTROL_REF ref, char *msg)
1894
+ {
1895
+ shoes_native_edit_line_set_text(ref, msg);
1896
+ }
1897
+
1898
+ SHOES_CONTROL_REF
1899
+ shoes_native_list_box(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
1900
+ {
1901
+ int cid = SHOES_CONTROL1 + RARRAY_LEN(canvas->slot->controls);
1902
+ SHOES_CONTROL_REF ref = CreateWindowEx(WS_EX_TRANSPARENT, TEXT("COMBOBOX"), NULL,
1903
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER | CBS_DROPDOWNLIST | WS_VSCROLL,
1904
+ place->ix + place->dx, place->iy + place->dy, place->iw, place->ih,
1905
+ canvas->slot->window, (HMENU)cid,
1906
+ (HINSTANCE)GetWindowLong(canvas->slot->window, GWL_HINSTANCE),
1907
+ NULL);
1908
+ SetWindowPos(ref, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
1909
+ shoes_win32_control_font(cid, canvas->slot->window);
1910
+ rb_ary_push(canvas->slot->controls, self);
1911
+ return ref;
1912
+ }
1913
+
1914
+ void
1915
+ shoes_native_list_box_update(SHOES_CONTROL_REF box, VALUE ary)
1916
+ {
1917
+ long i;
1918
+ SendMessage(box, CB_RESETCONTENT, 0, 0);
1919
+ for (i = 0; i < RARRAY_LEN(ary); i++)
1920
+ {
1921
+ VALUE msg = shoes_native_to_s(rb_ary_entry(ary, i));
1922
+ WCHAR *buffer = shoes_wchar(RSTRING_PTR(msg));
1923
+ if (buffer != NULL)
1924
+ {
1925
+ SendMessageW(box, CB_ADDSTRING, 0, (LPARAM)buffer);
1926
+ SHOE_FREE(buffer);
1927
+ }
1928
+ }
1929
+ }
1930
+
1931
+ VALUE
1932
+ shoes_native_list_box_get_active(SHOES_CONTROL_REF ref, VALUE items)
1933
+ {
1934
+ int sel = SendMessage(ref, CB_GETCURSEL, 0, 0);
1935
+ if (sel >= 0)
1936
+ return rb_ary_entry(items, sel);
1937
+ return Qnil;
1938
+ }
1939
+
1940
+ void
1941
+ shoes_native_list_box_set_active(SHOES_CONTROL_REF box, VALUE ary, VALUE item)
1942
+ {
1943
+ int idx = rb_ary_index_of(ary, item);
1944
+ if (idx < 0) return;
1945
+ SendMessage(box, CB_SETCURSEL, idx, 0);
1946
+ }
1947
+
1948
+ SHOES_CONTROL_REF
1949
+ shoes_native_progress(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
1950
+ {
1951
+ HWND ref = CreateWindowEx(WS_EX_TRANSPARENT, PROGRESS_CLASS, msg,
1952
+ WS_VISIBLE | WS_CHILD | PBS_SMOOTH,
1953
+ place->ix + place->dx, place->iy + place->dy, place->iw, place->ih,
1954
+ canvas->slot->window, NULL,
1955
+ (HINSTANCE)GetWindowLong(canvas->slot->window, GWL_HINSTANCE),
1956
+ NULL);
1957
+ SetWindowPos(ref, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
1958
+ return ref;
1959
+ }
1960
+
1961
+ double
1962
+ shoes_native_progress_get_fraction(SHOES_CONTROL_REF ref)
1963
+ {
1964
+ return SendMessage(ref, PBM_GETPOS, 0, 0) * 0.01;
1965
+ }
1966
+
1967
+ void
1968
+ shoes_native_progress_set_fraction(SHOES_CONTROL_REF ref, double perc)
1969
+ {
1970
+ SendMessage(ref, PBM_SETPOS, (int)(perc * 100), 0L);
1971
+ }
1972
+
1973
+ SHOES_CONTROL_REF
1974
+ shoes_native_slider(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
1975
+ {
1976
+ int cid = SHOES_CONTROL1 + RARRAY_LEN(canvas->slot->controls);
1977
+ HWND ref = CreateWindowEx(WS_EX_TRANSPARENT, TRACKBAR_CLASS, msg,
1978
+ WS_VISIBLE | WS_CHILD,
1979
+ place->ix + place->dx, place->iy + place->dy, place->iw, place->ih,
1980
+ canvas->slot->window, (HMENU)cid,
1981
+ (HINSTANCE)GetWindowLong(canvas->slot->window, GWL_HINSTANCE),
1982
+ NULL);
1983
+ SetWindowPos(ref, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
1984
+ rb_ary_push(canvas->slot->controls, self);
1985
+ return ref;
1986
+ }
1987
+
1988
+ double
1989
+ shoes_native_slider_get_fraction(SHOES_CONTROL_REF ref)
1990
+ {
1991
+ return SendMessage(ref, TBM_GETPOS, 0, 0) * 0.01;
1992
+ }
1993
+
1994
+ void
1995
+ shoes_native_slider_set_fraction(SHOES_CONTROL_REF ref, double perc)
1996
+ {
1997
+ SendMessage(ref, TBM_SETPOS, (int)(perc * 100), 0L);
1998
+ }
1999
+
2000
+ SHOES_CONTROL_REF
2001
+ shoes_native_check(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, char *msg)
2002
+ {
2003
+ int cid = SHOES_CONTROL1 + RARRAY_LEN(canvas->slot->controls);
2004
+ SHOES_CONTROL_REF ref = CreateWindowEx(WS_EX_TRANSPARENT, TEXT("BUTTON"), NULL,
2005
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
2006
+ place->ix + place->dx, place->iy + place->dy, place->iw, place->ih,
2007
+ canvas->slot->window, (HMENU)cid,
2008
+ (HINSTANCE)GetWindowLong(canvas->slot->window, GWL_HINSTANCE),
2009
+ NULL);
2010
+ SetWindowPos(ref, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
2011
+ shoes_win32_control_font(cid, canvas->slot->window);
2012
+ rb_ary_push(canvas->slot->controls, self);
2013
+ return ref;
2014
+ }
2015
+
2016
+ VALUE
2017
+ shoes_native_check_get(SHOES_CONTROL_REF ref)
2018
+ {
2019
+ return SendMessage(ref, BM_GETCHECK, 0, 0) == BST_CHECKED ? Qtrue : Qfalse;
2020
+ }
2021
+
2022
+ void
2023
+ shoes_native_check_set(SHOES_CONTROL_REF ref, int on)
2024
+ {
2025
+ SendMessage(ref, BM_SETCHECK, on ? BST_CHECKED : BST_UNCHECKED, 0L);
2026
+ }
2027
+
2028
+ SHOES_CONTROL_REF
2029
+ shoes_native_radio(VALUE self, shoes_canvas *canvas, shoes_place *place, VALUE attr, VALUE group)
2030
+ {
2031
+ int cid = SHOES_CONTROL1 + RARRAY_LEN(canvas->slot->controls);
2032
+ SHOES_CONTROL_REF ref = CreateWindowEx(WS_EX_TRANSPARENT, TEXT("BUTTON"), NULL,
2033
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_RADIOBUTTON,
2034
+ place->ix + place->dx, place->iy + place->dy, place->iw, place->ih,
2035
+ canvas->slot->window, (HMENU)cid,
2036
+ (HINSTANCE)GetWindowLong(canvas->slot->window, GWL_HINSTANCE),
2037
+ NULL);
2038
+ SetWindowPos(ref, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
2039
+ shoes_win32_control_font(cid, canvas->slot->window);
2040
+ rb_ary_push(canvas->slot->controls, self);
2041
+ return ref;
2042
+ }
2043
+
2044
+ void
2045
+ shoes_native_timer_remove(shoes_canvas *canvas, SHOES_TIMER_REF ref)
2046
+ {
2047
+ KillTimer(canvas->slot->window, ref);
2048
+ }
2049
+
2050
+ SHOES_TIMER_REF
2051
+ shoes_native_timer_start(VALUE self, shoes_canvas *canvas, unsigned int interval)
2052
+ {
2053
+ long nid = rb_ary_index_of(canvas->app->extras, self);
2054
+ SetTimer(canvas->app->slot->window, SHOES_CONTROL1 + nid, interval, NULL);
2055
+ return SHOES_CONTROL1 + nid;
2056
+ }
2057
+
2058
+ VALUE
2059
+ shoes_native_clipboard_get(shoes_app *app)
2060
+ {
2061
+ VALUE paste = Qnil;
2062
+ if (OpenClipboard(app->slot->window))
2063
+ {
2064
+ HANDLE hclip = GetClipboardData(CF_UNICODETEXT);
2065
+ WCHAR *buffer = (WCHAR *)GlobalLock(hclip);
2066
+ char *utf8 = shoes_utf8(buffer);
2067
+ paste = rb_str_new2(utf8);
2068
+ GlobalUnlock(hclip);
2069
+ CloseClipboard();
2070
+ SHOE_FREE(utf8);
2071
+ }
2072
+ return paste;
2073
+ }
2074
+
2075
+ void
2076
+ shoes_native_clipboard_set(shoes_app *app, VALUE string)
2077
+ {
2078
+ if (OpenClipboard(app->slot->window))
2079
+ {
2080
+ WCHAR *buffer = shoes_wchar(RSTRING_PTR(string));
2081
+ LONG buflen = wcslen(buffer);
2082
+ HGLOBAL hclip;
2083
+ EmptyClipboard();
2084
+ hclip = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (buflen + 1) * sizeof(WCHAR));
2085
+ wcsncpy((WCHAR *)GlobalLock(hclip), buffer, buflen + 1);
2086
+ GlobalUnlock(hclip);
2087
+ SetClipboardData(CF_UNICODETEXT, hclip);
2088
+ CloseClipboard();
2089
+ SHOE_FREE(buffer);
2090
+ }
2091
+ }
2092
+
2093
+ VALUE
2094
+ shoes_native_to_s(VALUE text)
2095
+ {
2096
+ text = rb_funcall(text, s_to_s, 0);
2097
+ text = rb_funcall(text, s_gsub, 2, reLF, rb_str_new2("\r\n"));
2098
+ return text;
2099
+ }
2100
+
2101
+ VALUE
2102
+ shoes_native_window_color(shoes_app *app)
2103
+ {
2104
+ DWORD winc = GetSysColor(COLOR_WINDOW);
2105
+ return shoes_color_new(GetRValue(winc), GetGValue(winc), GetBValue(winc), SHOES_COLOR_OPAQUE);
2106
+ }
2107
+
2108
+ VALUE
2109
+ shoes_native_dialog_color(shoes_app *app)
2110
+ {
2111
+ DWORD winc = GetSysColor(COLOR_3DFACE);
2112
+ return shoes_color_new(GetRValue(winc), GetGValue(winc), GetBValue(winc), SHOES_COLOR_OPAQUE);
2113
+ }
2114
+
2115
+ LPWSTR win32_dialog_label = NULL;
2116
+ LPWSTR win32_dialog_answer = NULL;
2117
+
2118
+ BOOL CALLBACK
2119
+ shoes_ask_win32proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2120
+ {
2121
+ switch (message)
2122
+ {
2123
+ case WM_INITDIALOG:
2124
+ SetDlgItemTextW(hwnd, IDQUIZ, win32_dialog_label);
2125
+ if (win32_dialog_label != NULL)
2126
+ {
2127
+ SHOE_FREE(win32_dialog_label);
2128
+ win32_dialog_label = NULL;
2129
+ }
2130
+ if (win32_dialog_answer != NULL)
2131
+ {
2132
+ GlobalFree((HANDLE)win32_dialog_answer);
2133
+ win32_dialog_answer = NULL;
2134
+ }
2135
+ return TRUE;
2136
+
2137
+ case WM_COMMAND:
2138
+ switch (LOWORD(wParam))
2139
+ {
2140
+ case IDOK:
2141
+ {
2142
+ int len = GetWindowTextLength(GetDlgItem(hwnd, IDQUED));
2143
+ if(len > 0)
2144
+ {
2145
+ win32_dialog_answer = (LPWSTR)GlobalAlloc(GPTR, (len + 1) * sizeof(WCHAR));
2146
+ GetDlgItemTextW(hwnd, IDQUED, win32_dialog_answer, len + 1);
2147
+ }
2148
+ }
2149
+ case IDCANCEL:
2150
+ EndDialog(hwnd, LOWORD(wParam));
2151
+ return TRUE;
2152
+ }
2153
+ break;
2154
+
2155
+ case WM_CLOSE:
2156
+ EndDialog(hwnd, 0);
2157
+ return FALSE;
2158
+ }
2159
+ return FALSE;
2160
+ }
2161
+
2162
+ VALUE
2163
+ shoes_dialog_alert(VALUE self, VALUE msg)
2164
+ {
2165
+ WCHAR *buffer;
2166
+ GLOBAL_APP(app);
2167
+ msg = shoes_native_to_s(msg);
2168
+ buffer = shoes_wchar(RSTRING_PTR(msg));
2169
+ MessageBoxW(APP_WINDOW(app), buffer, (LPCWSTR)dialog_title_says, MB_OK);
2170
+ if (buffer != NULL) SHOE_FREE(buffer);
2171
+ return Qnil;
2172
+ }
2173
+
2174
+ VALUE
2175
+ shoes_dialog_ask(int argc, VALUE *argv, VALUE self)
2176
+ {
2177
+ rb_arg_list args;
2178
+ VALUE answer = Qnil;
2179
+ rb_parse_args(argc, argv, "s|h", &args);
2180
+ GLOBAL_APP(app);
2181
+ win32_dialog_label = shoes_wchar(RSTRING_PTR(args.a[0]));
2182
+ int confirm = DialogBox(shoes_world->os.instance,
2183
+ MAKEINTRESOURCE(RTEST(ATTR(args.a[1], secret)) ? ASKSECRETDLG : ASKDLG),
2184
+ APP_WINDOW(app), shoes_ask_win32proc);
2185
+ if (confirm == IDOK)
2186
+ {
2187
+ if (win32_dialog_answer != NULL)
2188
+ {
2189
+ char *ans8 = shoes_utf8(win32_dialog_answer);
2190
+ answer = rb_str_new2(ans8);
2191
+ SHOE_FREE(ans8);
2192
+ GlobalFree((HANDLE)win32_dialog_answer);
2193
+ win32_dialog_answer = NULL;
2194
+ }
2195
+ }
2196
+ return answer;
2197
+ }
2198
+
2199
+ VALUE
2200
+ shoes_dialog_confirm(VALUE self, VALUE quiz)
2201
+ {
2202
+ WCHAR *buffer;
2203
+ VALUE answer = Qfalse;
2204
+ GLOBAL_APP(app);
2205
+ quiz = shoes_native_to_s(quiz);
2206
+ buffer = shoes_wchar(RSTRING_PTR(quiz));
2207
+ int confirm = MessageBoxW(APP_WINDOW(app), buffer, (LPCWSTR)dialog_title, MB_OKCANCEL);
2208
+ if (confirm == IDOK)
2209
+ answer = Qtrue;
2210
+ if (buffer != NULL) SHOE_FREE(buffer);
2211
+ return answer;
2212
+ }
2213
+
2214
+ VALUE
2215
+ shoes_dialog_color(VALUE self, VALUE title)
2216
+ {
2217
+ VALUE color = Qnil;
2218
+ GLOBAL_APP(app);
2219
+ CHOOSECOLOR cc;
2220
+ static COLORREF acrCustClr[16];
2221
+ static DWORD rgbCurrent;
2222
+
2223
+ // Initialize CHOOSECOLOR
2224
+ ZeroMemory(&cc, sizeof(cc));
2225
+ cc.lStructSize = sizeof(cc);
2226
+ cc.hwndOwner = APP_WINDOW(app);
2227
+ cc.lpCustColors = (LPDWORD) acrCustClr;
2228
+ cc.rgbResult = rgbCurrent;
2229
+ cc.Flags = CC_FULLOPEN | CC_RGBINIT;
2230
+
2231
+ if (ChooseColor(&cc)) {
2232
+ color = shoes_color_new(GetRValue(cc.rgbResult), GetGValue(cc.rgbResult), GetBValue(cc.rgbResult),
2233
+ SHOES_COLOR_OPAQUE);
2234
+ }
2235
+ return color;
2236
+ }
2237
+
2238
+ static char *
2239
+ shoes_fix_slashes(char *path)
2240
+ {
2241
+ char *p;
2242
+ for (p = path; *p != '\0'; p++)
2243
+ if (*p == '\\')
2244
+ *p = '/';
2245
+ return path;
2246
+ }
2247
+
2248
+ static void
2249
+ shoes_append_filter_token(char **filters, char *token, int token_len) {
2250
+ memcpy(*filters, token, token_len);
2251
+ (*filters) += token_len;
2252
+ *(*filters)++ = '\0';
2253
+ }
2254
+
2255
+ static VALUE
2256
+ shoes_dialog_chooser(VALUE self, char *title, DWORD flags, VALUE attr)
2257
+ {
2258
+ BOOL ok;
2259
+ VALUE path = Qnil;
2260
+ GLOBAL_APP(app);
2261
+ char _path[MAX_PATH+1];
2262
+ OPENFILENAME ofn;
2263
+ ZeroMemory(&ofn, sizeof(ofn));
2264
+ int filter_len = 64;
2265
+ int val_len, key_len = val_len = 0;
2266
+ char *filters;
2267
+
2268
+ if((filters = malloc(filter_len)) == NULL)
2269
+ return Qnil;
2270
+ *filters = '\0';
2271
+
2272
+ if(RTEST(shoes_hash_get(attr, rb_intern("types"))) &&
2273
+ TYPE(shoes_hash_get(attr, rb_intern("types"))) == T_HASH) {
2274
+ char *filters_buff = filters;
2275
+ int i;
2276
+ VALUE hsh = shoes_hash_get(attr, rb_intern("types"));
2277
+ VALUE keys = rb_funcall(hsh, s_keys, 0);
2278
+
2279
+ for(i = 0; i < RARRAY_LEN(keys); i++) {
2280
+ VALUE key = rb_ary_entry(keys, i);
2281
+ char *key_name = RSTRING_PTR(key);
2282
+ char *val = RSTRING_PTR(rb_hash_aref(hsh, key));
2283
+
2284
+ key_len = strlen(key_name);
2285
+ val_len = strlen(val);
2286
+ int pos = filters_buff - filters;
2287
+
2288
+ // ensure there's room for both tokens, thier NULL terminators
2289
+ // and the NULL terminator for the whole filter.
2290
+ if((pos + key_len + val_len + 3) >= filter_len) {
2291
+ filter_len *= 2;
2292
+ if((filters = realloc(filters, filter_len)) == NULL)
2293
+ return Qnil;
2294
+ filters_buff = filters + pos;
2295
+ }
2296
+
2297
+ // add the tokens on to the filter string
2298
+ shoes_append_filter_token(&filters_buff, key_name, key_len);
2299
+ shoes_append_filter_token(&filters_buff, val, val_len);
2300
+ }
2301
+
2302
+ // the whole thing needs a final terminator
2303
+ *filters_buff = '\0';
2304
+ } else
2305
+ // old shoes apps under windows may expect this
2306
+ memcpy(filters, "All\0*.*\0Text\0*.TXT\0\0", 20);
2307
+
2308
+ ofn.lpstrFilter = (LPCTSTR)filters;
2309
+ ofn.lStructSize = sizeof(ofn);
2310
+ ofn.hwndOwner = APP_WINDOW(app);
2311
+ ofn.hInstance = shoes_world->os.instance;
2312
+ ofn.lpstrFile = _path;
2313
+ ofn.lpstrTitle = title;
2314
+ ofn.nMaxFile = sizeof(_path);
2315
+ ofn.lpstrFile[0] = '\0';
2316
+ ofn.nFilterIndex = 1;
2317
+ ofn.lpstrFileTitle = NULL;
2318
+ ofn.nMaxFileTitle = 0;
2319
+ ofn.lpstrInitialDir = NULL;
2320
+ ofn.Flags = OFN_EXPLORER | flags;
2321
+ VALUE save = ID2SYM(rb_intern("save"));
2322
+
2323
+ if (RTEST(ATTR(attr, save)))
2324
+ ofn.lpstrFile = (LPSTR)RSTRING_PTR(rb_hash_aref(attr, save));
2325
+ if (flags & OFN_OVERWRITEPROMPT)
2326
+ ok = GetSaveFileName(&ofn);
2327
+ else
2328
+ ok = GetOpenFileName(&ofn);
2329
+
2330
+ free(filters);
2331
+
2332
+ if (ok)
2333
+ path = rb_str_new2(shoes_fix_slashes(ofn.lpstrFile));
2334
+
2335
+ return path;
2336
+ }
2337
+
2338
+ static VALUE
2339
+ shoes_dialog_chooser2(VALUE self, char *title, UINT flags, VALUE attr)
2340
+ {
2341
+ VALUE path = Qnil;
2342
+ BROWSEINFO bi = {0};
2343
+ bi.lpszTitle = title;
2344
+ bi.ulFlags = BIF_USENEWUI | flags;
2345
+ LPITEMIDLIST pidl = SHBrowseForFolder (&bi);
2346
+ if (pidl != 0)
2347
+ {
2348
+ char _path[MAX_PATH+1];
2349
+ if (SHGetPathFromIDList(pidl, _path))
2350
+ path = rb_str_new2(shoes_fix_slashes(_path));
2351
+
2352
+ IMalloc *imalloc = 0;
2353
+ if (SUCCEEDED(SHGetMalloc(&imalloc)))
2354
+ {
2355
+ IMalloc_Free(imalloc, pidl);
2356
+ IMalloc_Release(imalloc);
2357
+ }
2358
+ }
2359
+ return path;
2360
+ }
2361
+
2362
+ VALUE
2363
+ shoes_dialog_open(int argc, VALUE *argv, VALUE self)
2364
+ {
2365
+ rb_arg_list args;
2366
+ rb_parse_args(argc, argv, "|h", &args);
2367
+ return shoes_dialog_chooser(self, "Open file...", OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST, args.a[0]);
2368
+ }
2369
+
2370
+ VALUE
2371
+ shoes_dialog_save(int argc, VALUE *argv, VALUE self)
2372
+ {
2373
+ rb_arg_list args;
2374
+ rb_parse_args(argc, argv, "|h", &args);
2375
+ return shoes_dialog_chooser(self, "Save file...", OFN_OVERWRITEPROMPT, args.a[0]);
2376
+ }
2377
+
2378
+ VALUE
2379
+ shoes_dialog_open_folder(int argc, VALUE *argv, VALUE self)
2380
+ {
2381
+ rb_arg_list args;
2382
+ rb_parse_args(argc, argv, "|h", &args);
2383
+ return shoes_dialog_chooser2(self, "Open folder...", BIF_NONEWFOLDERBUTTON | BIF_RETURNONLYFSDIRS, args.a[0]);
2384
+ }
2385
+
2386
+ VALUE
2387
+ shoes_dialog_save_folder(int argc, VALUE *argv, VALUE self)
2388
+ {
2389
+ rb_arg_list args;
2390
+ rb_parse_args(argc, argv, "|h", &args);
2391
+ return shoes_dialog_chooser2(self, "Save folder...", BIF_RETURNONLYFSDIRS, args.a[0]);
2392
+ }