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,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
+ }