]> git.saurik.com Git - wxWidgets.git/commitdiff
More-or-less finished reasonably cool wxToolBar class with tooltips.
authorJulian Smart <julian@anthemion.co.uk>
Thu, 22 Oct 1998 14:08:14 +0000 (14:08 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Thu, 22 Oct 1998 14:08:14 +0000 (14:08 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@899 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/motif/todo.txt
include/wx/motif/toolbar.h
src/makeg95.env
src/motif/bmpbuttn.cpp
src/motif/statbmp.cpp
src/motif/textctrl.cpp
src/motif/timer.cpp
src/motif/toolbar.cpp

index 1e7f001ba6f02321bdf25917777d84f076939c25..52eb135233896b72de06a097b685214513f69baf 100644 (file)
@@ -37,29 +37,19 @@ High Priority
 
 - wxSpinButton
 
-- wxTextCtrl text file loading and saving.
-
 - A generic version of wxNotebook that can be used in wxMotif and
   other toolkits that don't have a native control. Perhaps use wxTab as a
   starting point.
 
-- Complete the MDI implementation. Could eventually alter the MDI
-  widgets to be more Windows-like -- currently it's half-hearted.
-
 - Tidy dialogs such as the colour and font selectors.
 
 - Use generic wxTreeCtrl, wxListCtrl: debug and enhance these.
 
-- Write a better generic wxToolBar class than wxToolBarSimple.
-  Alternatively, write a toolbar using Motif as described here:
-  http://www.motifzone.com/tmd/articles/Kurt_Huhner/jun96.html.
-  This article also explains how to implement tooltips.
-
 - Find out why modal dialogs give a grab warning.
 
-- Find out why UI updates aren't working (probably an OnIdle failure).
-
-- wxSystemSettings
+- wxSystemSettings. Eventually, should have control panel-like utility
+  to change colours/fonts but meanwhile should maybe read them
+  from a file.
 
 - wxThread (hopefully, similar to wxGTK)
 
@@ -106,8 +96,14 @@ Low Priority
   Netscape is running. See:
   http://www.motifzone.com/tmd/articles/John_Cwikla/index.html
 
+- wxRCConfig (a config class using X .rc files). Could simply
+  implement it in terms of current wxGet/WriteResource functions.
+
 - wxCheckBoxList
 
+- Reimplement combobox using Lesstif's widget (avoiding GPL'ed
+  widget currently used).
+
 - Write generic wxDirDialog (directory selector)
 
 - Use native Motif dialogs for wxMessageBox
@@ -116,3 +112,6 @@ Low Priority
   Linux)
 
 - Blit scaling
+
+- Could eventually alter the MDI widgets to be more Windows-like
+  -- currently it's half-hearted.
index f3c98e8d1eb4d36597c574d59f1003d16691de09..590b417b4f5bc5e8063191957ec22a15225e88d5 100644 (file)
@@ -70,10 +70,19 @@ class WXDLLEXPORT wxToolBar: public wxToolBarBase
   // necessary for completing the toolbar construction.
   bool Realize() { return CreateTools(); };
 
+// Implementation
+  void DestroyPixmaps();
+  int FindIndexForWidget(WXWidget w);
+  WXWidget FindWidgetForIndex(int index);
+
 protected:
   // List of widgets in the toolbar, indexed by tool index
   wxList    m_widgets;
 
+  // List of pixmaps to destroy when tools are recreated or
+  // or toolbar is destroyed.
+  wxList    m_pixmaps;
+
 DECLARE_EVENT_TABLE()
 };
 
index 374bdf15da8e7e6bf55cf5b0ca434e77f9030d71..56230fadc7669cac4654f48bd4bb7540588ae629 100644 (file)
@@ -39,8 +39,8 @@ MAKE=make
 LEX=flex.exe -t -L
 
 # YACC. byacc or bison
-YACC=byacc.exe
-YACC=bison.exe
+YACC=byacc.exe
+YACC=bison.exe
 
 # Resource compiler
 RESCOMP=windres.exe
index 74a9f6f93e86aaeff27e38ac19431e042db441a2..e7d790bcf0f791812b4b2d0aafeb3332c79e16f7 100644 (file)
@@ -169,7 +169,7 @@ void wxBitmapButton::SetBitmapLabel(const wxBitmap& bitmap)
         // since it is no longer valid.
         XtVaSetValues ((Widget) m_mainWidget,
             XmNlabelType, XmSTRING,
-            XmNlabelPixmap, NULL, // TODO: Does this work?
+            XmNlabelPixmap, XmUNSPECIFIED_PIXMAP,
            XmNlabelInsensitivePixmap, NULL,
             XmNarmPixmap, NULL,
             NULL);
index 009d175a64cb20ec2a3f73a808d6fcc8858d00d5..68fb07baadaf1e8ea8d0e9d4236ddd8bf00c0efd 100644 (file)
@@ -114,7 +114,7 @@ void wxStaticBitmap::SetBitmap(const wxBitmap& bitmap)
         // since it is no longer valid.
         XtVaSetValues (widget,
             XmNlabelType, XmSTRING,
-            XmNlabelPixmap, NULL, // TODO: Does this work?
+            XmNlabelPixmap, XmUNSPECIFIED_PIXMAP,
             NULL);
     }
 }
index 3016f39932e89083a0afe5cdc61c7be08858e65a..284744f3263f1e4d60a81260a16a61f0a912e328 100644 (file)
@@ -257,37 +257,36 @@ bool wxTextCtrl::LoadFile(const wxString& file)
 
     Clear();
 
-    ifstream input((char*) (const char*) file, ios::nocreate | ios::in);
+    Widget textWidget = (Widget) m_mainWidget;
+    FILE *fp;
 
-    if (!input.bad())
+    struct stat statb;
+    if ((stat ((char*) (const char*) file, &statb) == -1) || (statb.st_mode & S_IFMT) != S_IFREG ||
+      !(fp = fopen ((char*) (const char*) file, "r")))
     {
-        struct stat stat_buf;
-        if (stat(file, &stat_buf) < 0)
-            return FALSE;
-        // This may need to be a bigger buffer than the file size suggests,
-        // if it's a UNIX file. Give it an extra 1000 just in case.
-        char *tmp_buffer = (char*)malloc((size_t)(stat_buf.st_size+1+1000));
-        long no_lines = 0;
-        long pos = 0;
-        while (!input.eof() && input.peek() != EOF)
-        {
-            input.getline(wxBuffer, 500);
-               int len = strlen(wxBuffer);
-               wxBuffer[len] = 13;
-               wxBuffer[len+1] = 10;
-               wxBuffer[len+2] = 0;
-               strcpy(tmp_buffer+pos, wxBuffer);
-               pos += strlen(wxBuffer);
-               no_lines++;
-         }
-
-         // TODO add line
-
-         free(tmp_buffer);
-
-         return TRUE;
+      return FALSE;
+    }
+    else
+    {
+      long len = statb.st_size;
+      char *text;
+      if (!(text = XtMalloc ((unsigned) (len + 1))))
+       {
+         fclose (fp);
+         return FALSE;
+       }
+      if (fread (text, sizeof (char), len, fp) != (size_t) len)
+       {
+       }
+      fclose (fp);
+
+      text[len] = 0;
+      XmTextSetString (textWidget, text);
+      //      m_textPosition = len;
+      XtFree (text);
+      m_modified = FALSE;
+      return TRUE;
     }
-    return FALSE;
 }
 
 // If file is null, try saved file name first
@@ -301,13 +300,31 @@ bool wxTextCtrl::SaveFile(const wxString& file)
         return FALSE;
     m_fileName = theFile;
 
-    ofstream output((char*) (const char*) theFile);
-    if (output.bad())
-           return FALSE;
+  Widget textWidget = (Widget) m_mainWidget;
+  FILE *fp;
 
-    // TODO get and save text
+  if (!(fp = fopen ((char*) (const char*) theFile, "w")))
+    {
+      return FALSE;
+    }
+  else
+    {
+      char *text = XmTextGetString (textWidget);
+      long len = XmTextGetLastPosition (textWidget);
 
-    return FALSE;
+      if (fwrite (text, sizeof (char), len, fp) != (size_t) len)
+       {
+         // Did not write whole file
+       }
+      // Make sure newline terminates the file
+      if (text[len - 1] != '\n')
+       fputc ('\n', fp);
+
+      fclose (fp);
+      XtFree (text);
+      m_modified = FALSE;
+      return TRUE;
+    }
 }
 
 void wxTextCtrl::WriteText(const wxString& text)
index 1bf9297621a2124b2fd5ad7055a594ac43d8d69e..69b4917557fadf688f2e92eae9a35941d9cb00b1 100644 (file)
@@ -55,6 +55,7 @@ wxTimer::wxTimer()
 wxTimer::~wxTimer()
 {
     Stop();
+    wxTimerList.DeleteObject(this);
 }
 
 bool wxTimer::Start(int milliseconds, bool mode)
index d0db4cc53217b0e88ca4002d082a2d4cdd533f30..903b69be330ddd3d88b34089d50c8216c4598e2f 100644 (file)
 #endif
 
 #include "wx/wx.h"
+#include "wx/app.h"
+#include "wx/timer.h"
 #include "wx/motif/toolbar.h"
 
 #include <Xm/Xm.h>
 #include <Xm/PushBG.h>
 #include <Xm/PushB.h>
+#include <Xm/Label.h>
 #include <Xm/ToggleB.h>
 #include <Xm/ToggleBG.h>
 #include <Xm/Form.h>
@@ -32,6 +35,30 @@ BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
 END_EVENT_TABLE()
 #endif
 
+static void wxToolButtonCallback (Widget w, XtPointer clientData,
+                   XtPointer ptr);
+static void wxToolButtonPopupCallback (Widget w, XtPointer client_data,
+                     XEvent *event, Boolean *continue_to_dispatch);
+
+wxBitmap wxCreateMaskedBitmap(wxBitmap& bitmap, wxColour& colour);
+
+class wxToolBarTimer: public wxTimer
+{
+public:
+  wxToolBarTimer() { }
+  virtual void Notify();
+
+  static Widget help_popup;
+  static Widget buttonWidget;
+  static wxString helpString;
+};
+
+static wxToolBarTimer* wxTheToolBarTimer = (wxToolBarTimer*) NULL;
+
+Widget wxToolBarTimer::help_popup = (Widget) 0;
+Widget wxToolBarTimer::buttonWidget = (Widget) 0;
+wxString wxToolBarTimer::helpString = "";
+
 wxToolBar::wxToolBar():
   m_widgets(wxKEY_INTEGER)
 {
@@ -39,7 +66,6 @@ wxToolBar::wxToolBar():
   m_maxHeight = -1;
   m_defaultWidth = 24;
   m_defaultHeight = 22;
-  // TODO
 }
 
 bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
@@ -66,6 +92,10 @@ bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, cons
                 XmNtraversalOn, False,
                 XmNhorizontalSpacing, 0,
                 XmNverticalSpacing, 0,
+                XmNleftOffset, 0,
+                XmNrightOffset, 0,
+                XmNmarginWidth, 0,
+                XmNmarginHeight, 0,
                 NULL);
 
     m_mainWidget = (WXWidget) toolbar;
@@ -81,7 +111,10 @@ bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, cons
 
 wxToolBar::~wxToolBar()
 {
-    // TODO
+    delete wxTheToolBarTimer;
+    wxTheToolBarTimer = NULL;
+    ClearTools();
+    DestroyPixmaps();
 }
 
 bool wxToolBar::CreateTools()
@@ -89,13 +122,21 @@ bool wxToolBar::CreateTools()
     if (m_tools.Number() == 0)
         return FALSE;
 
+    // Separator spacing
+    const int separatorSize = GetToolSeparation(); // 8;
+
+    int currentSpacing = 0;
+
     m_widgets.Clear();
     Widget prevButton = (Widget) 0;
     wxNode* node = m_tools.First();
     while (node)
     {
         wxToolBarTool *tool = (wxToolBarTool *)node->Data();
-        if ((tool->m_toolStyle != wxTOOL_STYLE_SEPARATOR) && tool->m_bitmap1.Ok())
+
+        if (tool->m_toolStyle == wxTOOL_STYLE_SEPARATOR)
+            currentSpacing = separatorSize;
+        else if (tool->m_bitmap1.Ok())
         {
             Widget button = (Widget) 0;
 
@@ -105,12 +146,14 @@ bool wxToolBar::CreateTools()
                    xmToggleButtonWidgetClass, (Widget) m_mainWidget,
                    XmNleftAttachment, (prevButton == (Widget) 0) ? XmATTACH_FORM : XmATTACH_WIDGET,
                    XmNleftWidget, (prevButton == (Widget) 0) ? NULL : prevButton,
-                   XmNleftOffset, 0,
+                   XmNleftOffset, currentSpacing,
                    XmNtopAttachment, XmATTACH_FORM,
                                                 //                   XmNpushButtonEnabled, True,
                    XmNmultiClick, XmMULTICLICK_KEEP,
                    XmNlabelType, XmPIXMAP,
                    NULL);
+                XtAddCallback ((Widget) button, XmNvalueChangedCallback, (XtCallbackProc) wxToolButtonCallback,
+                (XtPointer) this);
             }
             else
             {
@@ -118,23 +161,25 @@ bool wxToolBar::CreateTools()
                    xmPushButtonWidgetClass, (Widget) m_mainWidget,
                    XmNleftAttachment, (prevButton == (Widget) 0) ? XmATTACH_FORM : XmATTACH_WIDGET,
                    XmNleftWidget, (prevButton == (Widget) 0) ? NULL : prevButton,
-                   XmNleftOffset, 0,
+                   XmNleftOffset, currentSpacing,
                    XmNtopAttachment, XmATTACH_FORM,
                    XmNpushButtonEnabled, True,
                    XmNmultiClick, XmMULTICLICK_KEEP,
                    XmNlabelType, XmPIXMAP,
                    NULL);
-           }
+                XtAddCallback (button,
+                   XmNactivateCallback, (XtCallbackProc) wxToolButtonCallback,
+                   (XtPointer) this);
+            }
 
             // For each button, if there is a mask, we must create
             // a new wxBitmap that has the correct background colour
             // for the button. Otherwise the background will just be
             // e.g. black if a transparent XPM has been loaded.
+            wxBitmap originalBitmap = tool->m_bitmap1;
+
             if (tool->m_bitmap1.GetMask())
             {
-                wxBitmap newBitmap(tool->m_bitmap1.GetWidth(),
-                                  tool->m_bitmap1.GetHeight(),
-                                  tool->m_bitmap1.GetDepth());
                 int backgroundPixel;
                 XtVaGetValues(button, XmNbackground, &backgroundPixel,
                              NULL);
@@ -143,50 +188,48 @@ bool wxToolBar::CreateTools()
                 wxColour col;
                 col.SetPixel(backgroundPixel);
                 
-                wxMemoryDC destDC;
-                wxMemoryDC srcDC;
-                srcDC.SelectObject(tool->m_bitmap1);
-                destDC.SelectObject(newBitmap);
-
-                wxBrush brush(col, wxSOLID);
-                destDC.SetOptimization(FALSE);
-                destDC.SetBackground(brush);
-                destDC.Clear();
-                destDC.Blit(0, 0, tool->m_bitmap1.GetWidth(), tool->m_bitmap1.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE);
+                wxBitmap newBitmap = wxCreateMaskedBitmap(tool->m_bitmap1, col);
 
                 tool->m_bitmap1 = newBitmap;
             }
-            if (tool->m_bitmap2.Ok() && tool->m_bitmap2.GetMask())
-            {
-                wxBitmap newBitmap(tool->m_bitmap2.GetWidth(),
-                                  tool->m_bitmap2.GetHeight(),
-                                  tool->m_bitmap2.GetDepth());
-                int backgroundPixel;
-                XtVaGetValues(button, XmNbackground, &backgroundPixel,
-                             NULL);
-
 
-                wxColour col;
-                col.SetPixel(backgroundPixel);
-                
-                wxMemoryDC destDC;
-                wxMemoryDC srcDC;
-                srcDC.SelectObject(tool->m_bitmap2);
-                destDC.SelectObject(newBitmap);
+            // Create a selected/toggled bitmap. If there isn't a m_bitmap2,
+            // we need to create it (with a darker, selected background)
+            int backgroundPixel;
+            if (tool->m_isToggle)
+                XtVaGetValues(button, XmNselectColor, &backgroundPixel,
+                     NULL);
+            else
+                XtVaGetValues(button, XmNarmColor, &backgroundPixel,
+                     NULL);
 
-                wxBrush brush(col, wxSOLID);
-                destDC.SetOptimization(FALSE);
-                destDC.SetBackground(brush);
-                destDC.Clear();
-                destDC.Blit(0, 0, tool->m_bitmap2.GetWidth(), tool->m_bitmap2.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE);
+            wxColour col;
+            col.SetPixel(backgroundPixel);
 
+            if (tool->m_bitmap2.Ok() && tool->m_bitmap2.GetMask())
+            {
+                // Use what's there
+                wxBitmap newBitmap = wxCreateMaskedBitmap(tool->m_bitmap2, col);
                 tool->m_bitmap2 = newBitmap;
             }
+            else
+            {
+                // Use unselected bitmap
+                if (originalBitmap.GetMask())
+                {
+                    wxBitmap newBitmap = wxCreateMaskedBitmap(originalBitmap, col);
+                    tool->m_bitmap2 = newBitmap;
+               }
+                else
+                    tool->m_bitmap2 = tool->m_bitmap1;
+            }
+
             Pixmap pixmap = (Pixmap) tool->m_bitmap1.GetPixmap();
             Pixmap insensPixmap = (Pixmap) tool->m_bitmap1.GetInsensPixmap();
 
             if (tool->m_isToggle)
             {
+                // Toggle button
                 Pixmap pixmap2 = (Pixmap) 0;
                 Pixmap insensPixmap2 = (Pixmap) 0;
 
@@ -200,34 +243,53 @@ bool wxToolBar::CreateTools()
                 else
                 {
                     pixmap2 = (Pixmap) tool->m_bitmap1.GetArmPixmap(button);
-                    // This has to be both toggled and insensitive, but
-                    // wxBitmap doesn't yet have a member to store & destroy
-                    // it, so make it the same as pixmap2. Actually it's not
-                    // used!
-                    insensPixmap2 = pixmap2;
+                    insensPixmap2 = XCreateInsensitivePixmap((Display*) wxGetDisplay(), pixmap2);
+                    m_pixmaps.Append((wxObject*) insensPixmap2); // Store for later deletion
                 }
                 XtVaSetValues (button,
-                XmNlabelPixmap, pixmap,
-                XmNselectPixmap, pixmap,
-         XmNlabelInsensitivePixmap, insensPixmap,
-        XmNselectInsensitivePixmap, insensPixmap,
-                XmNarmPixmap, pixmap2,
-                XmNlabelType, XmPIXMAP,
-                NULL);
-
-           }
+                    XmNindicatorOn, False,
+                   XmNshadowThickness, 2,
+                              //                   XmNborderWidth, 0,
+                              //                   XmNspacing, 0,
+                   XmNmarginWidth, 0,
+                   XmNmarginHeight, 0,
+                    XmNfillOnSelect, True,
+                    XmNlabelPixmap, pixmap,
+                    XmNselectPixmap, pixmap2,
+                    XmNlabelInsensitivePixmap, insensPixmap,
+                    XmNselectInsensitivePixmap, insensPixmap2,
+                    XmNlabelType, XmPIXMAP,
+                    NULL);
+            }
             else
             {
+                Pixmap pixmap2 = (Pixmap) 0;
+
+                // If there's a bitmap for the armed state, use it,
+                // otherwise generate one.
+                if (tool->m_bitmap2.Ok())
+                {
+                    pixmap2 = (Pixmap) tool->m_bitmap2.GetPixmap();
+                }
+                else
+                {
+                    pixmap2 = (Pixmap) tool->m_bitmap1.GetArmPixmap(button);
+
+                }
+                // Normal button
                 XtVaSetValues(button,
                    XmNlabelPixmap, pixmap,
-                  XmNlabelInsensitivePixmap, insensPixmap,
-                  NULL);
+                   XmNlabelInsensitivePixmap, insensPixmap,
+                   XmNarmPixmap, pixmap2,
+                   NULL);
             }
 
+            XtAddEventHandler (button, EnterWindowMask | LeaveWindowMask, 
+                       False, wxToolButtonPopupCallback, (XtPointer) this);
             m_widgets.Append(tool->m_index, (wxObject*) button);
 
             prevButton = button;
-            
+            currentSpacing = 0;
         }
         node = node->Next();
     }
@@ -261,7 +323,12 @@ void wxToolBar::EnableTool(int toolIndex, bool enable)
     {
         wxToolBarTool *tool = (wxToolBarTool *)node->Data();
         tool->m_enabled = enable;
-        // TODO enable button
+
+        WXWidget widget = FindWidgetForIndex(tool->m_index);
+        if (widget == (WXWidget) 0)
+            return;
+
+        XtSetSensitive((Widget) widget, (Boolean) enable);
     }
 }
 
@@ -274,7 +341,12 @@ void wxToolBar::ToggleTool(int toolIndex, bool toggle)
         if (tool->m_isToggle)
         {
             tool->m_toggleState = toggle;
-            // TODO: set toggle state
+
+            WXWidget widget = FindWidgetForIndex(tool->m_index);
+            if (widget == (WXWidget) 0)
+                return;
+
+            XmToggleButtonSetState((Widget) widget, (Boolean) toggle, False);
         }
     }
 }
@@ -289,10 +361,23 @@ void wxToolBar::ClearTools()
         node = node->Next();
     }
     m_widgets.Clear();
+    DestroyPixmaps();
 
     wxToolBarBase::ClearTools();
 }
 
+void wxToolBar::DestroyPixmaps()
+{
+    wxNode* node = m_pixmaps.First();
+    while (node)
+    {
+        Pixmap pixmap = (Pixmap) node->Data();
+        XmDestroyPixmap (DefaultScreenOfDisplay ((Display*) GetXDisplay()), pixmap);
+        node = node->Next();
+    }
+    m_pixmaps.Clear();
+}
+
 // If pushedBitmap is NULL, a reversed version of bitmap is
 // created and used as the pushed/toggled image.
 // If toggle is TRUE, the button toggles between the two states.
@@ -319,3 +404,180 @@ wxToolBarTool *wxToolBar::AddTool(int index, const wxBitmap& bitmap, const wxBit
   return tool;
 }
 
+int wxToolBar::FindIndexForWidget(WXWidget w)
+{
+    wxNode* node = m_widgets.First();
+    while (node)
+    {
+        WXWidget widget = (WXWidget) node->Data();
+        if (widget == w)
+            return (int) node->key.integer;
+        node = node->Next();
+    }
+    return -1;
+}
+
+WXWidget wxToolBar::FindWidgetForIndex(int index)
+{
+    wxNode* node = m_widgets.Find((long) index);
+    if (!node)
+        return (WXWidget) 0;
+    else
+        return (WXWidget) node->Data();
+}
+
+void wxToolButtonCallback (Widget w, XtPointer clientData,
+                   XtPointer ptr)
+{
+    wxToolBar *toolBar = (wxToolBar *) clientData;
+    int index = toolBar->FindIndexForWidget((WXWidget) w);
+
+    if (index != -1)
+    {
+        wxNode *node = toolBar->GetTools().Find((long)index);
+        if (!node)
+            return;
+        wxToolBarTool *tool = (wxToolBarTool *)node->Data();
+        if (tool->m_isToggle)
+            tool->m_toggleState = toolBar->GetToolState(index);
+
+        (void) toolBar->OnLeftClick(index, tool->m_toggleState);
+    }
+
+}
+
+// Creates a bitmap with transparent areas drawn in
+// the given colour.
+wxBitmap wxCreateMaskedBitmap(wxBitmap& bitmap, wxColour& colour)
+{
+    wxBitmap newBitmap(bitmap.GetWidth(),
+                       bitmap.GetHeight(),
+                       bitmap.GetDepth());
+    wxMemoryDC destDC;
+    wxMemoryDC srcDC;
+    srcDC.SelectObject(bitmap);
+    destDC.SelectObject(newBitmap);
+
+    wxBrush brush(colour, wxSOLID);
+    destDC.SetOptimization(FALSE);
+    destDC.SetBackground(brush);
+    destDC.Clear();
+    destDC.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE);
+
+    return newBitmap;
+}
+
+
+static void wxToolButtonPopupCallback (Widget w, XtPointer client_data,
+                     XEvent *event, Boolean *continue_to_dispatch)
+{
+    // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
+    int delayMilli = 800;
+    wxToolBar* toolBar = (wxToolBar*) client_data;
+
+    int index = toolBar->FindIndexForWidget((WXWidget) w);
+
+    if (index != -1)
+    {
+        wxNode *node = toolBar->GetTools().Find((long)index);
+        if (!node)
+            return;
+        wxToolBarTool *tool = (wxToolBarTool *)node->Data();
+        wxString str(toolBar->GetToolShortHelp(index));
+        if (str.IsNull() || str == "")
+            return;
+
+        if (!wxTheToolBarTimer)
+          wxTheToolBarTimer = new wxToolBarTimer;
+
+       wxToolBarTimer::buttonWidget = w;
+       wxToolBarTimer::helpString = str;
+
+
+    /************************************************************/
+    /* Popup help label                                         */
+    /************************************************************/
+    if (event->type == EnterNotify)
+    {
+        if (wxToolBarTimer::help_popup != (Widget) 0)
+        {
+            XtDestroyWidget (wxToolBarTimer::help_popup);
+            XtPopdown (wxToolBarTimer::help_popup);
+       }
+        wxToolBarTimer::help_popup = (Widget) 0;
+
+        // One shot
+        wxTheToolBarTimer->Start(delayMilli, TRUE);
+
+    }
+    /************************************************************/
+    /* Popdown help label                                       */
+    /************************************************************/
+    else if (event->type == LeaveNotify)
+    {
+        if (wxTheToolBarTimer)
+            wxTheToolBarTimer->Stop();
+        if (wxToolBarTimer::help_popup != (Widget) 0)
+        {
+            XtDestroyWidget (wxToolBarTimer::help_popup);
+            XtPopdown (wxToolBarTimer::help_popup);
+       }
+        wxToolBarTimer::help_popup = (Widget) 0;
+    }
+    }
+}
+
+void wxToolBarTimer::Notify()
+{
+    Position x, y;
+
+        /************************************************************/
+        /* Create shell without window decorations                  */
+        /************************************************************/
+        help_popup = XtVaCreatePopupShell ("shell", 
+                                           overrideShellWidgetClass, (Widget) wxTheApp->GetTopLevelWidget(), 
+                                           NULL);
+
+        /************************************************************/
+        /* Get absolute position on display of toolbar button       */
+        /************************************************************/
+        XtTranslateCoords (buttonWidget,
+                           (Position) 0, 
+                           (Position) 0, 
+                           &x, &y);
+
+        // Move the tooltip more or less above the button
+        int yOffset = 20; // TODO: What should be really?
+        y -= yOffset;
+        if (y < yOffset) y = 0;
+
+        /************************************************************/
+        /* Set the position of the help popup                       */
+        /************************************************************/
+        XtVaSetValues (help_popup, 
+                       XmNx, (Position) x, 
+                       XmNy, (Position) y, 
+                       NULL);
+        
+        /************************************************************/
+        /* Create help label                                        */
+        /************************************************************/
+        XmString text = XmStringCreateSimple ((char*) (const char*) helpString);
+        XtVaCreateManagedWidget ("help_label", 
+                                 xmLabelWidgetClass, help_popup, 
+                                 XmNlabelString, text,
+                                 XtVaTypedArg, 
+                                 XmNforeground, XtRString, "black", 
+                                                strlen("black")+1,      
+                                 XtVaTypedArg, 
+                                 XmNbackground, XtRString, "LightGoldenrod", 
+                                                strlen("LightGoldenrod")+1, 
+                                 NULL);
+        XmStringFree (text);
+
+        /************************************************************/
+        /* Popup help label                                         */
+        /************************************************************/
+        XtPopup (help_popup, XtGrabNone);
+}
+