# HG changeset patch # User Jordan Miner # Date 1248551923 18000 # Node ID d55b5b99841232c9995543d3a877f98d84b053ec # Parent 9a50d6d9681561d82f9debc6fbf434f074395362 Implement built-in mouse cursors with X. diff -r 9a50d6d96815 -r d55b5b998412 dynamin/c/xlib.d --- a/dynamin/c/xlib.d Sat Jul 25 14:47:45 2009 -0500 +++ b/dynamin/c/xlib.d Sat Jul 25 14:58:43 2009 -0500 @@ -245,6 +245,13 @@ uint bg, uint depth); +Pixmap XCreateBitmapFromData( + Display* display, + Drawable d, + /*const*/ char* data, + uint width, + uint height); + int XFreePixmap(Display* display, Pixmap pixmap); //}}} @@ -258,12 +265,95 @@ uint x, uint y); +Cursor XCreateFontCursor(Display* display, uint shape); + int XDefineCursor(Display* display, Window w, Cursor cursor); int XUndefineCursor(Display* display, Window w); int XFreeCursor(Display* display, Cursor cursor); +// cursorfont.h +enum { + XC_num_glyphs = 154, + XC_X_cursor = 0, + XC_arrow = 2, + XC_based_arrow_down = 4, + XC_based_arrow_up = 6, + XC_boat = 8, + XC_bogosity = 10, + XC_bottom_left_corner = 12, + XC_bottom_right_corner = 14, + XC_bottom_side = 16, + XC_bottom_tee = 18, + XC_box_spiral = 20, + XC_center_ptr = 22, + XC_circle = 24, + XC_clock = 26, + XC_coffee_mug = 28, + XC_cross = 30, + XC_cross_reverse = 32, + XC_crosshair = 34, + XC_diamond_cross = 36, + XC_dot = 38, + XC_dotbox = 40, + XC_double_arrow = 42, + XC_draft_large = 44, + XC_draft_small = 46, + XC_draped_box = 48, + XC_exchange = 50, + XC_fleur = 52, + XC_gobbler = 54, + XC_gumby = 56, + XC_hand1 = 58, + XC_hand2 = 60, + XC_heart = 62, + XC_icon = 64, + XC_iron_cross = 66, + XC_left_ptr = 68, + XC_left_side = 70, + XC_left_tee = 72, + XC_leftbutton = 74, + XC_ll_angle = 76, + XC_lr_angle = 78, + XC_man = 80, + XC_middlebutton = 82, + XC_mouse = 84, + XC_pencil = 86, + XC_pirate = 88, + XC_plus = 90, + XC_question_arrow = 92, + XC_right_ptr = 94, + XC_right_side = 96, + XC_right_tee = 98, + XC_rightbutton = 100, + XC_rtl_logo = 102, + XC_sailboat = 104, + XC_sb_down_arrow = 106, + XC_sb_h_double_arrow = 108, + XC_sb_left_arrow = 110, + XC_sb_right_arrow = 112, + XC_sb_up_arrow = 114, + XC_sb_v_double_arrow = 116, + XC_shuttle = 118, + XC_sizing = 120, + XC_spider = 122, + XC_spraycan = 124, + XC_star = 126, + XC_target = 128, + XC_tcross = 130, + XC_top_left_arrow = 132, + XC_top_left_corner = 134, + XC_top_right_corner = 136, + XC_top_side = 138, + XC_top_tee = 140, + XC_trek = 142, + XC_ul_angle = 144, + XC_umbrella = 146, + XC_ur_angle = 148, + XC_watch = 150, + XC_xterm = 152, +} //}}} //{{{ keyboard functions diff -r 9a50d6d96815 -r d55b5b998412 dynamin/gui/control.d --- a/dynamin/gui/control.d Sat Jul 25 14:47:45 2009 -0500 +++ b/dynamin/gui/control.d Sat Jul 25 14:58:43 2009 -0500 @@ -74,7 +74,7 @@ bool _elasticX, _elasticY; public: protected void dispatchMouseEntered(EventArgs e) { - Cursor.setCurrent(this, _cursor); + setCurrentCursor(_cursor); mouseEntered.callHandlers(e); mouseEntered.callMainHandler(e); } @@ -503,15 +503,24 @@ repaint(); } + void setCurrentCursor(Cursor cur) { + if(parent) + parent.setCurrentCursor(cur); + } + /** + * Gets or sets the mouse cursor that will be shown when the mouse + * is over this control. + */ Cursor cursor() { return _cursor; } + /// ditto void cursor(Cursor cur) { if(_cursor is cur) return; _cursor = cur; if(getHotControl() is this) - Cursor.setCurrent(this, _cursor); + setCurrentCursor(_cursor); } /** diff -r 9a50d6d96815 -r d55b5b998412 dynamin/gui/cursor.d --- a/dynamin/gui/cursor.d Sat Jul 25 14:47:45 2009 -0500 +++ b/dynamin/gui/cursor.d Sat Jul 25 14:58:43 2009 -0500 @@ -29,20 +29,38 @@ import dynamin.gui_backend; /// -class Cursor { +final class Cursor { private: mixin CursorBackend; +static: + Cursor _none = null; + Cursor _arrow = null; + Cursor _waitArrow = null; + Cursor _wait = null; + Cursor _text = null; + Cursor _hand = null; + Cursor _move = null; + Cursor _resizeHoriz = null; + Cursor _resizeVert = null; + Cursor _resizeBackslash = null; + Cursor _resizeSlash = null; + Cursor _drag = null; + Cursor _invalidDrag = null; + Cursor _reversedArrow = null; + Cursor _crosshair = null; + // handles caching for backends + Cursor maybeLoad(Cursor function() loadCursor, ref Cursor cache) { + if(cache is null) + cache = loadCursor(); + return cache; + } public: -static: - void setCurrent(Control c, Cursor cur) { - backend_SetCurrent(c, cur); - } /** * Gets a blank cursor used for an activity, such as typing, with which * the cursor may interfere. */ Cursor None() { - return backend_None; + return maybeLoad(&backend_None, _none); } /** * Gets the cursor used normally. @@ -52,7 +70,7 @@ * $(IMAGE ../web/example_arrow_cursor.png) */ Cursor Arrow() { - return backend_Arrow; + return maybeLoad(&backend_Arrow, _arrow); } /** * Gets the cursor used when the computer is accomplishing some @@ -63,7 +81,7 @@ * $(IMAGE ../web/example_wait_arrow_cursor.png) */ Cursor WaitArrow() { - return backend_WaitArrow; + return maybeLoad(&backend_WaitArrow, _waitArrow); } /** * Gets the cursor used when the computer is accomplishing some @@ -74,7 +92,7 @@ * $(IMAGE ../web/example_wait_cursor.png) */ Cursor Wait() { - return backend_Wait; + return maybeLoad(&backend_Wait, _wait); } /** * Gets the cursor used when the mouse is over selectable text. @@ -87,7 +105,7 @@ * $(IMAGE ../web/example_text_cursor.png) */ Cursor Text() { - return backend_Text; + return maybeLoad(&backend_Text, _text); } /** * Gets the cursor used when the mouse is over a link. @@ -97,7 +115,7 @@ * $(IMAGE ../web/example_hand_cursor.png) */ Cursor Hand() { - return backend_Hand; + return maybeLoad(&backend_Hand, _hand); } /** * Gets the cursor used when moving something. @@ -107,7 +125,7 @@ * $(IMAGE ../web/example_move_cursor.png) */ Cursor Move() { - return backend_Move; + return maybeLoad(&backend_Move, _move); } /** * Gets the cursor used when resizing the left or right @@ -118,7 +136,7 @@ * $(IMAGE ../web/example_resize_horiz_cursor.png) */ Cursor ResizeHoriz() { - return backend_ResizeHoriz; + return maybeLoad(&backend_ResizeHoriz, _resizeHoriz); } /** * Gets the cursor used when resizing the top or bottom @@ -129,7 +147,7 @@ * $(IMAGE ../web/example_resize_vert_cursor.png) */ Cursor ResizeVert() { - return backend_ResizeVert; + return maybeLoad(&backend_ResizeVert, _resizeVert); } /** * Gets the cursor used when resizing the top-left or bottom-right @@ -140,7 +158,7 @@ * $(IMAGE ../web/example_resize_backslash_cursor.png) */ Cursor ResizeBackslash() { - return backend_ResizeBackslash; + return maybeLoad(&backend_ResizeBackslash, _resizeBackslash); } /** * Gets the cursor used when resizing the bottom-left or top-right @@ -151,7 +169,7 @@ * $(IMAGE ../web/example_resize_slash_cursor.png) */ Cursor ResizeSlash() { - return backend_ResizeSlash; + return maybeLoad(&backend_ResizeSlash, _resizeSlash); } /** * Gets the cursor used when the mouse is over something that @@ -162,7 +180,7 @@ * $(IMAGE ../web/example_drag_cursor.png) */ Cursor Drag() { - return backend_Drag; + return maybeLoad(&backend_Drag, _drag); } /** * Gets the cursor used when the mouse is over something that @@ -173,7 +191,7 @@ * $(IMAGE ../web/example_invalid_drag_cursor.png) */ Cursor InvalidDrag() { - return backend_InvalidDrag; + return maybeLoad(&backend_InvalidDrag, _invalidDrag); } /** * Gets the cursor used when the mouse is over a gutter that @@ -184,7 +202,7 @@ * $(IMAGE ../web/example_reversed_arrow_cursor.png) */ Cursor ReversedArrow() { - return backend_ReversedArrow; + return maybeLoad(&backend_ReversedArrow, _reversedArrow); } /** * Gets the cursor that is sometimes used for selecting. @@ -194,7 +212,7 @@ * $(IMAGE ../web/example_crosshair_cursor.png) */ Cursor Crosshair() { - return backend_Crosshair; + return maybeLoad(&backend_Crosshair, _crosshair); } } diff -r 9a50d6d96815 -r d55b5b998412 dynamin/gui/window.d --- a/dynamin/gui/window.d Sat Jul 25 14:47:45 2009 -0500 +++ b/dynamin/gui/window.d Sat Jul 25 14:58:43 2009 -0500 @@ -30,6 +30,7 @@ import dynamin.all_painting; import dynamin.all_gui; import dynamin.gui.control; +import dynamin.gui.cursor; import dynamin.gui_backend; import dynamin.gui.container; import dynamin.gui.events; @@ -296,6 +297,12 @@ backend_borderStyle = border; } + override void setCurrentCursor(Cursor cur) { + if(!handleCreated) + return; + backend_setCurrentCursor(cur); + } + alias Control.repaint repaint; void repaint(Rect rect) { if(!handleCreated) diff -r 9a50d6d96815 -r d55b5b998412 dynamin/gui/windows_cursor.d --- a/dynamin/gui/windows_cursor.d Sat Jul 25 14:47:45 2009 -0500 +++ b/dynamin/gui/windows_cursor.d Sat Jul 25 14:58:43 2009 -0500 @@ -35,106 +35,75 @@ template CursorBackend() { HCURSOR _handle; - bool isBuiltin = false; this(HCURSOR h) { _handle = h; - isBuiltin = true; - } -static: - void backend_SetCurrent(Control c, Cursor cur) { - assert(cur.isBuiltin); // TODO: allow custom cursors - SetCursor(cur._handle); } - Cursor none = null; - Cursor arrow = null; - Cursor waitArrow = null; - Cursor wait = null; - Cursor text = null; - Cursor hand = null; - Cursor move = null; - Cursor resizeHoriz = null; - Cursor resizeVert = null; - Cursor resizeBackslash = null; - Cursor resizeSlash = null; - Cursor drag = null; // from resource - Cursor invalidDrag = null; - Cursor reversedArrow = null; // from resource - Cursor crosshair = null; - - Cursor backend_maybeLoad(Cursor* cache, int curRes) { - if(*cache is null) { - HCURSOR hcur = LoadImage(null, MAKEINTRESOURCE(curRes), - IMAGE_CURSOR, 0, 0, LR_SHARED | LR_DEFAULTSIZE); - if(hcur is null) - Stdout.format("LoadImage() failed loading cursor {}", curRes).newline; - else - *cache = new Cursor(hcur); - } - return *cache; + public HCURSOR handle() { return _handle; } +static: + Cursor backend_getCursor(int curRes) { + HCURSOR hcur = LoadImage(null, MAKEINTRESOURCE(curRes), + IMAGE_CURSOR, 0, 0, LR_SHARED | LR_DEFAULTSIZE); + if(hcur is null) + Stdout.format("LoadImage() failed loading cursor {}", curRes).newline; + return new Cursor(hcur); } - Cursor backend_maybeLoad(Cursor* cache, wchar[] name) { - if(*cache is null) { - HCURSOR hcur = LoadImage(GetModuleHandle(null), name.ptr, - IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); - if(hcur is null) - Stdout.format("LoadImage() failed loading cursor {}", name).newline; - else - *cache = new Cursor(hcur); - } - return *cache; + Cursor backend_getCursor(wchar[] name) { + HCURSOR hcur = LoadImage(GetModuleHandle(null), name.ptr, + IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); + if(hcur is null) + Stdout.format("LoadImage() failed loading cursor {}", name).newline; + return new Cursor(hcur); } Cursor backend_None() { - if(none is null) - none = new Cursor(cast(HCURSOR)null); - return none; + return new Cursor(cast(HCURSOR)null); } Cursor backend_Arrow() { - return backend_maybeLoad(&arrow, OCR_NORMAL); + return backend_getCursor(OCR_NORMAL); } Cursor backend_WaitArrow() { - return backend_maybeLoad(&waitArrow, OCR_APPSTARTING); + return backend_getCursor(OCR_APPSTARTING); } Cursor backend_Wait() { - return backend_maybeLoad(&wait, OCR_WAIT); + return backend_getCursor(OCR_WAIT); } Cursor backend_Text() { - return backend_maybeLoad(&text, OCR_IBEAM); + return backend_getCursor(OCR_IBEAM); } Cursor backend_Hand() { - return backend_maybeLoad(&hand, OCR_HAND); // Windows 98 & newer + return backend_getCursor(OCR_HAND); // Windows 98 & newer } Cursor backend_Move() { - return backend_maybeLoad(&move, OCR_SIZEALL); + return backend_getCursor(OCR_SIZEALL); } Cursor backend_ResizeHoriz() { - return backend_maybeLoad(&resizeHoriz, OCR_SIZEWE); + return backend_getCursor(OCR_SIZEWE); } Cursor backend_ResizeVert() { - return backend_maybeLoad(&resizeVert, OCR_SIZENS); + return backend_getCursor(OCR_SIZENS); } Cursor backend_ResizeBackslash() { - return backend_maybeLoad(&resizeBackslash, OCR_SIZENWSE); + return backend_getCursor(OCR_SIZENWSE); } Cursor backend_ResizeSlash() { - return backend_maybeLoad(&resizeSlash, OCR_SIZENESW); + return backend_getCursor(OCR_SIZENESW); } Cursor backend_Drag() { if(checkWindowsVersion(WindowsVersion.WindowsVista)) - return backend_maybeLoad(&drag, "AeroDragCur"); + return backend_getCursor("AeroDragCur"); else - return backend_maybeLoad(&drag, "DragCur"); + return backend_getCursor("DragCur"); } Cursor backend_InvalidDrag() { - return backend_maybeLoad(&invalidDrag, OCR_NO); + return backend_getCursor(OCR_NO); } Cursor backend_ReversedArrow() { if(checkWindowsVersion(WindowsVersion.WindowsVista)) - return backend_maybeLoad(&drag, "AeroReversedArrowCur"); + return backend_getCursor("AeroReversedArrowCur"); else - return backend_maybeLoad(&drag, "ReversedArrowCur"); + return backend_getCursor("ReversedArrowCur"); } Cursor backend_Crosshair() { - return backend_maybeLoad(&crosshair, OCR_CROSS); + return backend_getCursor(OCR_CROSS); } } diff -r 9a50d6d96815 -r d55b5b998412 dynamin/gui/windows_window.d --- a/dynamin/gui/windows_window.d Sat Jul 25 14:47:45 2009 -0500 +++ b/dynamin/gui/windows_window.d Sat Jul 25 14:58:43 2009 -0500 @@ -197,6 +197,9 @@ void backend_borderStyle(WindowBorderStyle border) { backend_updateWindowStyles(); } + void backend_setCurrentCursor(Cursor cur) { + SetCursor(cur.handle); + } void backend_repaint(Rect rect) { RECT wrect; wrect.left = cast(int)(rect.x-_borderSize.left); diff -r 9a50d6d96815 -r d55b5b998412 dynamin/gui/x_cursor.d --- a/dynamin/gui/x_cursor.d Sat Jul 25 14:47:45 2009 -0500 +++ b/dynamin/gui/x_cursor.d Sat Jul 25 14:58:43 2009 -0500 @@ -7,69 +7,63 @@ public import dynamin.gui.control; template CursorBackend() { -static: - void backend_SetCurrent(Control c, Cursor cur) { + XCursor _handle; + this(XCursor h) { + _handle = h; } - Cursor none = null; - Cursor arrow = null; - Cursor waitArrow = null; - Cursor wait = null; - Cursor text = null; - Cursor hand = null; - Cursor move = null; - Cursor resizeHoriz = null; - Cursor resizeVert = null; - Cursor resizeBackslash = null; - Cursor resizeSlash = null; - Cursor drag = null; // from resource - Cursor invalidDrag = null; - Cursor reversedArrow = null; // from resource - Cursor crosshair = null; - + public XCursor handle() { return _handle; } +static: + Cursor getCursor(uint shape) { + return new Cursor(XCreateFontCursor(display, shape)); + } Cursor backend_None() { - return null; + auto p = XCreateBitmapFromData(display, msgWin, + "\0\0\0\0\0\0\0\0", 1, 1); + XColor color; + return new Cursor(XCreatePixmapCursor(display, p, p, &color, &color, + 1, 1)); } Cursor backend_Arrow() { - return null; + return getCursor(XC_left_ptr); } Cursor backend_WaitArrow() { - return null; + return getCursor(XC_watch); } Cursor backend_Wait() { - return null; + return getCursor(XC_watch); } Cursor backend_Text() { - return null; + return getCursor(XC_xterm); } Cursor backend_Hand() { - return null; + return getCursor(XC_hand2); } Cursor backend_Move() { - return null; + return getCursor(XC_fleur); } Cursor backend_ResizeHoriz() { - return null; + return getCursor(XC_left_side); } Cursor backend_ResizeVert() { - return null; + return getCursor(XC_top_side); } Cursor backend_ResizeBackslash() { - return null; + return getCursor(XC_top_left_corner); } Cursor backend_ResizeSlash() { - return null; + return getCursor(XC_top_right_corner); } Cursor backend_Drag() { - return null; + return getCursor(XC_fleur); // not the best } Cursor backend_InvalidDrag() { - return null; + return getCursor(XC_fleur); // bad, but what Linux does } Cursor backend_ReversedArrow() { - return null; + return getCursor(XC_right_ptr); } Cursor backend_Crosshair() { - return null; + return getCursor(XC_crosshair); } } diff -r 9a50d6d96815 -r d55b5b998412 dynamin/gui/x_window.d --- a/dynamin/gui/x_window.d Sat Jul 25 14:47:45 2009 -0500 +++ b/dynamin/gui/x_window.d Sat Jul 25 14:58:43 2009 -0500 @@ -538,6 +538,10 @@ backend_update_MOTIF_WM_HINTS(); backend_nativeToBorderSize(); } + void backend_setCurrentCursor(Cursor cur) { + XDefineCursor(display, _handle, cur.handle); + } + static _InvalidRect[] invalidRects; void backend_repaint(Rect rect) { invalidRects.length = invalidRects.length+1;