OsWindow.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /*
  2. Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
  3. Permission is hereby granted, free of charge, to any person
  4. obtaining a copy of this software and associated documentation
  5. files (the "Software"), to deal in the Software without
  6. restriction, including without limitation the rights to use,
  7. copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the
  9. Software is furnished to do so, subject to the following
  10. conditions:
  11. The above copyright notice and this permission notice shall be
  12. included in all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  14. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  15. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  16. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  17. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. OTHER DEALINGS IN THE SOFTWARE.
  21. */
  22. #include "OsWindow.h"
  23. #include "Assert.h"
  24. #include "Keyboard.h"
  25. #include "OS.h"
  26. #include "GLContext.h"
  27. #include "StringUtils.h"
  28. #include "OsEvents.h"
  29. namespace crown
  30. {
  31. //-----------------------------------------------------------------------------
  32. static Key x11_translate_key(int32_t x11_key)
  33. {
  34. if ((x11_key > 0x40 && x11_key < 0x5B) || (x11_key > 0x60 && x11_key < 0x7B) || (x11_key > 0x2F && x11_key < 0x3A))
  35. {
  36. return (Key)x11_key;
  37. }
  38. switch (x11_key)
  39. {
  40. case XK_BackSpace: return KC_BACKSPACE;
  41. case XK_Tab: return KC_TAB;
  42. case XK_space: return KC_SPACE;
  43. case XK_Escape: return KC_ESCAPE;
  44. case XK_Return: return KC_ENTER;
  45. case XK_F1: return KC_F1;
  46. case XK_F2: return KC_F2;
  47. case XK_F3: return KC_F3;
  48. case XK_F4: return KC_F4;
  49. case XK_F5: return KC_F5;
  50. case XK_F6: return KC_F6;
  51. case XK_F7: return KC_F7;
  52. case XK_F8: return KC_F8;
  53. case XK_F9: return KC_F9;
  54. case XK_F10: return KC_F10;
  55. case XK_F11: return KC_F11;
  56. case XK_F12: return KC_F12;
  57. case XK_Home: return KC_HOME;
  58. case XK_Left: return KC_LEFT;
  59. case XK_Up: return KC_UP;
  60. case XK_Right: return KC_RIGHT;
  61. case XK_Down: return KC_DOWN;
  62. case XK_Page_Up: return KC_PAGE_UP;
  63. case XK_Page_Down: return KC_PAGE_DOWN;
  64. case XK_Shift_L: return KC_LSHIFT;
  65. case XK_Shift_R: return KC_RSHIFT;
  66. case XK_Control_L: return KC_LCONTROL;
  67. case XK_Control_R: return KC_RCONTROL;
  68. case XK_Caps_Lock: return KC_CAPS_LOCK;
  69. case XK_Alt_L: return KC_LALT;
  70. case XK_Alt_R: return KC_RALT;
  71. case XK_Super_L: return KC_LSUPER;
  72. case XK_Super_R: return KC_RSUPER;
  73. case XK_KP_0: return KC_KP_0;
  74. case XK_KP_1: return KC_KP_1;
  75. case XK_KP_2: return KC_KP_2;
  76. case XK_KP_3: return KC_KP_3;
  77. case XK_KP_4: return KC_KP_4;
  78. case XK_KP_5: return KC_KP_5;
  79. case XK_KP_6: return KC_KP_6;
  80. case XK_KP_7: return KC_KP_7;
  81. case XK_KP_8: return KC_KP_8;
  82. case XK_KP_9: return KC_KP_9;
  83. default: return KC_NOKEY;
  84. }
  85. }
  86. //-----------------------------------------------------------------------------
  87. OsWindow::OsWindow(uint32_t width, uint32_t height, uint32_t parent) :
  88. m_x11_display(NULL),
  89. m_x11_window(None),
  90. m_x11_parent_window(None),
  91. m_x(0),
  92. m_y(0),
  93. m_width(width),
  94. m_height(height),
  95. m_resizable(true),
  96. m_x11_detectable_autorepeat(false),
  97. m_x11_hidden_cursor(None)
  98. {
  99. CE_ASSERT(width != 0 || height != 0, "Width and height must differ from zero");
  100. m_x11_display = XOpenDisplay(NULL);
  101. CE_ASSERT(m_x11_display != NULL, "Unable to open X11 display");
  102. int screen = DefaultScreen(m_x11_display);
  103. int depth = DefaultDepth(m_x11_display, screen);
  104. Visual* visual = DefaultVisual(m_x11_display, screen);
  105. if (parent != 0)
  106. {
  107. m_x11_parent_window = (Window) parent;
  108. }
  109. else
  110. {
  111. m_x11_parent_window = RootWindow(m_x11_display, screen);
  112. }
  113. // We want to track keyboard and mouse events
  114. XSetWindowAttributes win_attribs;
  115. win_attribs.background_pixmap = 0;
  116. win_attribs.border_pixel = 0;
  117. win_attribs.event_mask = FocusChangeMask | StructureNotifyMask | KeyPressMask |
  118. KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
  119. m_x11_window = XCreateWindow(
  120. m_x11_display,
  121. m_x11_parent_window,
  122. 0, 0,
  123. width, height,
  124. 0,
  125. depth,
  126. InputOutput,
  127. visual,
  128. CWBorderPixel | CWEventMask,
  129. &win_attribs
  130. );
  131. CE_ASSERT(m_x11_window != None, "Unable to create X window");
  132. // Check presence of detectable autorepeat
  133. Bool detectable;
  134. m_x11_detectable_autorepeat = (bool) XkbSetDetectableAutoRepeat(m_x11_display, true, &detectable);
  135. // Build hidden cursor
  136. Pixmap bm_no;
  137. XColor black, dummy;
  138. Colormap colormap;
  139. static char no_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  140. colormap = XDefaultColormap(m_x11_display, screen);
  141. XAllocNamedColor(m_x11_display, colormap, "black", &black, &dummy);
  142. bm_no = XCreateBitmapFromData(m_x11_display, m_x11_window, no_data, 8, 8);
  143. m_x11_hidden_cursor = XCreatePixmapCursor(m_x11_display, bm_no, bm_no, &black, &black, 0, 0);
  144. set_x11_display_and_window(m_x11_display, m_x11_window);
  145. }
  146. //-----------------------------------------------------------------------------
  147. OsWindow::~OsWindow()
  148. {
  149. if (m_x11_display)
  150. {
  151. if (m_x11_window != None)
  152. {
  153. XDestroyWindow(m_x11_display, m_x11_window);
  154. }
  155. XCloseDisplay(m_x11_display);
  156. }
  157. }
  158. //-----------------------------------------------------------------------------
  159. void OsWindow::show()
  160. {
  161. XMapRaised(m_x11_display, m_x11_window);
  162. }
  163. //-----------------------------------------------------------------------------
  164. void OsWindow::hide()
  165. {
  166. XUnmapWindow(m_x11_display, m_x11_window);
  167. }
  168. //-----------------------------------------------------------------------------
  169. void OsWindow::get_size(uint32_t& width, uint32_t& height)
  170. {
  171. width = m_width;
  172. height = m_height;
  173. }
  174. //-----------------------------------------------------------------------------
  175. void OsWindow::get_position(uint32_t& x, uint32_t& y)
  176. {
  177. x = m_x;
  178. y = m_y;
  179. }
  180. //-----------------------------------------------------------------------------
  181. void OsWindow::resize(uint32_t width, uint32_t height)
  182. {
  183. XResizeWindow(m_x11_display, m_x11_window, width, height);
  184. }
  185. //-----------------------------------------------------------------------------
  186. void OsWindow::move(uint32_t x, uint32_t y)
  187. {
  188. XMoveWindow(m_x11_display, m_x11_window, x, y);
  189. }
  190. //-----------------------------------------------------------------------------
  191. void OsWindow::minimize()
  192. {
  193. XIconifyWindow(m_x11_display, m_x11_window, DefaultScreen(m_x11_display));
  194. }
  195. //-----------------------------------------------------------------------------
  196. void OsWindow::restore()
  197. {
  198. XMapRaised(m_x11_display, m_x11_window);
  199. }
  200. //-----------------------------------------------------------------------------
  201. bool OsWindow::is_resizable() const
  202. {
  203. return m_resizable;
  204. }
  205. //-----------------------------------------------------------------------------
  206. void OsWindow::set_resizable(bool resizable)
  207. {
  208. XSizeHints hints;
  209. hints.flags = PMinSize | PMaxSize;
  210. hints.min_width = resizable ? 1 : m_width;
  211. hints.min_height = resizable ? 1 : m_height;
  212. hints.max_width = resizable ? 65535 : m_width;
  213. hints.max_height = resizable ? 65535 : m_height;
  214. XSetWMNormalHints(m_x11_display, m_x11_window, &hints);
  215. m_resizable = resizable;
  216. }
  217. //-----------------------------------------------------------------------------
  218. void OsWindow::show_cursor()
  219. {
  220. XDefineCursor(m_x11_display, m_x11_window, None);
  221. }
  222. //-----------------------------------------------------------------------------
  223. void OsWindow::hide_cursor()
  224. {
  225. XDefineCursor(m_x11_display, m_x11_window, m_x11_hidden_cursor);
  226. }
  227. //-----------------------------------------------------------------------------
  228. void OsWindow::get_cursor_xy(int32_t& x, int32_t& y)
  229. {
  230. Window unused;
  231. int32_t pointer_x, pointer_y, dummy;
  232. uint32_t dummy2;
  233. XQueryPointer(m_x11_display, m_x11_window, &unused, &unused, &dummy, &dummy, &pointer_x, &pointer_y, &dummy2);
  234. x = pointer_x;
  235. y = pointer_y;
  236. }
  237. //-----------------------------------------------------------------------------
  238. void OsWindow::set_cursor_xy(int32_t x, int32_t y)
  239. {
  240. XWarpPointer(m_x11_display, None, m_x11_window, 0, 0, m_width, m_height, x, y);
  241. XFlush(m_x11_display);
  242. }
  243. //-----------------------------------------------------------------------------
  244. char* OsWindow::title()
  245. {
  246. static char title[1024];
  247. char* tmp_title;
  248. XFetchName(m_x11_display, m_x11_window, &tmp_title);
  249. string::strncpy(title, tmp_title, 1024);
  250. XFree(tmp_title);
  251. return title;
  252. }
  253. //-----------------------------------------------------------------------------
  254. void OsWindow::set_title(const char* title)
  255. {
  256. XStoreName(m_x11_display, m_x11_window, title);
  257. }
  258. //-----------------------------------------------------------------------------
  259. void OsWindow::frame()
  260. {
  261. XEvent event;
  262. OsMouseEvent mouse_event;
  263. OsKeyboardEvent keyboard_event;
  264. while (XPending(m_x11_display))
  265. {
  266. XNextEvent(m_x11_display, &event);
  267. switch (event.type)
  268. {
  269. case ConfigureNotify:
  270. {
  271. m_x = event.xconfigure.x;
  272. m_y = event.xconfigure.y;
  273. m_width = event.xconfigure.width;
  274. m_height = event.xconfigure.height;
  275. break;
  276. }
  277. case ButtonPress:
  278. case ButtonRelease:
  279. {
  280. OsEventType oset_type = event.type == ButtonPress ? OSET_BUTTON_PRESS : OSET_BUTTON_RELEASE;
  281. mouse_event.x = event.xbutton.x;
  282. mouse_event.y = event.xbutton.y;
  283. switch (event.xbutton.button)
  284. {
  285. case Button1:
  286. {
  287. mouse_event.button = 0;
  288. os_event_buffer()->push_event(oset_type, &mouse_event, sizeof(OsMouseEvent));
  289. break;
  290. }
  291. case Button2:
  292. {
  293. mouse_event.button = 1;
  294. os_event_buffer()->push_event(oset_type, &mouse_event, sizeof(OsMouseEvent));
  295. break;
  296. }
  297. case Button3:
  298. {
  299. mouse_event.button = 2;
  300. os_event_buffer()->push_event(oset_type, &mouse_event, sizeof(OsMouseEvent));
  301. break;
  302. }
  303. }
  304. break;
  305. }
  306. // case MotionNotify:
  307. // {
  308. // push_event(OSET_MOTION_NOTIFY, data_button[0], data_button[1], data_button[2], data_button[3]);
  309. // break;
  310. // }
  311. case KeyPress:
  312. case KeyRelease:
  313. {
  314. char string[4] = {0, 0, 0, 0};
  315. KeySym key;
  316. XLookupString(&event.xkey, string, 4, &key, NULL);
  317. Key kc = x11_translate_key(key);
  318. // Check if any modifier key is pressed or released
  319. int32_t modifier_mask = 0;
  320. if (kc == KC_LSHIFT || kc == KC_RSHIFT)
  321. {
  322. (event.type == KeyPress) ? modifier_mask |= MK_SHIFT : modifier_mask &= ~MK_SHIFT;
  323. }
  324. else if (kc == KC_LCONTROL || kc == KC_RCONTROL)
  325. {
  326. (event.type == KeyPress) ? modifier_mask |= MK_CTRL : modifier_mask &= ~MK_CTRL;
  327. }
  328. else if (kc == KC_LALT || kc == KC_RALT)
  329. {
  330. (event.type == KeyPress) ? modifier_mask |= MK_ALT : modifier_mask &= ~MK_ALT;
  331. }
  332. OsEventType oset_type = event.type == KeyPress ? OSET_KEY_PRESS : OSET_KEY_RELEASE;
  333. keyboard_event.key = ((int32_t)kc);
  334. keyboard_event.modifier = modifier_mask;
  335. os_event_buffer()->push_event(oset_type, &keyboard_event, sizeof(OsKeyboardEvent));
  336. // // Text input part
  337. // if (event.type == KeyPress && len > 0)
  338. // {
  339. // //crownEvent.event_type = ET_TEXT;
  340. // //crownEvent.text.type = TET_TEXT_INPUT;
  341. // strncpy(keyboardEvent.text, string, 4);
  342. // if (mListener)
  343. // {
  344. // mListener->TextInput(keyboardEvent);
  345. // }
  346. // }
  347. break;
  348. }
  349. case KeymapNotify:
  350. {
  351. XRefreshKeyboardMapping(&event.xmapping);
  352. break;
  353. }
  354. default:
  355. {
  356. break;
  357. }
  358. }
  359. }
  360. }
  361. } // namespace crown