OpenCPN Partial API docs
ocpCursor.cpp
1 /******************************************************************************
2  *
3  * Project: OpenCPN
4  *
5  ***************************************************************************
6  * Copyright (C) 2013 by David S. Register *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the *
20  * Free Software Foundation, Inc., *
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22  ***************************************************************************
23  */
24 
25 #include "ocpCursor.h"
26 
27 #ifdef __WXX11__
28 
29 #include <wx/x11/private.h>
30 
31 class ocpCursorRefData : public wxObjectRefData {
32 public:
33  ocpCursorRefData();
34  ~ocpCursorRefData();
35 
36  WXCursor m_cursor;
37  WXDisplay* m_display;
38 };
39 
40 ocpCursorRefData::ocpCursorRefData() {
41  m_cursor = NULL;
42  m_display = NULL;
43 }
44 
45 ocpCursorRefData::~ocpCursorRefData() {
46  if (m_cursor) XFreeCursor((Display*)m_display, (Cursor)m_cursor);
47 }
48 
49 //-----------------------------------------------------------------------------
50 
51 #define M_CURSORDATA ((ocpCursorRefData*)m_refData)
52 
53 ocpCursor::ocpCursor(const wxString& cursorName, long type, int hotSpotX,
54  int hotSpotY)
55  : wxCursor(wxCURSOR_CROSS) {
56  wxImage cImage;
57 
58  if (!cImage.CanRead(cursorName)) ::wxInitAllImageHandlers();
59 
60  cImage.LoadFile(cursorName);
61 
62  int width = cImage.GetWidth();
63  int height = cImage.GetHeight();
64 
65  // m_refData = new wxCursorRefData();
66 
67  // Get some X parameters
68  int xscreen = DefaultScreen((Display*)wxGlobalDisplay());
69  Window xroot = RootWindow((Display*)wxGlobalDisplay(), xscreen);
70  Visual* xvisual = DefaultVisual((Display*)wxGlobalDisplay(), xscreen);
71 
72  M_CURSORDATA->m_display = wxGlobalDisplay();
73  wxASSERT_MSG(M_CURSORDATA->m_display, wxT("No display"));
74 
75  // Make a pixmap
76  Pixmap cpixmap =
77  XCreatePixmap((Display*)wxGlobalDisplay(), xroot, width, height, 1);
78 
79  // Make an Ximage
80  XImage* data_image = XCreateImage((Display*)wxGlobalDisplay(), xvisual, 1,
81  ZPixmap, 0, 0, width, height, 32, 0);
82  data_image->data =
83  (char*)malloc(data_image->bytes_per_line * data_image->height);
84 
85  int index = 0;
86  int pixel = 0;
87  unsigned char* data = cImage.GetData();
88 
89  // Create mask
90 
91  Pixmap cmask;
92  unsigned char mr, mg, mb;
93 
94  if (cImage.HasMask()) {
95  XImage* mask_image = XCreateImage((Display*)wxGlobalDisplay(), xvisual, 1,
96  ZPixmap, 0, 0, width, height, 32, 0);
97  mask_image->data =
98  (char*)malloc(mask_image->bytes_per_line * mask_image->height);
99 
100  cImage.GetOrFindMaskColour(&mr, &mg, &mb);
101 
102  int rit = (mr << 16) + (mg << 8) + mb;
103  for (int y = 0; y < height; y++) {
104  for (int x = 0; x < width; x++) {
105  int ri = (int)data[index++];
106  ri += data[index++] << 8;
107  ri += data[index++] << 16;
108 
109  /*
110  int ri = *(int *)(&data[index]);
111  ri &= 0x00ffffff;
112  index++;
113  index++;
114  index++;
115  */
116  pixel = 1;
117  if (ri == rit) // if data is mask value, mask pixel gets 0
118  pixel = 0;
119 
120  XPutPixel(mask_image, x, y, pixel);
121  }
122  }
123 
124  cmask = XCreatePixmap((Display*)wxGlobalDisplay(), xroot, width, height, 1);
125 
126  GC gc = XCreateGC((Display*)wxGlobalDisplay(), cmask, 0, NULL);
127  XPutImage((Display*)wxGlobalDisplay(), cmask, gc, mask_image, 0, 0, 0, 0,
128  width, height);
129 
130  XDestroyImage(mask_image);
131  XFreeGC((Display*)wxGlobalDisplay(), gc);
132  }
133 
134  // Render the wxImage cImage onto the Ximage
135  // Simple black/white cursors only, please
136 
137  index = 0;
138 
139  for (int y = 0; y < height; y++) {
140  for (int x = 0; x < width; x++) {
141  int ri = (int)data[index++];
142  ri += data[index++] << 8;
143  ri += data[index++] << 16;
144 
145  /*
146  int ri = *(int *)(&data[index]);
147  ri &= 0x00ffffff;
148  index++;
149  index++;
150  index++;
151  */
152 
153  pixel = 0;
154  if (ri) pixel = 1;
155 
156  XPutPixel(data_image, x, y, pixel);
157  }
158  }
159 
160  // Put the Ximage into the pixmap
161 
162  GC gc = XCreateGC((Display*)wxGlobalDisplay(), cpixmap, 0, NULL);
163  XPutImage((Display*)wxGlobalDisplay(), cpixmap, gc, data_image, 0, 0, 0, 0,
164  width, height);
165 
166  // Free the Ximage stuff
167  XDestroyImage(data_image);
168  XFreeGC((Display*)wxGlobalDisplay(), gc);
169 
170  // Make a X cursor from the pixmap
171 
172  XColor fg, bg;
173  fg.red = fg.blue = fg.green = 0xffff;
174  bg.red = bg.blue = bg.green = 0;
175 
176  M_CURSORDATA->m_cursor =
177  (WXCursor)XCreatePixmapCursor((Display*)wxGlobalDisplay(), cpixmap, cmask,
178  &fg, &bg, hotSpotX, hotSpotY);
179 }
180 
181 ocpCursor::ocpCursor(const char** xpm_data, long type, int hotSpotX,
182  int hotSpotY)
183  : wxCursor(wxCURSOR_CROSS) {
184  wxImage cImage(xpm_data);
185 
186  int width = cImage.GetWidth();
187  int height = cImage.GetHeight();
188 
189  // m_refData = new wxCursorRefData();
190 
191  // Get some X parameters
192  int xscreen = DefaultScreen((Display*)wxGlobalDisplay());
193  Window xroot = RootWindow((Display*)wxGlobalDisplay(), xscreen);
194  Visual* xvisual = DefaultVisual((Display*)wxGlobalDisplay(), xscreen);
195 
196  M_CURSORDATA->m_display = wxGlobalDisplay();
197  wxASSERT_MSG(M_CURSORDATA->m_display, wxT("No display"));
198 
199  // Make a pixmap
200  Pixmap cpixmap =
201  XCreatePixmap((Display*)wxGlobalDisplay(), xroot, width, height, 1);
202 
203  // Make an Ximage
204  XImage* data_image = XCreateImage((Display*)wxGlobalDisplay(), xvisual, 1,
205  ZPixmap, 0, 0, width, height, 32, 0);
206  data_image->data =
207  (char*)malloc(data_image->bytes_per_line * data_image->height);
208 
209  int index = 0;
210  int pixel = 0;
211  unsigned char* data = cImage.GetData();
212 
213  // Create mask
214 
215  Pixmap cmask;
216  unsigned char mr, mg, mb;
217 
218  if (cImage.HasMask()) {
219  XImage* mask_image = XCreateImage((Display*)wxGlobalDisplay(), xvisual, 1,
220  ZPixmap, 0, 0, width, height, 32, 0);
221  mask_image->data =
222  (char*)malloc(mask_image->bytes_per_line * mask_image->height);
223 
224  cImage.GetOrFindMaskColour(&mr, &mg, &mb);
225 
226  int rit = (mr << 16) + (mg << 8) + mb;
227  for (int y = 0; y < height; y++) {
228  for (int x = 0; x < width; x++) {
229  int ri = (int)data[index++];
230  ri += data[index++] << 8;
231  ri += data[index++] << 16;
232 
233  /*
234  int ri = *(int *)(&data[index]);
235  ri &= 0x00ffffff;
236  index++;
237  index++;
238  index++;
239  */
240  pixel = 1;
241  if (ri == rit) // if data is mask value, mask pixel gets 0
242  pixel = 0;
243 
244  XPutPixel(mask_image, x, y, pixel);
245  }
246  }
247 
248  cmask = XCreatePixmap((Display*)wxGlobalDisplay(), xroot, width, height, 1);
249 
250  GC gc = XCreateGC((Display*)wxGlobalDisplay(), cmask, 0, NULL);
251  XPutImage((Display*)wxGlobalDisplay(), cmask, gc, mask_image, 0, 0, 0, 0,
252  width, height);
253 
254  XDestroyImage(mask_image);
255  XFreeGC((Display*)wxGlobalDisplay(), gc);
256  }
257 
258  // Render the wxImage cImage onto the Ximage
259  // Simple black/white cursors only, please
260 
261  index = 0;
262 
263  for (int y = 0; y < height; y++) {
264  for (int x = 0; x < width; x++) {
265  int ri = (int)data[index++];
266  ri += data[index++] << 8;
267  ri += data[index++] << 16;
268 
269  /*
270  int ri = *(int *)(&data[index]);
271  ri &= 0x00ffffff;
272  index++;
273  index++;
274  index++;
275  */
276 
277  pixel = 0;
278  if (ri) pixel = 1;
279 
280  XPutPixel(data_image, x, y, pixel);
281  }
282  }
283 
284  // Put the Ximage into the pixmap
285 
286  GC gc = XCreateGC((Display*)wxGlobalDisplay(), cpixmap, 0, NULL);
287  XPutImage((Display*)wxGlobalDisplay(), cpixmap, gc, data_image, 0, 0, 0, 0,
288  width, height);
289 
290  // Free the Ximage stuff
291  XDestroyImage(data_image);
292  XFreeGC((Display*)wxGlobalDisplay(), gc);
293 
294  // Make a X cursor from the pixmap
295 
296  XColor fg, bg;
297  fg.red = fg.blue = fg.green = 0xffff;
298  bg.red = bg.blue = bg.green = 0;
299 
300  M_CURSORDATA->m_cursor =
301  (WXCursor)XCreatePixmapCursor((Display*)wxGlobalDisplay(), cpixmap, cmask,
302  &fg, &bg, hotSpotX, hotSpotY);
303 }
304 
305 #endif // __WXX11__
306 
307 // We derive a class from wxCursor to create ocpCursor
308 // Specifically to fix a bug in wxImage-wxBitmap conversions
309 
310 #ifdef __WXMSW__
311 
312 ocpCursor::ocpCursor(const wxString& cursorName, long type, int hotSpotX,
313  int hotSpotY)
314  : wxCursor(wxCURSOR_ARROW)
315 
316 {
317  wxImage cImage;
318 
319  if (!cImage.CanRead(cursorName)) ::wxInitAllImageHandlers();
320 
321  cImage.LoadFile(cursorName);
322 
323  // wxMSW Bug???
324  // On Windows XP, conversion from wxImage to wxBitmap fails at the
325  // ::CreateDIBitmap() call unless a "compatible" dc is provided. Why??
326  // As a workaround, just make a simple wxDC for temporary use
327 
328  wxBitmap tbmp(cImage.GetWidth(), cImage.GetHeight(), -1);
329  wxMemoryDC dwxdc;
330  dwxdc.SelectObject(tbmp);
331 
332  // HCURSOR hcursor = wxBitmapToHCURSOR ( wxBitmap ( cImage, ( wxDC & )
333  // dwxdc ),
334  // hotSpotX, hotSpotY );
335  HCURSOR hcursor = NULL;
336 
337  if (!hcursor) {
338  wxLogWarning(_T( "Failed to create ocpCursor." ));
339  return;
340  }
341 
342  // Replace the HANDLE created in the base class constructor
343  // Probably leaks....
344  GetGDIImageData()->m_handle = hcursor;
345 }
346 
347 ocpCursor::ocpCursor(const char** xpm_data, long type, int hotSpotX,
348  int hotSpotY)
349  : wxCursor(wxCURSOR_ARROW)
350 
351 {
352  wxImage cImage(xpm_data);
353 
354  // wxMSW Bug???
355  // On Windows XP, conversion from wxImage to wxBitmap fails at the
356  // ::CreateDIBitmap() call unless a "compatible" dc is provided. Why??
357  // As a workaround, just make a simple wxDC for temporary use
358 
359  wxBitmap tbmp(cImage.GetWidth(), cImage.GetHeight(), -1);
360  wxMemoryDC dwxdc;
361  dwxdc.SelectObject(tbmp);
362 
363  // HCURSOR hcursor = wxBitmapToHCURSOR ( wxBitmap ( cImage, ( wxDC & )
364  // dwxdc ),
365  // hotSpotX, hotSpotY );
366 
367  HCURSOR hcursor = NULL;
368 
369  if (!hcursor) {
370  wxLogWarning(_T( "Failed to create ocpCursor." ));
371  return;
372  }
373 
374  // Replace the HANDLE created in the base class constructor
375  // Probably leaks....
376  GetGDIImageData()->m_handle = hcursor;
377 }
378 #endif // __MSW
379 
380 #ifdef __WXOSX__ // begin rms
381 ocpCursor::ocpCursor(const wxString& cursorName, long type, int hotSpotX,
382  int hotSpotY)
383  : wxCursor(wxCURSOR_ARROW)
384 
385 {
386  wxImage cImage;
387 
388  if (!cImage.CanRead(cursorName)) ::wxInitAllImageHandlers();
389 
390  cImage.LoadFile(cursorName);
391 
392  // wxMSW Bug???
393  // On Windows XP, conversion from wxImage to wxBitmap fails at the
394  // ::CreateDIBitmap() call unless a "compatible" dc is provided. Why??
395  // As a workaround, just make a simple wxDC for temporary use
396 
397  wxBitmap tbmp(cImage.GetWidth(), cImage.GetHeight(), -1);
398 }
399 
400 //----------------------------------------------------------------------------------------------
401 // A new constructor taking a static char ** of XPM data and assign as a
402 // cursor
403 //----------------------------------------------------------------------------------------------
404 
405 ocpCursor::ocpCursor(const char** xpm_data, long type, int hotSpotX,
406  int hotSpotY)
407  : wxCursor(wxCURSOR_ARROW)
408 
409 {
410  wxImage cImage(xpm_data);
411 
412  wxBitmap tbmp(cImage.GetWidth(), cImage.GetHeight(), -1);
413 }
414 
415 #endif // __WXOSX__ end rms