1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "bitmap.h"
17 #define XtParent XTPARENT
22 #include "wx/palette.h"
23 #include "wx/bitmap.h"
26 #include "wx/control.h"
27 #include "wx/dcmemory.h"
32 #pragma message disable nosimpint
36 #pragma message enable nosimpint
39 #include "wx/motif/private.h"
47 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxGDIObject
)
48 IMPLEMENT_DYNAMIC_CLASS(wxMask
, wxObject
)
50 wxBitmapRefData::wxBitmapRefData()
60 m_pixmap
= (WXPixmap
) 0;
61 m_display
= (WXDisplay
*) 0;
63 m_freePixmap
= TRUE
; //TODO: necessary?
64 m_freeColors
= (unsigned long*) 0;
65 m_freeColorsCount
= 0;
67 // These 5 variables are for wxControl
68 m_insensPixmap
= (WXPixmap
) 0;
69 m_labelPixmap
= (WXPixmap
) 0;
70 m_armPixmap
= (WXPixmap
) 0;
71 m_image
= (WXImage
*) 0;
72 m_insensImage
= (WXImage
*) 0;
75 wxBitmapRefData::~wxBitmapRefData()
78 XmDestroyPixmap (DefaultScreenOfDisplay ((Display
*) m_display
), (Pixmap
) m_labelPixmap
);
81 XmDestroyPixmap (DefaultScreenOfDisplay ((Display
*) m_display
), (Pixmap
) m_armPixmap
);
84 XmDestroyPixmap (DefaultScreenOfDisplay ((Display
*) m_display
), (Pixmap
) m_insensPixmap
);
88 XmUninstallImage ((XImage
*) m_image
);
89 XtFree ((char *) (XImage
*) m_image
);
94 XmUninstallImage ((XImage
*) m_insensImage
);
95 delete[] ((XImage
*) m_insensImage
)->data
;
96 XtFree ((char *) (XImage
*) m_insensImage
);
98 if (m_pixmap
&& m_freePixmap
)
99 XFreePixmap ((Display
*) m_display
, (Pixmap
) m_pixmap
);
103 int screen
= DefaultScreen((Display
*) m_display
);
104 Colormap cmp
= DefaultColormap((Display
*) m_display
,screen
);
106 for(llp
= 0;llp
< m_freeColorsCount
;llp
++)
107 XFreeColors((Display
*) m_display
, cmp
, &m_freeColors
[llp
], 1, 0L);
116 wxList
wxBitmap::sm_handlers
;
118 #define M_BMPDATA ((wxBitmapRefData *)m_refData)
125 wxBitmap::~wxBitmap()
129 wxBitmap::wxBitmap(const char bits
[], int width
, int height
, int depth
)
131 m_refData
= new wxBitmapRefData
;
133 (void) Create((void*) bits
, wxBITMAP_TYPE_XBM_DATA
, width
, height
, depth
);
136 wxBitmap::wxBitmap(int w
, int h
, int d
)
138 (void)Create(w
, h
, d
);
141 wxBitmap::wxBitmap(void *data
, long type
, int width
, int height
, int depth
)
143 (void) Create(data
, type
, width
, height
, depth
);
146 wxBitmap::wxBitmap(const wxString
& filename
, int type
)
148 LoadFile(filename
, (int)type
);
151 // Create from XPM data
152 static wxControl
* sg_Control
= NULL
;
153 wxBitmap::wxBitmap(char **data
, wxControl
* control
)
155 // Pass the control to the Create function using a global
156 sg_Control
= control
;
158 (void) Create((void *)data
, wxBITMAP_TYPE_XPM_DATA
, 0, 0, 0);
160 sg_Control
= (wxControl
*) NULL
;
163 bool wxBitmap::CreateFromXpm(const char **bits
)
165 wxCHECK_MSG( bits
, FALSE
, _T("NULL pointer in wxBitmap::CreateFromXpm") );
167 return Create(bits
, wxBITMAP_TYPE_XPM_DATA
, 0, 0, 0);
170 bool wxBitmap::CopyFromIcon(const wxIcon
& icon
)
176 bool wxBitmap::Create(int w
, int h
, int d
)
180 m_refData
= new wxBitmapRefData
;
183 d
= wxDisplayDepth();
185 M_BITMAPDATA
->m_width
= w
;
186 M_BITMAPDATA
->m_height
= h
;
187 M_BITMAPDATA
->m_depth
= d
;
188 M_BITMAPDATA
->m_freePixmap
= TRUE
;
190 Display
*dpy
= (Display
*) wxGetDisplay();
192 M_BITMAPDATA
->m_display
= dpy
; /* MATTHEW: [4] Remember the display */
194 M_BITMAPDATA
->m_pixmap
= (WXPixmap
) XCreatePixmap (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
197 M_BITMAPDATA
->m_ok
= (M_BITMAPDATA
->m_pixmap
!= (WXPixmap
) 0) ;
198 return M_BITMAPDATA
->m_ok
;
201 bool wxBitmap::LoadFile(const wxString
& filename
, long type
)
205 m_refData
= new wxBitmapRefData
;
207 wxBitmapHandler
*handler
= FindHandler(type
);
209 if ( handler
== NULL
) {
211 if (!image
.LoadFile( filename
, type
)) return FALSE
;
214 *this = image
.ConvertToBitmap();
220 return handler
->LoadFile(this, filename
, type
, -1, -1);
223 bool wxBitmap::Create(void *data
, long type
, int width
, int height
, int depth
)
227 m_refData
= new wxBitmapRefData
;
229 wxBitmapHandler
*handler
= FindHandler(type
);
231 if ( handler
== NULL
) {
232 wxLogWarning("no data bitmap handler for type %ld defined.", type
);
237 return handler
->Create(this, data
, type
, width
, height
, depth
);
240 bool wxBitmap::SaveFile(const wxString
& filename
, int type
, const wxPalette
*palette
)
242 wxBitmapHandler
*handler
= FindHandler(type
);
244 if ( handler
== NULL
) { // try wxImage
245 wxImage
image( *this );
246 if (image
.Ok()) return image
.SaveFile( filename
, type
);
250 return handler
->SaveFile(this, filename
, type
, palette
);
253 void wxBitmap::SetWidth(int w
)
256 m_refData
= new wxBitmapRefData
;
258 M_BITMAPDATA
->m_width
= w
;
261 void wxBitmap::SetHeight(int h
)
264 m_refData
= new wxBitmapRefData
;
266 M_BITMAPDATA
->m_height
= h
;
269 void wxBitmap::SetDepth(int d
)
272 m_refData
= new wxBitmapRefData
;
274 M_BITMAPDATA
->m_depth
= d
;
277 void wxBitmap::SetQuality(int q
)
280 m_refData
= new wxBitmapRefData
;
282 M_BITMAPDATA
->m_quality
= q
;
285 void wxBitmap::SetOk(bool isOk
)
288 m_refData
= new wxBitmapRefData
;
290 M_BITMAPDATA
->m_ok
= isOk
;
293 void wxBitmap::SetPalette(const wxPalette
& palette
)
296 m_refData
= new wxBitmapRefData
;
298 M_BITMAPDATA
->m_bitmapPalette
= palette
;
301 void wxBitmap::SetMask(wxMask
*mask
)
304 m_refData
= new wxBitmapRefData
;
306 M_BITMAPDATA
->m_bitmapMask
= mask
;
309 wxBitmap
wxBitmap::GetSubBitmap( const wxRect
& rect
) const
312 (rect
.x
>= 0) && (rect
.y
>= 0) &&
313 (rect
.x
+rect
.width
<= M_BMPDATA
->m_width
) && (rect
.y
+rect
.height
<= M_BMPDATA
->m_height
),
314 wxNullBitmap
, wxT("invalid bitmap or bitmap region") );
316 wxBitmap
ret( rect
.width
, rect
.height
, 0 );
317 wxASSERT_MSG( ret
.Ok(), wxT("GetSubBitmap error") );
319 // The remaining still TODO
323 void wxBitmap::AddHandler(wxBitmapHandler
*handler
)
325 sm_handlers
.Append(handler
);
328 void wxBitmap::InsertHandler(wxBitmapHandler
*handler
)
330 sm_handlers
.Insert(handler
);
333 bool wxBitmap::RemoveHandler(const wxString
& name
)
335 wxBitmapHandler
*handler
= FindHandler(name
);
338 sm_handlers
.DeleteObject(handler
);
345 wxBitmapHandler
*wxBitmap::FindHandler(const wxString
& name
)
347 wxNode
*node
= sm_handlers
.First();
350 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
351 if ( handler
->GetName() == name
)
358 wxBitmapHandler
*wxBitmap::FindHandler(const wxString
& extension
, long bitmapType
)
360 wxNode
*node
= sm_handlers
.First();
363 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
364 if ( handler
->GetExtension() == extension
&&
365 (bitmapType
== -1 || handler
->GetType() == bitmapType
) )
372 wxBitmapHandler
*wxBitmap::FindHandler(long bitmapType
)
374 wxNode
*node
= sm_handlers
.First();
377 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
378 if (handler
->GetType() == bitmapType
)
391 m_pixmap
= (WXPixmap
) 0;
394 // Construct a mask from a bitmap and a colour indicating
395 // the transparent area
396 wxMask::wxMask(const wxBitmap
& bitmap
, const wxColour
& colour
)
398 m_pixmap
= (WXPixmap
) 0;
400 Create(bitmap
, colour
);
403 // Construct a mask from a bitmap and a palette index indicating
404 // the transparent area
405 wxMask::wxMask(const wxBitmap
& bitmap
, int paletteIndex
)
407 m_pixmap
= (WXPixmap
) 0;
409 Create(bitmap
, paletteIndex
);
412 // Construct a mask from a mono bitmap (copies the bitmap).
413 wxMask::wxMask(const wxBitmap
& bitmap
)
415 m_pixmap
= (WXPixmap
) 0;
422 // TODO: this may be the wrong display
424 XFreePixmap ((Display
*) wxGetDisplay(), (Pixmap
) m_pixmap
);
427 // Create a mask from a mono bitmap (copies the bitmap).
428 bool wxMask::Create(const wxBitmap
& WXUNUSED(bitmap
))
434 // Create a mask from a bitmap and a palette index indicating
435 // the transparent area
436 bool wxMask::Create(const wxBitmap
& WXUNUSED(bitmap
), int WXUNUSED(paletteIndex
))
442 // Create a mask from a bitmap and a colour indicating
443 // the transparent area
444 bool wxMask::Create(const wxBitmap
& WXUNUSED(bitmap
), const wxColour
& WXUNUSED(colour
))
454 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler
, wxObject
)
456 bool wxBitmapHandler::Create(wxBitmap
*WXUNUSED(bitmap
), void *WXUNUSED(data
), long WXUNUSED(type
),
457 int WXUNUSED(width
), int WXUNUSED(height
), int WXUNUSED(depth
))
462 bool wxBitmapHandler::LoadFile(wxBitmap
*WXUNUSED(bitmap
), const wxString
& WXUNUSED(name
), long WXUNUSED(type
),
463 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
468 bool wxBitmapHandler::SaveFile(wxBitmap
*WXUNUSED(bitmap
), const wxString
& WXUNUSED(name
), int WXUNUSED(type
),
469 const wxPalette
*WXUNUSED(palette
))
478 class WXDLLEXPORT wxXBMFileHandler
: public wxBitmapHandler
480 DECLARE_DYNAMIC_CLASS(wxXBMFileHandler
)
482 inline wxXBMFileHandler()
486 m_type
= wxBITMAP_TYPE_XBM
;
489 virtual bool LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long flags
,
490 int desiredWidth
, int desiredHeight
);
492 IMPLEMENT_DYNAMIC_CLASS(wxXBMFileHandler
, wxBitmapHandler
)
494 bool wxXBMFileHandler::LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long WXUNUSED(flags
),
495 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
))
497 M_BITMAPHANDLERDATA
->m_freePixmap
= TRUE
;
503 Display
*dpy
= (Display
*) wxGetDisplay();
504 M_BITMAPDATA
->m_display
= (WXDisplay
*) dpy
;
506 int value
= XReadBitmapFile (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)),
507 (char*) (const char*) name
, &w
, &h
, &pixmap
, &hotX
, &hotY
);
508 M_BITMAPHANDLERDATA
->m_width
= w
;
509 M_BITMAPHANDLERDATA
->m_height
= h
;
510 M_BITMAPHANDLERDATA
->m_depth
= 1;
511 M_BITMAPHANDLERDATA
->m_pixmap
= (WXPixmap
) pixmap
;
513 if ((value
== BitmapFileInvalid
) ||
514 (value
== BitmapOpenFailed
) ||
515 (value
== BitmapNoMemory
))
517 M_BITMAPHANDLERDATA
->m_ok
= FALSE
;
518 M_BITMAPHANDLERDATA
->m_pixmap
= (WXPixmap
) 0;
521 M_BITMAPHANDLERDATA
->m_ok
= TRUE
;
523 return M_BITMAPHANDLERDATA
->m_ok
;
526 class WXDLLEXPORT wxXBMDataHandler
: public wxBitmapHandler
528 DECLARE_DYNAMIC_CLASS(wxXBMDataHandler
)
530 inline wxXBMDataHandler()
534 m_type
= wxBITMAP_TYPE_XBM_DATA
;
537 virtual bool Create(wxBitmap
*bitmap
, void *data
, long flags
, int width
, int height
, int depth
= 1);
539 IMPLEMENT_DYNAMIC_CLASS(wxXBMDataHandler
, wxBitmapHandler
)
541 bool wxXBMDataHandler::Create( wxBitmap
*bitmap
, void *data
, long WXUNUSED(flags
),
542 int width
, int height
, int WXUNUSED(depth
))
544 M_BITMAPHANDLERDATA
->m_width
= width
;
545 M_BITMAPHANDLERDATA
->m_height
= height
;
546 M_BITMAPHANDLERDATA
->m_depth
= 1;
547 M_BITMAPHANDLERDATA
->m_freePixmap
= TRUE
;
549 Display
*dpy
= (Display
*) wxGetDisplay();
550 M_BITMAPHANDLERDATA
->m_display
= (WXDisplay
*) dpy
;
552 M_BITMAPHANDLERDATA
->m_pixmap
= (WXPixmap
) XCreateBitmapFromData (dpy
, RootWindow (dpy
, DefaultScreen (dpy
)), (char*) data
, width
, height
);
553 M_BITMAPHANDLERDATA
->m_ok
= (M_BITMAPHANDLERDATA
->m_pixmap
!= (WXPixmap
) 0) ;
555 // code for wxControl. TODO: can we avoid doing this until we need it?
556 // E.g. have CreateButtonPixmaps which is called on demand.
557 XImage
* image
= (XImage
*) XtMalloc (sizeof (XImage
));
558 image
->width
= width
;
559 image
->height
= height
;
560 image
->data
= (char*) data
;
563 image
->format
= XYBitmap
;
564 image
->byte_order
= LSBFirst
;
565 image
->bitmap_unit
= 8;
566 image
->bitmap_bit_order
= LSBFirst
;
567 image
->bitmap_pad
= 8;
568 image
->bytes_per_line
= (width
+ 7) >> 3;
571 sprintf (tmp
, "Im%x", (unsigned int) image
);
572 XmInstallImage (image
, tmp
);
574 // Build our manually stipped pixmap.
576 int bpl
= (width
+ 7) / 8;
577 char *data1
= new char[height
* bpl
];
578 char* bits
= (char*) data
;
580 for (i
= 0; i
< height
; i
++)
582 int mask
= i
% 2 ? 0x55 : 0xaa;
584 for (j
= 0; j
< bpl
; j
++)
585 data1
[i
* bpl
+ j
] = bits
[i
* bpl
+ j
] & mask
;
587 XImage
* insensImage
= (XImage
*) XtMalloc (sizeof (XImage
));
588 insensImage
->width
= width
;
589 insensImage
->height
= height
;
590 insensImage
->data
= data1
;
591 insensImage
->depth
= 1;
592 insensImage
->xoffset
= 0;
593 insensImage
->format
= XYBitmap
;
594 insensImage
->byte_order
= LSBFirst
;
595 insensImage
->bitmap_unit
= 8;
596 insensImage
->bitmap_bit_order
= LSBFirst
;
597 insensImage
->bitmap_pad
= 8;
598 insensImage
->bytes_per_line
= bpl
;
600 sprintf (tmp
, "Not%x", (unsigned int)insensImage
);
601 XmInstallImage (insensImage
, tmp
);
603 M_BITMAPHANDLERDATA
->m_image
= (WXImage
*) image
;
604 M_BITMAPHANDLERDATA
->m_insensImage
= (WXImage
*) insensImage
;
610 class WXDLLEXPORT wxXPMFileHandler
: public wxBitmapHandler
612 DECLARE_DYNAMIC_CLASS(wxXPMFileHandler
)
614 inline wxXPMFileHandler()
618 m_type
= wxBITMAP_TYPE_XPM
;
621 virtual bool LoadFile(wxBitmap
*bitmap
, const wxString
& name
, long flags
,
622 int desiredWidth
, int desiredHeight
);
623 virtual bool SaveFile(wxBitmap
*bitmap
, const wxString
& name
, int type
, const wxPalette
*palette
= NULL
);
626 IMPLEMENT_DYNAMIC_CLASS(wxXPMFileHandler
, wxBitmapHandler
)
628 bool wxXPMFileHandler::LoadFile( wxBitmap
*bitmap
, const wxString
& name
, long WXUNUSED(flags
),
629 int WXUNUSED(desiredWidth
), int WXUNUSED(desiredHeight
) )
631 Display
*dpy
= (Display
*) wxGetDisplay();
632 M_BITMAPHANDLERDATA
->m_display
= (WXDisplay
*) dpy
;
634 XpmAttributes xpmAttr
;
638 M_BITMAPHANDLERDATA
->m_ok
= FALSE
;
639 xpmAttr
.valuemask
= XpmReturnInfos
| XpmCloseness
;
640 xpmAttr
.closeness
= 40000;
641 int errorStatus
= XpmReadFileToPixmap(dpy
,
642 RootWindow(dpy
, DefaultScreen(dpy
)), (char*) (const char*) name
,
643 &pixmap
, &mask
, &xpmAttr
);
645 if (errorStatus
== XpmSuccess
)
647 M_BITMAPHANDLERDATA
->m_pixmap
= (WXPixmap
) pixmap
;
650 M_BITMAPHANDLERDATA
->m_bitmapMask
= new wxMask
;
651 M_BITMAPHANDLERDATA
->m_bitmapMask
->SetPixmap((WXPixmap
) mask
);
654 unsigned int depthRet
;
656 unsigned int widthRet
, heightRet
, borderWidthRet
;
657 Window rootWindowRet
;
658 XGetGeometry(dpy
, pixmap
, &rootWindowRet
, &xRet
, &yRet
,
659 &widthRet
, &heightRet
, &borderWidthRet
, &depthRet
);
661 M_BITMAPHANDLERDATA
->m_width
= xpmAttr
.width
;
662 M_BITMAPHANDLERDATA
->m_height
= xpmAttr
.height
;
665 if ( xpmAttr.npixels > 2 )
667 M_BITMAPHANDLERDATA->m_depth = 8; // TODO: next time not just a guess :-) ...
670 M_BITMAPHANDLERDATA->m_depth = 1; // mono
674 M_BITMAPHANDLERDATA
->m_depth
= depthRet
;
676 M_BITMAPHANDLERDATA
->m_numColors
= xpmAttr
.npixels
;
678 XpmFreeAttributes(&xpmAttr
);
680 M_BITMAPHANDLERDATA
->m_ok
= TRUE
;
684 // XpmDebugError(errorStatus, name);
685 M_BITMAPHANDLERDATA
->m_ok
= FALSE
;
690 bool wxXPMFileHandler::SaveFile( wxBitmap
*bitmap
, const wxString
& name
, int WXUNUSED(type
),
691 const wxPalette
*WXUNUSED(palette
))
693 if (M_BITMAPHANDLERDATA
->m_ok
&& M_BITMAPHANDLERDATA
->m_pixmap
)
695 Display
*dpy
= (Display
*) M_BITMAPHANDLERDATA
->m_display
;
696 int errorStatus
= XpmWriteFileFromPixmap(dpy
, (char*) (const char*) name
,
697 (Pixmap
) M_BITMAPHANDLERDATA
->m_pixmap
,
698 (M_BITMAPHANDLERDATA
->m_bitmapMask
? (Pixmap
) M_BITMAPHANDLERDATA
->m_bitmapMask
->GetPixmap() : (Pixmap
) 0),
699 (XpmAttributes
*) NULL
);
700 if (errorStatus
== XpmSuccess
)
709 class WXDLLEXPORT wxXPMDataHandler
: public wxBitmapHandler
711 DECLARE_DYNAMIC_CLASS(wxXPMDataHandler
)
713 inline wxXPMDataHandler()
717 m_type
= wxBITMAP_TYPE_XPM_DATA
;
720 virtual bool Create(wxBitmap
*bitmap
, void *data
, long flags
, int width
, int height
, int depth
= 1);
722 IMPLEMENT_DYNAMIC_CLASS(wxXPMDataHandler
, wxBitmapHandler
)
724 bool wxXPMDataHandler::Create( wxBitmap
*bitmap
, void *data
, long WXUNUSED(flags
),
725 int width
, int height
, int WXUNUSED(depth
))
727 M_BITMAPHANDLERDATA
->m_width
= width
;
728 M_BITMAPHANDLERDATA
->m_height
= height
;
729 M_BITMAPHANDLERDATA
->m_depth
= 1;
730 M_BITMAPHANDLERDATA
->m_freePixmap
= TRUE
;
732 Display
*dpy
= (Display
*) wxGetDisplay();
733 M_BITMAPHANDLERDATA
->m_display
= (WXDisplay
*) dpy
;
735 XpmAttributes xpmAttr
;
737 xpmAttr
.valuemask
= XpmReturnInfos
; /* nothing yet, but get infos back */
739 XpmColorSymbol symbolicColors
[4];
740 if (sg_Control
&& sg_Control
->GetMainWidget())
742 symbolicColors
[0].name
= "foreground";
743 symbolicColors
[0].value
= NULL
;
744 symbolicColors
[1].name
= "background";
745 symbolicColors
[1].value
= NULL
;
746 XtVaGetValues((Widget
) sg_Control
->GetMainWidget(),
747 XmNforeground
, &symbolicColors
[0].pixel
,
748 XmNbackground
, &symbolicColors
[1].pixel
,NULL
);
749 xpmAttr
.numsymbols
= 2;
750 xpmAttr
.colorsymbols
= symbolicColors
;
751 xpmAttr
.valuemask
|= XpmColorSymbols
; // add flag
756 int ErrorStatus
= XpmCreatePixmapFromData(dpy
, RootWindow(dpy
, DefaultScreen(dpy
)),
757 (char**) data
, &pixmap
, &mask
, &xpmAttr
);
758 if (ErrorStatus
== XpmSuccess
)
761 M_BITMAPHANDLERDATA
->m_width
= xpmAttr
.width
;
762 M_BITMAPHANDLERDATA
->m_height
= xpmAttr
.height
;
764 unsigned int depthRet
;
766 unsigned int widthRet
, heightRet
, borderWidthRet
;
767 Window rootWindowRet
;
768 XGetGeometry(dpy
, pixmap
, &rootWindowRet
, &xRet
, &yRet
,
769 &widthRet
, &heightRet
, &borderWidthRet
, &depthRet
);
772 if ( xpmAttr.npixels > 2 )
774 M_BITMAPHANDLERDATA->m_depth = 8; // next time not just a guess :-) ...
777 M_BITMAPHANDLERDATA->m_depth = 1; // mono
781 M_BITMAPHANDLERDATA
->m_depth
= depthRet
;
783 M_BITMAPHANDLERDATA
->m_numColors
= xpmAttr
.npixels
;
784 XpmFreeAttributes(&xpmAttr
);
785 M_BITMAPHANDLERDATA
->m_ok
= TRUE
;
786 M_BITMAPHANDLERDATA
->m_pixmap
= (WXPixmap
) pixmap
;
789 M_BITMAPHANDLERDATA
->m_bitmapMask
= new wxMask
;
790 M_BITMAPHANDLERDATA
->m_bitmapMask
->SetPixmap((WXPixmap
) mask
);
795 // XpmDebugError(ErrorStatus, NULL);
796 M_BITMAPHANDLERDATA
->m_ok
= FALSE
;
798 return M_BITMAPHANDLERDATA
->m_ok
;
801 #endif // wxHAVE_LIB_XPM
803 void wxBitmap::CleanUpHandlers()
805 wxNode
*node
= sm_handlers
.First();
808 wxBitmapHandler
*handler
= (wxBitmapHandler
*)node
->Data();
809 wxNode
*next
= node
->Next();
816 void wxBitmap::InitStandardHandlers()
818 // Initialize all standard bitmap or derived class handlers here.
819 AddHandler(new wxXBMFileHandler
);
820 AddHandler(new wxXBMDataHandler
);
822 // XPM is considered standard for Motif, although it can be omitted if
823 // libXpm is not installed
825 AddHandler(new wxXPMFileHandler
);
826 AddHandler(new wxXPMDataHandler
);
827 #endif // wxHAVE_LIB_XPM
830 WXPixmap
wxBitmap::GetLabelPixmap (WXWidget w
)
833 return (WXPixmap
)NULL
;
834 if (M_BITMAPDATA
->m_image
== (WXPixmap
) 0)
835 return M_BITMAPDATA
->m_pixmap
;
837 Display
*dpy
= (Display
*) M_BITMAPDATA
->m_display
;
842 if (labelPixmap) return labelPixmap;
843 things can be wrong, because colors can have been changed.
847 XmDestroyPixmap(DefaultScreenOfDisplay(dpy),labelPixmap) ;
848 we got BadDrawable if the pixmap is referenced by multiples widgets
852 So, before doing thing really clean, I just do nothing; if the pixmap is
853 referenced by many widgets, Motif performs caching functions.
854 And if pixmap is referenced with multiples colors, we just have some
855 memory leaks... I hope we can deal with them...
857 // Must be destroyed, because colours can have been changed!
858 if (M_BITMAPDATA
->m_labelPixmap
)
859 XmDestroyPixmap (DefaultScreenOfDisplay (dpy
), M_BITMAPDATA
->m_labelPixmap
);
863 sprintf (tmp
, "Im%x", (unsigned int) M_BITMAPDATA
->m_image
);
866 Widget widget
= (Widget
) w
;
868 while (XmIsGadget ( widget
))
869 widget
= XtParent (widget
);
870 XtVaGetValues (widget
, XmNbackground
, &bg
, XmNforeground
, &fg
, NULL
);
872 M_BITMAPDATA
->m_labelPixmap
= (WXPixmap
) XmGetPixmap (DefaultScreenOfDisplay (dpy
), tmp
, fg
, bg
);
874 return M_BITMAPDATA
->m_labelPixmap
;
877 WXPixmap
wxBitmap::GetArmPixmap (WXWidget w
)
879 if (M_BITMAPDATA
->m_image
== (WXPixmap
) 0)
880 return M_BITMAPDATA
->m_pixmap
;
882 Display
*dpy
= (Display
*) M_BITMAPDATA
->m_display
;
884 // See GetLabelPixmap () comment
886 // Must be destroyed, because colours can have been changed!
887 if (M_BITMAPDATA
->m_armPixmap
)
888 XmDestroyPixmap (DefaultScreenOfDisplay (dpy
), M_BITMAPDATA
->m_armPixmap
);
892 sprintf (tmp
, "Im%x", (unsigned int) M_BITMAPDATA
->m_image
);
895 Widget widget
= (Widget
) w
;
897 XtVaGetValues (widget
, XmNarmColor
, &bg
, NULL
);
898 while (XmIsGadget (widget
))
899 widget
= XtParent (widget
);
900 XtVaGetValues (widget
, XmNforeground
, &fg
, NULL
);
902 M_BITMAPDATA
->m_armPixmap
= (WXPixmap
) XmGetPixmap (DefaultScreenOfDisplay (dpy
), tmp
, fg
, bg
);
904 return M_BITMAPDATA
->m_armPixmap
;
907 WXPixmap
wxBitmap::GetInsensPixmap (WXWidget w
)
909 Display
*dpy
= (Display
*) M_BITMAPDATA
->m_display
;
912 return (WXPixmap
)NULL
;
913 if (M_BITMAPDATA
->m_insensPixmap
)
914 return M_BITMAPDATA
->m_insensPixmap
;
918 M_BITMAPDATA
->m_insensPixmap
= (WXPixmap
) XCreateInsensitivePixmap(dpy
, (Pixmap
) M_BITMAPDATA
->m_pixmap
);
919 if (M_BITMAPDATA
->m_insensPixmap
)
920 return M_BITMAPDATA
->m_insensPixmap
;
922 return M_BITMAPDATA
->m_pixmap
;
925 if (M_BITMAPDATA
->m_insensImage
== (WXPixmap
) 0)
926 return M_BITMAPDATA
->m_pixmap
;
929 See
GetLabelPixmap () comment
930 // Must be destroyed, because colours can have been changed!
931 if (M_BITMAPDATA
->m_insensPixmap
)
932 XmDestroyPixmap (DefaultScreenOfDisplay (dpy
), (Pixmap
) M_BITMAPDATA
->m_insensPixmap
);
936 sprintf (tmp
, "Not%x", (unsigned int) M_BITMAPDATA
->m_insensImage
);
939 Widget widget
= (Widget
) w
;
941 while (XmIsGadget (widget
))
942 widget
= XtParent (widget
);
943 XtVaGetValues (widget
, XmNbackground
, &bg
, XmNforeground
, &fg
, NULL
);
945 M_BITMAPDATA
->m_insensPixmap
= (WXPixmap
) XmGetPixmap (DefaultScreenOfDisplay (dpy
), tmp
, fg
, bg
);
947 return M_BITMAPDATA
->m_insensPixmap
;
950 // We may need this sometime...
952 /****************************************************************************
955 XCreateInsensitivePixmap - create a grayed-out copy of a pixmap
958 Pixmap XCreateInsensitivePixmap( Display *display, Pixmap pixmap )
961 This function creates a grayed-out copy of the argument pixmap, suitable
962 for use as a XmLabel's XmNlabelInsensitivePixmap resource.
965 The return value is the new Pixmap id or zero on error. Errors include
966 a NULL display argument or an invalid Pixmap argument.
969 If one of the XLib functions fail, it will produce a X error. The
970 default X error handler prints a diagnostic and calls exit().
973 XCopyArea(3), XCreateBitmapFromData(3), XCreateGC(3), XCreatePixmap(3),
974 XFillRectangle(3), exit(2)
977 John R Veregge - john@puente.jpl.nasa.gov
978 Advanced Engineering and Prototyping Group (AEG)
979 Information Systems Technology Section (395)
980 Jet Propulsion Lab - Calif Institute of Technology
982 *****************************************************************************/
985 XCreateInsensitivePixmap( Display
*display
, Pixmap pixmap
)
988 static char stipple_data
[] =
990 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA,
991 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA,
992 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA,
993 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA
996 Pixmap ipixmap
, stipple
;
997 unsigned width
, height
, depth
;
999 Window window
; /* These return values */
1000 unsigned border
; /* from XGetGeometry() */
1001 int x
, y
; /* are not needed. */
1005 if ( NULL
== display
|| 0 == pixmap
)
1008 if ( 0 == XGetGeometry( display
, pixmap
, &window
, &x
, &y
,
1009 &width
, &height
, &border
, &depth
)
1011 return ipixmap
; /* BadDrawable: probably an invalid pixmap */
1013 /* Get the stipple pixmap to be used to 'gray-out' the argument pixmap.
1015 stipple
= XCreateBitmapFromData( display
, pixmap
, stipple_data
, 16, 16 );
1018 gc
= XCreateGC( display
, pixmap
, (XtGCMask
)0, (XGCValues
*)NULL
);
1021 /* Create an identical copy of the argument pixmap.
1023 ipixmap
= XCreatePixmap( display
, pixmap
, width
, height
, depth
);
1026 /* Copy the argument pixmap into the new pixmap.
1028 XCopyArea( display
, pixmap
, ipixmap
,
1029 gc
, 0, 0, width
, height
, 0, 0 );
1031 /* Refill the new pixmap using the stipple algorithm/pixmap.
1033 XSetStipple( display
, gc
, stipple
);
1034 XSetFillStyle( display
, gc
, FillStippled
);
1035 XFillRectangle( display
, ipixmap
, gc
, 0, 0, width
, height
);
1037 XFreeGC( display
, gc
);
1039 XFreePixmap( display
, stipple
);
1044 // Creates a bitmap with transparent areas drawn in
1045 // the given colour.
1046 wxBitmap
wxCreateMaskedBitmap(const wxBitmap
& bitmap
, wxColour
& colour
)
1048 wxBitmap
newBitmap(bitmap
.GetWidth(),
1053 srcDC
.SelectObject(bitmap
);
1054 destDC
.SelectObject(newBitmap
);
1056 wxBrush
brush(colour
, wxSOLID
);
1057 destDC
.SetOptimization(FALSE
);
1058 destDC
.SetBackground(brush
);
1060 destDC
.Blit(0, 0, bitmap
.GetWidth(), bitmap
.GetHeight(), & srcDC
, 0, 0, wxCOPY
, TRUE
);
1068 //-----------------------------------------------------------------------------
1069 // wxImage conversion routines
1070 //-----------------------------------------------------------------------------
1074 Date: Wed, 05 Jan 2000 11:45:40 +0100
1075 From: Frits Boel <boel@niob.knaw.nl>
1076 To: julian.smart@ukonline.co.uk
1077 Subject: Patch for Motif ConvertToBitmap
1081 I've been working on a wxWin application for image processing. From the
1082 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
1083 till I looked in the source code of image.cpp. I saw that converting a
1084 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
1085 to the 256 colors of the palet. A very time-consuming piece of code!
1087 Because I wanted a faster application, I've made a 'patch' for this. In
1088 short: every pixel of the image is compared to a sorted list with
1089 colors. If the color is found in the list, the palette entry is
1090 returned; if the color is not found, the color palette is searched and
1091 then the palette entry is returned and the color added to the sorted
1094 Maybe there is another method for this, namely changing the palette
1095 itself (if the colors are known, as is the case with tiffs with a
1096 colormap). I did not look at this, maybe someone else did?
1098 The code of the patch is attached, have a look on it, and maybe you will
1099 ship it with the next release of wxMotif?
1104 Software engineer at Hubrecht Laboratory, The Netherlands.
1111 wxSearchColor( void );
1112 wxSearchColor( int size
, XColor
*colors
);
1113 ~wxSearchColor( void );
1115 int SearchColor( int r
, int g
, int b
);
1117 int AddColor( unsigned int value
, int pos
);
1121 unsigned int *color
;
1128 wxSearchColor::wxSearchColor( void )
1131 colors
= (XColor
*) NULL
;
1132 color
= (unsigned int *) NULL
;
1133 entry
= (int*) NULL
;
1139 wxSearchColor::wxSearchColor( int size_
, XColor
*colors_
)
1144 color
= new unsigned int[size
];
1145 entry
= new int [size
];
1147 for (i
= 0; i
< size
; i
++ ) {
1151 bottom
= top
= ( size
>> 1 );
1154 wxSearchColor::~wxSearchColor( void )
1156 if ( color
) delete color
;
1157 if ( entry
) delete entry
;
1160 int wxSearchColor::SearchColor( int r
, int g
, int b
)
1162 unsigned int value
= ( ( ( r
* 256 ) + g
) * 256 ) + b
;
1167 while ( begin
<= end
) {
1169 middle
= ( begin
+ end
) >> 1;
1171 if ( value
== color
[middle
] ) {
1172 return( entry
[middle
] );
1173 } else if ( value
< color
[middle
] ) {
1181 return AddColor( value
, middle
);
1184 int wxSearchColor::AddColor( unsigned int value
, int pos
)
1188 int max
= 3 * (65536);
1189 for ( i
= 0; i
< 256; i
++ ) {
1190 int rdiff
= ((value
>> 8) & 0xFF00 ) - colors
[i
].red
;
1191 int gdiff
= ((value
) & 0xFF00 ) - colors
[i
].green
;
1192 int bdiff
= ((value
<< 8) & 0xFF00 ) - colors
[i
].blue
;
1193 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
1194 if (sum
< max
) { pixel
= i
; max
= sum
; }
1197 if ( entry
[pos
] < 0 ) {
1200 } else if ( value
< color
[pos
] ) {
1203 for ( i
= bottom
; i
< pos
; i
++ ) {
1204 color
[i
-1] = color
[i
];
1205 entry
[i
-1] = entry
[i
];
1208 color
[pos
-1] = value
;
1209 entry
[pos
-1] = pixel
;
1210 } else if ( top
< size
-1 ) {
1211 for ( i
= top
; i
>= pos
; i
-- ) {
1212 color
[i
+1] = color
[i
];
1213 entry
[i
+1] = entry
[i
];
1222 if ( top
< size
-1 ) {
1223 for ( i
= top
; i
> pos
; i
-- ) {
1224 color
[i
+1] = color
[i
];
1225 entry
[i
+1] = entry
[i
];
1228 color
[pos
+1] = value
;
1229 entry
[pos
+1] = pixel
;
1230 } else if ( bottom
> 0 ) {
1231 for ( i
= bottom
; i
< pos
; i
++ ) {
1232 color
[i
-1] = color
[i
];
1233 entry
[i
-1] = entry
[i
];
1246 bool wxBitmap::CreateFromImage( const wxImage
& image
, int depth
)
1248 wxCHECK_MSG( image
.Ok(), FALSE
, wxT("invalid image") )
1249 wxCHECK_MSG( depth
== -1, FALSE
, wxT("invalid bitmap depth") )
1251 m_refData
= new wxBitmapRefData();
1253 int width
= image
.GetWidth();
1254 int height
= image
.GetHeight();
1256 SetHeight( height
);
1259 Display
*dpy
= (Display
*) wxGetDisplay();
1260 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1261 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1265 XImage
*data_image
= XCreateImage( dpy
, vis
, bpp
, ZPixmap
, 0, 0, width
, height
, 32, 0 );
1266 data_image
->data
= (char*) malloc( data_image
->bytes_per_line
* data_image
->height
);
1268 Create( width
, height
, bpp
);
1272 XImage
*mask_image
= (XImage
*) NULL
;
1273 if (image
.HasMask())
1275 mask_image
= XCreateImage( dpy
, vis
, 1, ZPixmap
, 0, 0, width
, height
, 32, 0 );
1276 mask_image
->data
= (char*) malloc( mask_image
->bytes_per_line
* mask_image
->height
);
1279 // Retrieve depth info
1281 XVisualInfo vinfo_template
;
1284 vinfo_template
.visual
= vis
;
1285 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1286 vinfo_template
.depth
= bpp
;
1289 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1291 wxCHECK_MSG( vi
, FALSE
, wxT("no visual") );
1295 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1296 if (bpp
< 8) bpp
= 8;
1300 enum byte_order
{ RGB
, RBG
, BRG
, BGR
, GRB
, GBR
};
1301 byte_order b_o
= RGB
;
1305 if ((vi
->red_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->blue_mask
)) b_o
= RGB
;
1306 else if ((vi
->red_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->green_mask
)) b_o
= RGB
;
1307 else if ((vi
->blue_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->green_mask
)) b_o
= BRG
;
1308 else if ((vi
->blue_mask
> vi
->green_mask
) && (vi
->green_mask
> vi
->red_mask
)) b_o
= BGR
;
1309 else if ((vi
->green_mask
> vi
->red_mask
) && (vi
->red_mask
> vi
->blue_mask
)) b_o
= GRB
;
1310 else if ((vi
->green_mask
> vi
->blue_mask
) && (vi
->blue_mask
> vi
->red_mask
)) b_o
= GBR
;
1313 int r_mask
= image
.GetMaskRed();
1314 int g_mask
= image
.GetMaskGreen();
1315 int b_mask
= image
.GetMaskBlue();
1320 Colormap cmap
= (Colormap
) wxTheApp
->GetMainColormap( dpy
);
1322 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
1323 XQueryColors( dpy
, cmap
, colors
, 256 );
1326 wxSearchColor
scolor( 256, colors
);
1327 unsigned char* data
= image
.GetData();
1329 bool hasMask
= image
.HasMask();
1332 for (int y
= 0; y
< height
; y
++)
1334 for (int x
= 0; x
< width
; x
++)
1336 int r
= data
[index
];
1338 int g
= data
[index
];
1340 int b
= data
[index
];
1345 if ((r
== r_mask
) && (b
== b_mask
) && (g
== g_mask
))
1346 XPutPixel( mask_image
, x
, y
, 0 );
1348 XPutPixel( mask_image
, x
, y
, 1 );
1355 #if 0 // Old, slower code
1358 if (wxTheApp->m_colorCube)
1360 pixel = wxTheApp->m_colorCube
1361 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1366 int max
= 3 * (65536);
1367 for (int i
= 0; i
< 256; i
++)
1369 int rdiff
= (r
<< 8) - colors
[i
].red
;
1370 int gdiff
= (g
<< 8) - colors
[i
].green
;
1371 int bdiff
= (b
<< 8) - colors
[i
].blue
;
1372 int sum
= abs (rdiff
) + abs (gdiff
) + abs (bdiff
);
1373 if (sum
< max
) { pixel
= i
; max
= sum
; }
1380 // And this is all to get the 'right' color...
1381 int pixel
= scolor
.SearchColor( r
, g
, b
);
1382 XPutPixel( data_image
, x
, y
, pixel
);
1387 int pixel
= ((r
& 0xf8) << 7) | ((g
& 0xf8) << 2) | ((b
& 0xf8) >> 3);
1388 XPutPixel( data_image
, x
, y
, pixel
);
1393 int pixel
= ((r
& 0xf8) << 8) | ((g
& 0xfc) << 3) | ((b
& 0xf8) >> 3);
1394 XPutPixel( data_image
, x
, y
, pixel
);
1403 case RGB
: pixel
= (r
<< 16) | (g
<< 8) | b
; break;
1404 case RBG
: pixel
= (r
<< 16) | (b
<< 8) | g
; break;
1405 case BRG
: pixel
= (b
<< 16) | (r
<< 8) | g
; break;
1406 case BGR
: pixel
= (b
<< 16) | (g
<< 8) | r
; break;
1407 case GRB
: pixel
= (g
<< 16) | (r
<< 8) | b
; break;
1408 case GBR
: pixel
= (g
<< 16) | (b
<< 8) | r
; break;
1410 XPutPixel( data_image
, x
, y
, pixel
);
1420 gcvalues
.foreground
= BlackPixel( dpy
, DefaultScreen( dpy
) );
1421 GC gc
= XCreateGC( dpy
, RootWindow ( dpy
, DefaultScreen(dpy
) ), GCForeground
, &gcvalues
);
1422 XPutImage( dpy
, (Drawable
)GetPixmap(), gc
, data_image
, 0, 0, 0, 0, width
, height
);
1424 XDestroyImage( data_image
);
1428 if (image
.HasMask())
1430 wxBitmap
maskBitmap(width
, height
, 1);
1432 GC gcMask
= XCreateGC( dpy
, (Pixmap
) maskBitmap
.GetPixmap(), (XtGCMask
) 0, (XGCValues
*)NULL
);
1433 XPutImage( dpy
, (Drawable
)maskBitmap
.GetPixmap(), gcMask
, mask_image
, 0, 0, 0, 0, width
, height
);
1435 XDestroyImage( mask_image
);
1436 XFreeGC( dpy
, gcMask
);
1438 wxMask
* mask
= new wxMask
;
1439 mask
->SetPixmap(maskBitmap
.GetPixmap());
1443 maskBitmap
.SetPixmapNull();
1450 wxImage
wxBitmap::ConvertToImage() const
1454 wxCHECK_MSG( Ok(), wxNullImage
, wxT("invalid bitmap") );
1456 Display
*dpy
= (Display
*) wxGetDisplay();
1457 Visual
* vis
= DefaultVisual( dpy
, DefaultScreen( dpy
) );
1458 int bpp
= DefaultDepth( dpy
, DefaultScreen( dpy
) );
1460 XImage
*ximage
= XGetImage( dpy
,
1461 (Drawable
)GetPixmap(),
1463 GetWidth(), GetHeight(),
1464 AllPlanes
, ZPixmap
);
1466 wxCHECK_MSG( ximage
, wxNullImage
, wxT("couldn't create image") );
1468 image
.Create( GetWidth(), GetHeight() );
1469 char unsigned *data
= image
.GetData();
1473 XDestroyImage( ximage
);
1474 wxFAIL_MSG( wxT("couldn't create image") );
1479 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1482 gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
1484 GetWidth(), GetHeight() );
1486 image.SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1490 // Retrieve depth info
1492 XVisualInfo vinfo_template
;
1495 vinfo_template
.visual
= vis
;
1496 vinfo_template
.visualid
= XVisualIDFromVisual( vis
);
1497 vinfo_template
.depth
= bpp
;
1500 vi
= XGetVisualInfo( dpy
, VisualIDMask
|VisualDepthMask
, &vinfo_template
, &nitem
);
1502 wxCHECK_MSG( vi
, wxNullImage
, wxT("no visual") );
1504 if ((bpp
== 16) && (vi
->red_mask
!= 0xf800)) bpp
= 15;
1511 Colormap cmap
= (Colormap
)wxTheApp
->GetMainColormap( dpy
);
1513 for (int i
= 0; i
< 256; i
++) colors
[i
].pixel
= i
;
1514 XQueryColors( dpy
, cmap
, colors
, 256 );
1518 for (int j
= 0; j
< GetHeight(); j
++)
1520 for (int i
= 0; i
< GetWidth(); i
++)
1522 int pixel
= XGetPixel( ximage
, i
, j
);
1525 data
[pos
] = colors
[pixel
].red
>> 8;
1526 data
[pos
+1] = colors
[pixel
].green
>> 8;
1527 data
[pos
+2] = colors
[pixel
].blue
>> 8;
1528 } else if (bpp
== 15)
1530 data
[pos
] = (pixel
>> 7) & 0xf8;
1531 data
[pos
+1] = (pixel
>> 2) & 0xf8;
1532 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1533 } else if (bpp
== 16)
1535 data
[pos
] = (pixel
>> 8) & 0xf8;
1536 data
[pos
+1] = (pixel
>> 3) & 0xfc;
1537 data
[pos
+2] = (pixel
<< 3) & 0xf8;
1540 data
[pos
] = (pixel
>> 16) & 0xff;
1541 data
[pos
+1] = (pixel
>> 8) & 0xff;
1542 data
[pos
+2] = pixel
& 0xff;
1548 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1549 if (mask_pixel == 0)
1562 XDestroyImage( ximage
);
1564 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );