X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4bb6408c2631988fab9925014c6619358bf867de..973451afc6ebeb44869d4a75f6d7c197474da97c:/src/motif/cursor.cpp?ds=sidebyside diff --git a/src/motif/cursor.cpp b/src/motif/cursor.cpp index 4ecd0ad6d5..72425e23d8 100644 --- a/src/motif/cursor.cpp +++ b/src/motif/cursor.cpp @@ -14,174 +14,541 @@ #endif #include "wx/cursor.h" -#include "wx/icon.h" +#include "wx/app.h" +#include "wx/utils.h" +#include "wx/list.h" +#include "wx/window.h" +#if wxUSE_IMAGE +#include "wx/image.h" +#endif -#if !USE_SHARED_LIBRARIES -IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxBitmap) +#ifdef __VMS__ +#pragma message disable nosimpint +#endif +#include +#include +#ifdef __VMS__ +#pragma message enable nosimpint #endif -wxCursorRefData::wxCursorRefData() +#include "wx/motif/private.h" + +// Cursor for one display, so we can choose the correct one for +// the current display. +class wxXCursor { - m_width = 32; m_height = 32; +public: + WXDisplay* m_display; + WXCursor m_cursor; +}; -/* TODO - m_hCursor = 0 ; -*/ -} +WX_DECLARE_LIST(wxXCursor, wxXCursorList); +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxXCursorList); -wxCursorRefData::~wxCursorRefData() +class WXDLLEXPORT wxCursorRefData: public wxObjectRefData { - // TODO: destroy cursor + friend class WXDLLEXPORT wxCursor; +public: + wxCursorRefData(); + ~wxCursorRefData(); + + wxXCursorList m_cursors; // wxXCursor objects, one per display + wxStockCursor m_cursorId; // wxWindows standard cursor id +}; + +#define M_CURSORDATA ((wxCursorRefData *)m_refData) +#define M_CURSORHANDLERDATA ((wxCursorRefData *)bitmap->m_refData) + +IMPLEMENT_DYNAMIC_CLASS(wxCursor, wxObject) + +wxCursorRefData::wxCursorRefData() +{ + m_cursorId = wxCURSOR_NONE; } -// Cursors -wxCursor::wxCursor() +wxCursorRefData::~wxCursorRefData() { + wxXCursorList::Node* node = m_cursors.GetFirst(); + while (node) + { + wxXCursor* c = node->GetData(); + XFreeCursor((Display*) c->m_display, (Cursor) c->m_cursor); + delete c; + node = node->GetNext(); + } } -wxCursor::wxCursor(const char WXUNUSED(bits)[], int WXUNUSED(width), int WXUNUSED(height), - int WXUNUSED(hotSpotX), int WXUNUSED(hotSpotY), const char WXUNUSED(maskBits)[]) +wxCursor::wxCursor() { } -wxCursor::wxCursor(const wxString& cursor_file, long flags, int hotSpotX, int hotSpotY) +#if wxUSE_IMAGE +wxCursor::wxCursor(const wxImage & image) { - m_refData = new wxIconRefData; + unsigned char * rgbBits = image.GetData(); + int w = image.GetWidth() ; + int h = image.GetHeight(); + bool bHasMask = image.HasMask(); + int imagebitcount = (w*h)/8; - // TODO: create cursor from a file -} + unsigned char * bits = new unsigned char [imagebitcount]; + unsigned char * maskBits = new unsigned char [imagebitcount]; -// Cursors by stock number -wxCursor::wxCursor(int cursor_type) -{ - m_refData = new wxIconRefData; - -/* TODO - switch (cursor_type) - { - case wxCURSOR_WAIT: - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_WAIT); - break; - case wxCURSOR_IBEAM: - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_IBEAM); - break; - case wxCURSOR_CROSS: - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_CROSS); - break; - case wxCURSOR_SIZENWSE: - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_SIZENWSE); - break; - case wxCURSOR_SIZENESW: - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_SIZENESW); - break; - case wxCURSOR_SIZEWE: - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_SIZEWE); - break; - case wxCURSOR_SIZENS: - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_SIZENS); - break; - case wxCURSOR_CHAR: + int i, j, i8; unsigned char c, cMask; + for (i=0; im_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_ARROW); - break; + bits[i] = 0; + i8 = i * 8; + + cMask = 1; + for (j=0; j<8; j++) + { + // possible overflow if we do the summation first ? + c = rgbBits[(i8+j)*3]/3 + rgbBits[(i8+j)*3+1]/3 + rgbBits[(i8+j)*3+2]/3; + //if average value is > mid grey + if (c>127) + bits[i] = bits[i] | cMask; + cMask = cMask * 2; + } } - case wxCURSOR_HAND: + + if (bHasMask) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_HAND"); - break; + unsigned char + r = image.GetMaskRed(), + g = image.GetMaskGreen(), + b = image.GetMaskBlue(); + + for (i=0; im_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_BULLSEYE"); - break; + for (i=0; i= w) + hotSpotX = 0; + if (hotSpotY < 0 || hotSpotY >= h) + hotSpotY = 0; + + m_refData = new wxCursorRefData; + + Display *dpy = (Display*) wxGetDisplay(); + int screen_num = DefaultScreen (dpy); + + Pixmap pixmap = XCreatePixmapFromBitmapData (dpy, + RootWindow (dpy, DefaultScreen(dpy)), + (char*) bits, w, h, + 1 , 0 , 1); + + Pixmap mask_pixmap = None; + if (maskBits != NULL) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_PENCIL"); - break; + mask_pixmap = XCreatePixmapFromBitmapData (dpy, + RootWindow (dpy, DefaultScreen(dpy)), + (char*) maskBits, w, h, + 1 , 0 , 1); } - case wxCURSOR_MAGNIFIER: + + XColor foreground_color; + XColor background_color; + foreground_color.pixel = BlackPixel(dpy, screen_num); + background_color.pixel = WhitePixel(dpy, screen_num); + Colormap cmap = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dpy); + XQueryColor(dpy, cmap, &foreground_color); + XQueryColor(dpy, cmap, &background_color); + + Cursor cursor = XCreatePixmapCursor (dpy, + pixmap, + mask_pixmap, + &foreground_color, + &background_color, + hotSpotX , + hotSpotY); + + XFreePixmap( dpy, pixmap ); + if (mask_pixmap != None) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_MAGNIFIER"); - break; + XFreePixmap( dpy, mask_pixmap ); } - case wxCURSOR_NO_ENTRY: + + if (cursor) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_NO_ENTRY"); - break; + wxXCursor *c = new wxXCursor; + + c->m_cursor = (WXCursor) cursor; + c->m_display = (WXDisplay*) dpy; + M_CURSORDATA->m_cursors.Append(c); } - case wxCURSOR_LEFT_BUTTON: +} +#endif + +wxCursor::wxCursor(const char bits[], int width, int height, + int hotSpotX, int hotSpotY, const char maskBits[]) +{ + m_refData = new wxCursorRefData; + + Display *dpy = (Display*) wxGetDisplay(); + int screen_num = DefaultScreen (dpy); + + Pixmap pixmap = XCreatePixmapFromBitmapData (dpy, + RootWindow (dpy, DefaultScreen(dpy)), + (char*) bits, width, height, + 1 , 0 , 1); + + Pixmap mask_pixmap = None; + if (maskBits != NULL) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_ARROW); - break; + mask_pixmap = XCreatePixmapFromBitmapData (dpy, + RootWindow (dpy, DefaultScreen(dpy)), + (char*) maskBits, width, height, + 1 , 0 , 1); } - case wxCURSOR_RIGHT_BUTTON: + + XColor foreground_color; + XColor background_color; + foreground_color.pixel = BlackPixel(dpy, screen_num); + background_color.pixel = WhitePixel(dpy, screen_num); + Colormap cmap = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dpy); + XQueryColor(dpy, cmap, &foreground_color); + XQueryColor(dpy, cmap, &background_color); + + Cursor cursor = XCreatePixmapCursor (dpy, + pixmap, + mask_pixmap, + &foreground_color, + &background_color, + hotSpotX , + hotSpotY); + + XFreePixmap( dpy, pixmap ); + if (mask_pixmap != None) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_ARROW); - break; + XFreePixmap( dpy, mask_pixmap ); } - case wxCURSOR_MIDDLE_BUTTON: + + if (cursor) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_ARROW); - break; + wxXCursor *c = new wxXCursor; + + c->m_cursor = (WXCursor) cursor; + c->m_display = (WXDisplay*) dpy; + M_CURSORDATA->m_cursors.Append(c); } - case wxCURSOR_SIZING: +} + +wxCursor::wxCursor(const wxString& name, long flags, int hotSpotX, int hotSpotY) +{ + // Must be an XBM file + if (flags != wxBITMAP_TYPE_XBM) + return; + + m_refData = new wxCursorRefData; + + int hotX = -1, hotY = -1; + unsigned int w, h; + Pixmap pixmap; + + Display *dpy = (Display*) wxGetDisplay(); + int screen_num = DefaultScreen (dpy); + + int value = XReadBitmapFile (dpy, RootWindow (dpy, DefaultScreen (dpy)), + wxConstCast(name.c_str(), char), + &w, &h, &pixmap, &hotX, &hotY); + + if ((value == BitmapFileInvalid) || + (value == BitmapOpenFailed) || + (value == BitmapNoMemory)) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_SIZING"); - break; } - case wxCURSOR_WATCH: + else { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_WATCH"); - break; + XColor foreground_color; + XColor background_color; + foreground_color.pixel = BlackPixel(dpy, screen_num); + background_color.pixel = WhitePixel(dpy, screen_num); + Colormap cmap = (Colormap) wxTheApp->GetMainColormap((WXDisplay*) dpy); + XQueryColor(dpy, cmap, &foreground_color); + XQueryColor(dpy, cmap, &background_color); + + // TODO: how do we determine whether hotX, hotY were read correctly? + if (hotX < 0 || hotY < 0) + { + hotX = hotSpotX; + hotY = hotSpotY; + } + if (hotX < 0 || hotY < 0) + { + hotX = 0; + hotY = 0; + } + + Pixmap mask_pixmap = None; + Cursor cursor = XCreatePixmapCursor (dpy, + pixmap, + mask_pixmap, + &foreground_color, + &background_color, + hotX, + hotY); + + XFreePixmap( dpy, pixmap ); + if (cursor) + { + wxXCursor *c = new wxXCursor; + + c->m_cursor = (WXCursor) cursor; + c->m_display = (WXDisplay*) dpy; + M_CURSORDATA->m_cursors.Append(c); + } } - case wxCURSOR_SPRAYCAN: + +} + +// Cursors by stock number +wxCursor::wxCursor(wxStockCursor id) +{ + m_refData = new wxCursorRefData; + M_CURSORDATA->m_cursorId = id; +} + +wxCursor::~wxCursor() +{ +} + +bool wxCursor::Ok() const +{ + return m_refData != NULL; +} + +// Motif-specific: create/get a cursor for the current display +WXCursor wxCursor::GetXCursor(WXDisplay* display) +{ + if (!M_CURSORDATA) + return (WXCursor) 0; + wxXCursorList::Node* node = M_CURSORDATA->m_cursors.GetFirst(); + while (node) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_ROLLER"); - break; + wxXCursor* c = node->GetData(); + if (c->m_display == display) + return c->m_cursor; + node = node->GetNext(); } - case wxCURSOR_PAINT_BRUSH: + + // No cursor for this display, so let's see if we're an id-type cursor. + + if (M_CURSORDATA->m_cursorId != wxCURSOR_NONE) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_PBRUSH"); - break; + WXCursor cursor = MakeCursor(display, M_CURSORDATA->m_cursorId); + if (cursor) + { + wxXCursor* c = new wxXCursor; + c->m_cursor = cursor; + c->m_display = display; + M_CURSORDATA->m_cursors.Append(c); + return cursor; + } + else + return (WXCursor) 0; } - case wxCURSOR_POINT_LEFT: + + // Not an id-type cursor, so we don't know how to create it. + return (WXCursor) 0; +} + +// Make a cursor from standard id +WXCursor wxCursor::MakeCursor(WXDisplay* display, wxStockCursor id) +{ + Display* dpy = (Display*) display; + Cursor cursor = (Cursor) 0; + int x_cur = -1; + + switch (id) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_PLEFT"); - break; - } - case wxCURSOR_POINT_RIGHT: + case wxCURSOR_WAIT: x_cur = XC_watch; break; + case wxCURSOR_CROSS: x_cur = XC_crosshair; break; + case wxCURSOR_CHAR: return (WXCursor)cursor; break; + case wxCURSOR_HAND: x_cur = XC_hand1; break; + case wxCURSOR_BULLSEYE: x_cur = XC_target; break; + case wxCURSOR_PENCIL: x_cur = XC_pencil; break; + case wxCURSOR_MAGNIFIER: x_cur = XC_sizing; break; + case wxCURSOR_IBEAM: x_cur = XC_xterm; break; + case wxCURSOR_NO_ENTRY: x_cur = XC_pirate; break; + case wxCURSOR_LEFT_BUTTON: x_cur = XC_leftbutton; break; + case wxCURSOR_RIGHT_BUTTON: x_cur = XC_rightbutton; break; + case wxCURSOR_MIDDLE_BUTTON: x_cur = XC_middlebutton; break; + case wxCURSOR_QUESTION_ARROW: x_cur = XC_question_arrow; break; + case wxCURSOR_SIZING: x_cur = XC_sizing; break; + case wxCURSOR_WATCH: x_cur = XC_watch; break; + case wxCURSOR_SPRAYCAN: x_cur = XC_spraycan; break; + case wxCURSOR_PAINT_BRUSH: x_cur = XC_spraycan; break; + case wxCURSOR_SIZENWSE: + case wxCURSOR_SIZENESW: x_cur = XC_crosshair; break; + case wxCURSOR_SIZEWE: x_cur = XC_sb_h_double_arrow; break; + case wxCURSOR_SIZENS: x_cur = XC_sb_v_double_arrow; break; + case wxCURSOR_POINT_LEFT: x_cur = XC_sb_left_arrow; break; + case wxCURSOR_POINT_RIGHT: x_cur = XC_sb_right_arrow; break; + // (JD Huggins) added more stock cursors for X + // X-only cursors BEGIN + case wxCURSOR_CROSS_REVERSE: x_cur = XC_cross_reverse; break; + case wxCURSOR_DOUBLE_ARROW: x_cur = XC_double_arrow; break; + case wxCURSOR_BASED_ARROW_UP: x_cur = XC_based_arrow_up; break; + case wxCURSOR_BASED_ARROW_DOWN: x_cur = XC_based_arrow_down; break; + case wxCURSOR_BLANK: { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_PRIGHT"); - break; + GC gc; + XGCValues gcv; + Pixmap empty_pixmap; + XColor blank_color; + + empty_pixmap = + XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)), + 16, 16, 1); + gcv.function = GXxor; + gc = XCreateGC (dpy, + empty_pixmap, + GCFunction, + &gcv); + XCopyArea (dpy, + empty_pixmap, + empty_pixmap, + gc, + 0, 0, + 16, 16, + 0, 0); + XFreeGC (dpy, gc); + cursor = XCreatePixmapCursor (dpy, + empty_pixmap, + empty_pixmap, + &blank_color, + &blank_color, + 8, 8); + + break; } - case wxCURSOR_QUESTION_ARROW: + case wxCURSOR_ARROW: + default: x_cur = XC_top_left_arrow; break; + } + + if( x_cur == -1 ) + return (WXCursor)cursor; + + cursor = XCreateFontCursor (dpy, x_cur); + return (WXCursor) cursor; +} + +// Global cursor setting +void wxSetCursor(const wxCursor& WXUNUSED(cursor)) +{ + // Nothing to do for Motif (no global cursor) +} + + +// ---------------------------------------------------------------------------- +// busy cursor stuff +// ---------------------------------------------------------------------------- + +static int wxBusyCursorCount = 0; + +// Helper function +static void +wxXSetBusyCursor (wxWindow * win, wxCursor * cursor) +{ + Display *display = (Display*) win->GetXDisplay(); + + Window xwin = (Window) win->GetXWindow(); + if (!xwin) + return; + + XSetWindowAttributes attrs; + + if (cursor) { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_QARROW"); - break; + attrs.cursor = (Cursor) cursor->GetXCursor(display); } - case wxCURSOR_BLANK: + else { - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(wxGetInstance(), "wxCURSOR_BLANK"); - break; + // Restore old cursor + if (win->GetCursor().Ok()) + attrs.cursor = (Cursor) win->GetCursor().GetXCursor(display); + else + attrs.cursor = None; } - default: - case wxCURSOR_ARROW: - M_CURSORDATA->m_hCursor = (WXHCURSOR) LoadCursor(NULL, IDC_ARROW); - break; - } -*/ + if (xwin) + XChangeWindowAttributes (display, xwin, CWCursor, &attrs); + + XFlush (display); + for(wxWindowList::Node *node = win->GetChildren().GetFirst (); node; + node = node->GetNext()) + { + wxWindow *child = node->GetData (); + wxXSetBusyCursor (child, cursor); + } } -wxCursor::~wxCursor() +// Set the cursor to the busy cursor for all windows +void wxBeginBusyCursor(wxCursor *cursor) { + wxBusyCursorCount++; + if (wxBusyCursorCount == 1) + { + for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node; + node = node->GetNext()) + { + wxWindow *win = node->GetData (); + wxXSetBusyCursor (win, cursor); + } + } } -// Global cursor setting -void wxSetCursor(const wxCursor& cursor) +// Restore cursor to normal +void wxEndBusyCursor() { - // TODO (optional on platforms with no global cursor) -} + if (wxBusyCursorCount == 0) + return; + wxBusyCursorCount--; + if (wxBusyCursorCount == 0) + { + for(wxWindowList::Node *node = wxTopLevelWindows.GetFirst (); node; + node = node->GetNext()) + { + wxWindow *win = node->GetData (); + wxXSetBusyCursor (win, NULL); + } + } +} +// TRUE if we're between the above two calls +bool wxIsBusy() +{ + return (wxBusyCursorCount > 0); +}