1 /* Copyright (C) 2018 Wildfire Games.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #include "precompiled.h"
24 #include "lib/sysdep/cursor.h"
25
26 #include "lib/sysdep/gfx.h"
27 #include "lib/sysdep/os/win/win.h"
28 #include "lib/sysdep/os/win/wutil.h"
29
cursor_from_HICON(HICON hIcon)30 static sys_cursor cursor_from_HICON(HICON hIcon)
31 {
32 return (sys_cursor)(uintptr_t)hIcon;
33 }
34
cursor_from_HCURSOR(HCURSOR hCursor)35 static sys_cursor cursor_from_HCURSOR(HCURSOR hCursor)
36 {
37 return (sys_cursor)(uintptr_t)hCursor;
38 }
39
HICON_from_cursor(sys_cursor cursor)40 static HICON HICON_from_cursor(sys_cursor cursor)
41 {
42 return (HICON)(uintptr_t)cursor;
43 }
44
HCURSOR_from_cursor(sys_cursor cursor)45 static HCURSOR HCURSOR_from_cursor(sys_cursor cursor)
46 {
47 return (HCURSOR)(uintptr_t)cursor;
48 }
49
50
sys_cursor_create_common(int w,int h,void * bgra_img,void * mask_img,int hx,int hy,sys_cursor * cursor)51 static Status sys_cursor_create_common(int w, int h, void* bgra_img, void* mask_img, int hx, int hy, sys_cursor* cursor)
52 {
53 *cursor = 0;
54
55 // MSDN says selecting this HBITMAP into a DC is slower since we use
56 // CreateBitmap; bpp/format must be checked against those of the DC.
57 // this is the simplest way and we don't care about slight performance
58 // differences because this is typically only called once.
59 HBITMAP hbmColor = CreateBitmap(w, h, 1, 32, bgra_img);
60
61 // CreateIconIndirect doesn't access this; we just need to pass
62 // an empty bitmap.
63 HBITMAP hbmMask = CreateBitmap(w, h, 1, 1, mask_img);
64
65 // create the cursor (really an icon; they differ only in
66 // fIcon and the hotspot definitions).
67 ICONINFO ii;
68 ii.fIcon = FALSE; // cursor
69 ii.xHotspot = (DWORD)hx;
70 ii.yHotspot = (DWORD)hy;
71 ii.hbmMask = hbmMask;
72 ii.hbmColor = hbmColor;
73 HICON hIcon = CreateIconIndirect(&ii);
74
75 // CreateIconIndirect makes copies, so we no longer need these.
76 DeleteObject(hbmMask);
77 DeleteObject(hbmColor);
78
79 if(!wutil_IsValidHandle(hIcon))
80 WARN_RETURN(ERR::FAIL);
81
82 *cursor = cursor_from_HICON(hIcon);
83 return INFO::OK;
84 }
85
sys_cursor_create(int w,int h,void * bgra_img,int hx,int hy,sys_cursor * cursor)86 Status sys_cursor_create(int w, int h, void* bgra_img, int hx, int hy, sys_cursor* cursor)
87 {
88 // alpha-blended cursors do not work on a 16-bit display
89 // (they get drawn as a black square), so refuse to load the
90 // cursor in that case
91 int bpp = 0;
92 RETURN_STATUS_IF_ERR(gfx::GetVideoMode(NULL, NULL, &bpp, NULL));
93 if (bpp <= 16)
94 return ERR::FAIL;
95
96 return sys_cursor_create_common(w, h, bgra_img, NULL, hx, hy, cursor);
97 }
98
sys_cursor_create_empty(sys_cursor * cursor)99 Status sys_cursor_create_empty(sys_cursor* cursor)
100 {
101 // the mask gets ignored on 32-bit displays, but is used on 16-bit displays;
102 // setting it to 0xFF makes the cursor invisible (though I'm not quite
103 // sure why it's that way round)
104 u8 bgra_img[] = {0, 0, 0, 0};
105 u8 mask_img[] = {0xFF};
106 return sys_cursor_create_common(1, 1, bgra_img, mask_img, 0, 0, cursor);
107 }
108
109
sys_cursor_set(sys_cursor cursor)110 Status sys_cursor_set(sys_cursor cursor)
111 {
112 // restore default cursor.
113 if(!cursor)
114 cursor = cursor_from_HCURSOR(LoadCursor(0, IDC_ARROW));
115
116 (void)SetCursor(HCURSOR_from_cursor(cursor));
117 // return value (previous cursor) is useless.
118
119 return INFO::OK;
120 }
121
122
sys_cursor_free(sys_cursor cursor)123 Status sys_cursor_free(sys_cursor cursor)
124 {
125 // bail now to prevent potential confusion below; there's nothing to do.
126 if(!cursor)
127 return INFO::OK;
128
129 // if the cursor being freed is active, restore the default arrow
130 // (just for safety).
131 if(cursor_from_HCURSOR(GetCursor()) == cursor)
132 WARN_IF_ERR(sys_cursor_set(0));
133
134 if(!DestroyIcon(HICON_from_cursor(cursor)))
135 WARN_RETURN(StatusFromWin());
136 return INFO::OK;
137 }
138
sys_cursor_reset()139 Status sys_cursor_reset()
140 {
141 return INFO::OK;
142 }
143