From 50414e24a7aa082f2569666421d3ee1ea581a3cd Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Fri, 18 Sep 1998 21:33:46 +0000 Subject: [PATCH] Some more wxMotif stuff: menus git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@753 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- distrib/msw/generic.rsp | 3 +- include/wx/defs.h | 1 + include/wx/menuitem.h | 108 +---- include/wx/motif/frame.h | 9 +- include/wx/motif/menu.h | 34 +- include/wx/motif/private.h | 5 + include/wx/motif/window.h | 35 +- src/motif/frame.cpp | 49 +-- src/motif/menu.cpp | 485 ++++++++++++++++++---- src/motif/menuitem.cpp | 282 ++++++++++++- src/motif/utils.cpp | 322 +++++++++++++++ src/motif/window.cpp | 801 ++++++++++++++++++++++++++++++++++++- 12 files changed, 1894 insertions(+), 240 deletions(-) diff --git a/distrib/msw/generic.rsp b/distrib/msw/generic.rsp index b21b78523a..73dd6266e9 100644 --- a/distrib/msw/generic.rsp +++ b/distrib/msw/generic.rsp @@ -1,4 +1,5 @@ -distrib/*.* +distrib/msw/*.rsp +distrib/msw/*.bat docs/readme.txt docs/install.txt diff --git a/include/wx/defs.h b/include/wx/defs.h index b57ca70842..dcc47eedef 100644 --- a/include/wx/defs.h +++ b/include/wx/defs.h @@ -893,6 +893,7 @@ typedef void* WXColormap; typedef void WXDisplay; typedef void WXEvent; typedef void* WXCursor; +typedef void* WXPixmap; #endif #endif diff --git a/include/wx/menuitem.h b/include/wx/menuitem.h index 5d32a5f426..ffb693fe0c 100644 --- a/include/wx/menuitem.h +++ b/include/wx/menuitem.h @@ -1,95 +1,19 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: menuitem.h -// Purpose: wxMenuItem class -// Author: Vadim Zeitlin -// Modified by: -// Created: 11.11.97 -// RCS-ID: $Id$ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MENUITEM_H -#define _MENUITEM_H - -#ifdef __GNUG__ -#pragma interface "menuitem.h" -#endif - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/setup.h" - -// an exception to the general rule that a normal header doesn't include other -// headers - only because ownerdrw.h is not always included and I don't want -// to write #ifdef's everywhere... -#if USE_OWNER_DRAWN -#include "wx/ownerdrw.h" +#ifndef _WX_MENUITEM_H_BASE_ +#define _WX_MENUITEM_H_BASE_ + +#if defined(__WXMSW__) +#include "wx/msw/menuitem.h" +#elif defined(__WXMOTIF__) +#include "wx/motif/menuitem.h" +#elif defined(__WXGTK__) +#include "wx/gtk/menuitem.h" +#elif defined(__WXQT__) +#include "wx/qt/menuitem.h" +#elif defined(__WXMAC__) +#include "wx/mac/menuitem.h" +#elif defined(__WXSTUBS__) +#include "wx/stubs/menuitem.h" #endif -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// id for a separator line in the menu (invalid for normal item) -#define ID_SEPARATOR (-1) - -// ---------------------------------------------------------------------------- -// wxMenuItem: an item in the menu, optionally implements owner-drawn behaviour -// ---------------------------------------------------------------------------- -class WXDLLEXPORT wxMenuItem: public wxObject -#if USE_OWNER_DRAWN - , public wxOwnerDrawn #endif -{ -DECLARE_DYNAMIC_CLASS(wxMenuItem) - -public: - // ctor & dtor - wxMenuItem(wxMenu *pParentMenu = NULL, int id = ID_SEPARATOR, - const wxString& strName = "", const wxString& wxHelp = "", - bool bCheckable = FALSE, wxMenu *pSubMenu = NULL); - virtual ~wxMenuItem(); - - // accessors (some more are inherited from wxOwnerDrawn or are below) - bool IsSeparator() const { return m_idItem == ID_SEPARATOR; } - bool IsEnabled() const { return m_bEnabled; } - bool IsChecked() const { return m_bChecked; } - - int GetId() const { return m_idItem; } - const wxString& GetHelp() const { return m_strHelp; } - wxMenu *GetSubMenu() const { return m_pSubMenu; } - - // operations - void SetName(const wxString& strName) { m_strName = strName; } - void SetHelp(const wxString& strHelp) { m_strHelp = strHelp; } - - void Enable(bool bDoEnable = TRUE); - void Check(bool bDoCheck = TRUE); - - void DeleteSubMenu(); - -private: - int m_idItem; // numeric id of the item - wxString m_strHelp; // associated help string - wxMenu *m_pSubMenu, // may be NULL - *m_pParentMenu; // menu this item is contained in - bool m_bEnabled, // enabled or greyed? - m_bChecked; // checked? (only if checkable) - -#if USE_OWNER_DRAWN - // wxOwnerDrawn base class already has these variables - nothing to do - -#else //!owner drawn - bool m_bCheckable; // can be checked? - wxString m_strName; // name or label of the item - -public: - const wxString& GetName() const { return m_strName; } - bool IsCheckable() const { return m_bCheckable; } -#endif //owner drawn -}; - -#endif //_MENUITEM_H \ No newline at end of file + // _WX_MENUITEM_H_BASE_ diff --git a/include/wx/motif/frame.h b/include/wx/motif/frame.h index bb719ddac5..3373854b2b 100644 --- a/include/wx/motif/frame.h +++ b/include/wx/motif/frame.h @@ -147,9 +147,12 @@ public: //// Motif-specific WXWidget GetMenuBarWidget() const ; - WXWidget GetShellWidget() const { return m_frameShell; } - WXWidget GetWorkAreaWidget() const { return m_workArea; } - WXWidget GetClientAreaWidget() const { return m_clientArea; } + inline WXWidget GetShellWidget() const { return m_frameShell; } + inline WXWidget GetWorkAreaWidget() const { return m_workArea; } + inline WXWidget GetClientAreaWidget() const { return m_clientArea; } + + // The widget that can have children on it + WXWidget GetClientWidget() const; bool GetVisibleStatus() const { return m_visibleStatus; } bool PreResize(); diff --git a/include/wx/motif/menu.h b/include/wx/motif/menu.h index dd34942155..f89f733d11 100644 --- a/include/wx/motif/menu.h +++ b/include/wx/motif/menu.h @@ -90,7 +90,27 @@ public: //// Motif-specific inline WXWidget GetButtonWidget() const { return m_buttonWidget; } + inline void SetButtonWidget(WXWidget buttonWidget) { m_buttonWidget = buttonWidget; } inline WXWidget GetMainWidget() const { return m_menuWidget; } + inline wxMenu* GetParent() const { return m_menuParent; } + inline int GetId() const { return m_menuId; } + inline void SetId(int id) { m_menuId = id; } + inline void SetMenuBar(wxMenuBar* menuBar) { m_menuBar = menuBar; } + inline wxMenuBar* GetMenuBar() const { return m_menuBar; } + + void CreatePopup (WXWidget logicalParent, int x, int y); + void DestroyPopup (void); + void ShowPopup (int x, int y); + void HidePopup (void); + + WXWidget CreateMenu(wxMenuBar *menuBar, WXWidget parent, wxMenu *topMenu, + const wxString& title = "", bool isPulldown = FALSE); + + // For popups, need to destroy, then recreate menu for a different (or + // possibly same) window, since the parent may change. + void DestroyMenu(bool full); + WXWidget FindMenuItem(int id, wxMenuItem **it = NULL) const; + public: wxFunction m_callback; @@ -107,7 +127,7 @@ public: WXWidget m_popupShell; // For holding the popup shell widget WXWidget m_buttonWidget; // The actual string, so we can grey it etc. int m_menuId; - wxMenu* m_topMenu ; + wxMenu* m_topLevelMenu ; wxMenu* m_menuParent; bool m_ownedByMenuBar; }; @@ -157,14 +177,22 @@ class WXDLLEXPORT wxMenuBar: public wxEvtHandler inline int GetMenuCount() const { return m_menuCount; } inline wxMenu* GetMenu(int i) const { return m_menus[i]; } + //// Motif-specific + inline wxFrame* GetMenuBarFrame() const { return m_menuBarFrame; } + inline void SetMenuBarFrame(wxFrame* frame) { m_menuBarFrame = frame; } + inline WXWidget GetMainWidget() const { return m_mainWidget; } + inline void SetMainWidget(WXWidget widget) { m_mainWidget = widget; } + public: wxEvtHandler * m_eventHandler; int m_menuCount; wxMenu ** m_menus; wxString * m_titles; wxFrame * m_menuBarFrame; -/* TODO: data that represents the actual menubar when created. - */ + + //// Motif-specific + WXWidget m_mainWidget; + }; #endif // _WX_MENU_H_ diff --git a/include/wx/motif/private.h b/include/wx/motif/private.h index 7a05f643bb..3a6732a7cb 100644 --- a/include/wx/motif/private.h +++ b/include/wx/motif/private.h @@ -23,6 +23,11 @@ extern wxHashTable *wxWidgetHashTable; extern void wxDeleteWindowFromTable(Widget w); extern wxWindow *wxGetWindowFromTable(Widget w); extern bool wxAddWindowToTable(Widget w, wxWindow *win); +extern char wxFindMnemonic(const char* s); +extern char * wxFindAccelerator (char *s); +extern XmString wxFindAcceleratorText (char *s); +extern int wxCharCodeXToWX(KeySym keySym); +extern KeySym wxCharCodeWXToX(int id); #endif // _WX_PRIVATE_H_ diff --git a/include/wx/motif/window.h b/include/wx/motif/window.h index 9510f97fd0..cbe336c021 100644 --- a/include/wx/motif/window.h +++ b/include/wx/motif/window.h @@ -448,7 +448,13 @@ public: // to the window via validators. virtual void InitDialog(); - /// MOTIF-specific + /// Motif-specific + + void CanvasGetSize(int* width, int* height) const; // If have drawing area + void CanvasGetClientSize(int *width, int *height) const; + void CanvasGetPosition(int *x, int *y) const; // If have drawing area + void CanvasSetClientSize(int width, int size); + void CanvasSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); // Gives window a chance to do something in response to a size // message, e.g. arrange status bar, toolbar etc. @@ -456,12 +462,18 @@ public: // Get main widget for this window virtual WXWidget GetMainWidget() const; + // Get the client widget for this window (something we can + // create other windows on) + virtual WXWidget GetClientWidget() const; virtual void SetMainWidget(WXWidget w) { m_mainWidget = w; } // Get the underlying X window and display virtual WXWindow GetXWindow() const; virtual WXDisplay *GetXDisplay() const; + // Generates a paint event + virtual void DoPaint(); + //////////////////////////////////////////////////////////////////////// //// PROTECTED DATA protected: @@ -507,15 +519,32 @@ public: int m_returnCode; public: - /// MOTIF-specific + /// Motif-specific bool m_button1Pressed; bool m_button2Pressed; bool m_button3Pressed; - + // For double-click detection + long m_lastTS; // last timestamp + int m_lastButton; // last pressed button + wxList m_updateRects; // List of wxRectangles representing damaged region protected: WXWidget m_mainWidget; + WXWidget m_hScrollBar; + WXWidget m_vScrollBar; + WXWidget m_borderWidget; + WXWidget m_scrolledWindow; + WXWidget m_drawingArea; bool m_winCaptured; bool m_isShown; + bool m_hScroll; + bool m_vScroll; + bool m_hScrollingEnabled; + bool m_vScrollingEnabled; + WXPixmap m_backingPixmap; + int m_pixmapWidth; + int m_pixmapHeight; + int m_pixmapOffsetX; + int m_pixmapOffsetY; DECLARE_EVENT_TABLE() }; diff --git a/src/motif/frame.cpp b/src/motif/frame.cpp index 43727d9930..516b5a6765 100644 --- a/src/motif/frame.cpp +++ b/src/motif/frame.cpp @@ -579,6 +579,9 @@ void wxFrame::SetStatusWidths(int n, const int widths_field[]) void wxFrame::PositionStatusBar() { + if (!m_frameStatusBar) + return; + int w, h; GetClientSize(&w, &h); int sw, sh; @@ -586,16 +589,14 @@ void wxFrame::PositionStatusBar() // Since we wish the status bar to be directly under the client area, // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS. - m_frameStatusBar->SetSize(0, h, w, sh); + m_frameStatusBar->SetSize(0-sh, h, w, sh); } WXWidget wxFrame::GetMenuBarWidget() const { - /* TODO if (GetMenuBar()) return GetMenuBar()->GetMainWidget(); else - */ return (WXWidget) NULL; } @@ -612,8 +613,6 @@ void wxFrame::SetMenuBar(wxMenuBar *menuBar) m_frameMenuBar = menuBar; - // TODO -#if 0 Widget menuBarW = XmCreateMenuBar ((Widget) m_frameWidget, "MenuBar", NULL, 0); m_frameMenuBar->SetMainWidget( (WXWidget) menuBarW); @@ -621,12 +620,13 @@ void wxFrame::SetMenuBar(wxMenuBar *menuBar) for (i = 0; i < menuBar->GetMenuCount(); i++) { wxMenu *menu = menuBar->GetMenu(i); - menu->SetButtonWidget(menu->CreateMenu (menuBar, menuBarW, menu, menuBar->m_titles[i], TRUE); + wxString title(menuBar->m_titles[i]); + menu->SetButtonWidget(menu->CreateMenu (menuBar, menuBarW, menu, title, TRUE)); /* * COMMENT THIS OUT IF YOU DON'T LIKE A RIGHT-JUSTIFIED HELP MENU */ - wxStripMenuCodes (menuBar->m_titles[i], wxBuffer); + wxStripMenuCodes ((char*) (const char*) title, wxBuffer); if (strcmp (wxBuffer, "Help") == 0) XtVaSetValues ((Widget) menuBarW, XmNmenuHelpWidget, (Widget) menu->GetButtonWidget(), NULL); @@ -635,7 +635,6 @@ void wxFrame::SetMenuBar(wxMenuBar *menuBar) XtRealizeWidget ((Widget) menuBarW); XtManageChild ((Widget) menuBarW); menuBar->SetMenuBarFrame(this); -#endif } void wxFrame::Fit() @@ -1016,37 +1015,15 @@ static void wxFrameMapProc(Widget frameShell, XtPointer clientData, //// Motif-specific bool wxFrame::PreResize() { - /* TODO - // Set status line, if any - if (status_line_exists) - { - Dimension clientW, clientH; - XtVaGetValues(clientArea, XmNwidth, &clientW, XmNheight, &clientH, NULL); - Dimension xx, yy; - XtVaGetValues(statusLineWidget, XmNwidth, &xx, XmNheight, &yy, NULL); - - XtUnmanageChild(statusLineWidget); - XtVaSetValues(statusLineWidget, XmNx, 0, XmNy, clientH - yy, XmNwidth, clientW, NULL); - - if (statusLineForm) - XtVaSetValues(statusLineForm, XmNwidth, clientW, NULL); - - XtManageChild(statusLineWidget); - } - - int width, height; - GetSize(&width, &height); - - if (width == lastWidth && height == lastHeight) - return FALSE; - else - { - return TRUE; - } - */ + PositionStatusBar(); return TRUE; } +WXWidget wxFrame::GetClientWidget() const +{ + return m_clientArea; +} + void wxCloseFrameCallback(Widget widget, XtPointer client_data, XmAnyCallbackStruct *cbs) { wxFrame *frame = (wxFrame *)client_data; diff --git a/src/motif/menu.cpp b/src/motif/menu.cpp index 468ed194e4..53df95214b 100644 --- a/src/motif/menu.cpp +++ b/src/motif/menu.cpp @@ -26,6 +26,8 @@ #include "wx/menuitem.h" #include "wx/log.h" #include "wx/utils.h" +#include "wx/app.h" +#include "wx/frame.h" #include #include @@ -37,17 +39,12 @@ #include #include +#include "wx/motif/private.h" + // other standard headers // ---------------------- #include -void wxMenuItemCallback (Widget w, XtPointer clientData, - XtPointer ptr); -void wxMenuItemArmCallback (Widget w, XtPointer clientData, - XtPointer ptr); -void wxMenuItemDisarmCallback (Widget w, XtPointer clientData, - XtPointer ptr); - #if !USE_SHARED_LIBRARY IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler) IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler) @@ -74,36 +71,46 @@ wxMenu::wxMenu(const wxString& title, const wxFunction func) m_popupShell = (WXWidget) NULL; m_buttonWidget = (WXWidget) NULL; m_menuId = 0; - m_topMenu = (wxMenu*) NULL; + m_topLevelMenu = (wxMenu*) NULL; m_ownedByMenuBar = FALSE; m_menuParent = (wxMenu*) NULL; if (m_title != "") { - Append(-2, m_title) ; + Append(ID_SEPARATOR, m_title) ; AppendSeparator() ; } Callback(func); - - // TODO create menu } // The wxWindow destructor will take care of deleting the submenus. wxMenu::~wxMenu() { - // TODO destroy menu and children + if (m_menuWidget) + { + if (m_menuParent) + DestroyMenu(TRUE); + else + DestroyMenu(FALSE); + } + + // Not sure if this is right + if (m_menuParent && m_menuBar) + { + m_menuParent = NULL; + // m_menuBar = NULL; + } wxNode *node = m_menuItems.First(); while (node) { wxMenuItem *item = (wxMenuItem *)node->Data(); - // Delete child menus. - // Beware: they must not be appended to children list!!! - // (because order of delete is significant) + /* if (item->GetSubMenu()) item->DeleteSubMenu(); + */ wxNode *next = node->Next(); delete item; @@ -114,40 +121,47 @@ wxMenu::~wxMenu() void wxMenu::Break() { - // TODO + m_numColumns ++; } // function appends a new item or submenu to the menu void wxMenu::Append(wxMenuItem *pItem) { - // TODO - wxCHECK_RET( pItem != NULL, "can't append NULL item to the menu" ); m_menuItems.Append(pItem); + if (m_menuWidget) + pItem->CreateItem (m_menuWidget, m_menuBar, m_topLevelMenu); // this is a dynamic Append + m_noItems++; } void wxMenu::AppendSeparator() { - // TODO Append(new wxMenuItem(this, ID_SEPARATOR)); } // Pullright item -void wxMenu::Append(int Id, const wxString& label, wxMenu *SubMenu, +// N.B.: difference between old and new code. +// Old code stores subMenu in 'children' for later deletion, +// as well as in m_menuItems, whereas we only store it in +// m_menuItems here. What implications does this have? + +void wxMenu::Append(int id, const wxString& label, wxMenu *subMenu, const wxString& helpString) { - Append(new wxMenuItem(this, Id, label, helpString, FALSE, SubMenu)); + Append(new wxMenuItem(this, id, label, helpString, FALSE, subMenu)); + + subMenu->m_topLevelMenu = m_topLevelMenu; } // Ordinary menu item -void wxMenu::Append(int Id, const wxString& label, +void wxMenu::Append(int id, const wxString& label, const wxString& helpString, bool checkable) { // 'checkable' parameter is useless for Windows. - Append(new wxMenuItem(this, Id, label, helpString, checkable)); + Append(new wxMenuItem(this, id, label, helpString, checkable)); } void wxMenu::Delete(int id) @@ -156,7 +170,8 @@ void wxMenu::Delete(int id) wxMenuItem *item; int pos; - for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++) { + for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++) + { item = (wxMenuItem *)node->Data(); if (item->GetId() == id) break; @@ -165,18 +180,27 @@ void wxMenu::Delete(int id) if (!node) return; + item->DestroyItem(TRUE); + + // See also old code - don't know if this is needed (seems redundant). + /* + if (item->GetSubMenu()) { + item->subMenu->top_level_menu = item->GetSubMenu(); + item->subMenu->window_parent = NULL; + children->DeleteObject(item->GetSubMenu()); + } + */ + m_menuItems.DeleteNode(node); delete item; - - // TODO } -void wxMenu::Enable(int Id, bool Flag) +void wxMenu::Enable(int id, bool flag) { - wxMenuItem *item = FindItemForId(Id); + wxMenuItem *item = FindItemForId(id); wxCHECK_RET( item != NULL, "can't enable non-existing menu item" ); - item->Enable(Flag); + item->Enable(flag); } bool wxMenu::Enabled(int Id) const @@ -195,9 +219,9 @@ void wxMenu::Check(int Id, bool Flag) item->Check(Flag); } -bool wxMenu::Checked(int Id) const +bool wxMenu::Checked(int id) const { - wxMenuItem *item = FindItemForId(Id); + wxMenuItem *item = FindItemForId(id); wxCHECK( item != NULL, FALSE ); return item->IsChecked(); @@ -206,7 +230,21 @@ bool wxMenu::Checked(int Id) const void wxMenu::SetTitle(const wxString& label) { m_title = label ; - // TODO + + wxNode *node = m_menuItems.First (); + if (!node) + return; + + wxMenuItem *item = (wxMenuItem *) node->Data (); + Widget widget = (Widget) item->GetButtonWidget(); + if (!widget) + return; + + XmString title_str = XmStringCreateSimple ((char*) (const char*) label); + XtVaSetValues (widget, + XmNlabelString, title_str, + NULL); + // TODO: should we delete title_str now? } const wxString wxMenu::GetTitle() const @@ -216,25 +254,39 @@ const wxString wxMenu::GetTitle() const void wxMenu::SetLabel(int id, const wxString& label) { - wxMenuItem *item = FindItemForId(id) ; - if (item==NULL) - return; + wxMenuItem *item = FindItemForId(id); + if (item == (wxMenuItem*) NULL) + return; - if (item->GetSubMenu()==NULL) - { - // TODO - } - else - { - // TODO - } - item->SetName(label); + item->SetLabel(label); } -wxString wxMenu::GetLabel(int Id) const +wxString wxMenu::GetLabel(int id) const { - // TODO - return wxString("") ; + wxMenuItem *it = NULL; + WXWidget w = FindMenuItem (id, &it); + if (w) + { + XmString text; + char *s; + XtVaGetValues ((Widget) w, + XmNlabelString, &text, + NULL); + + if (XmStringGetLtoR (text, XmSTRING_DEFAULT_CHARSET, &s)) + { + wxString str(s); + XtFree (s); + return str; + } + else + { + XmStringFree (text); + return wxEmptyString; + } + } + else + return wxEmptyString; } // Finds the item id matching the given string, -1 if not found. @@ -332,8 +384,66 @@ void wxMenu::ProcessCommand(wxCommandEvent & event) bool wxWindow::PopupMenu(wxMenu *menu, int x, int y) { - // TODO + Widget widget = (Widget) GetMainWidget(); + + /* The menuId field seems to be usused, so we'll use it to + indicate whether a menu is popped up or not: + 0: Not currently created as a popup + -1: Created as a popup, but not active + 1: Active popup. + */ + + if (menu->GetParent() && (menu->GetId() != -1)) return FALSE; + + if (menu->GetMainWidget()) { + menu->DestroyMenu(TRUE); + } + + wxWindow *parent = this; + + menu->SetId(1); /* Mark as popped-up */ + menu->CreateMenu(NULL, widget, menu); + // menu->SetParent(parent); + // parent->children->Append(menu); // Store menu for later deletion + + Widget menuWidget = (Widget) menu->GetMainWidget(); + + int rootX = 0; + int rootY = 0; + + int deviceX = x; + int deviceY = y; + /* + if (this->IsKindOf(CLASSINFO(wxCanvas))) + { + wxCanvas *canvas = (wxCanvas *) this; + deviceX = canvas->GetDC ()->LogicalToDeviceX (x); + deviceY = canvas->GetDC ()->LogicalToDeviceY (y); + } + */ + + Display *display = XtDisplay (widget); + Window rootWindow = RootWindowOfScreen (XtScreen((Widget)widget)); + Window thisWindow = XtWindow (widget); + Window childWindow; + XTranslateCoordinates (display, thisWindow, rootWindow, (int) deviceX, (int) deviceY, + &rootX, &rootY, &childWindow); + + XButtonPressedEvent event; + event.type = ButtonPress; + event.button = 1; + + event.x = deviceX; + event.y = deviceY; + + event.x_root = rootX; + event.y_root = rootY; + + XmMenuPosition (menuWidget, &event); + XtManageChild (menuWidget); + + return TRUE; } // Menu Bar @@ -344,8 +454,6 @@ wxMenuBar::wxMenuBar() m_menus = NULL; m_titles = NULL; m_menuBarFrame = NULL; - - // TODO } wxMenuBar::wxMenuBar(int n, wxMenu *menus[], const wxString titles[]) @@ -358,8 +466,6 @@ wxMenuBar::wxMenuBar(int n, wxMenu *menus[], const wxString titles[]) for ( i = 0; i < n; i++ ) m_titles[i] = titles[i]; m_menuBarFrame = NULL; - - // TODO } wxMenuBar::~wxMenuBar() @@ -371,8 +477,6 @@ wxMenuBar::~wxMenuBar() } delete[] m_menus; delete[] m_titles; - - // TODO } // Must only be used AFTER menu has been attached to frame, @@ -383,8 +487,7 @@ void wxMenuBar::Enable(int id, bool flag) wxMenuItem *item = FindItemForId(id, &itemMenu) ; if (!item) return; - - // TODO + item->Enable(flag); } void wxMenuBar::EnableTop(int pos, bool flag) @@ -404,7 +507,7 @@ void wxMenuBar::Check(int id, bool flag) if (!item->IsCheckable()) return ; - // TODO + item->Check(flag); } bool wxMenuBar::Checked(int id) const @@ -414,8 +517,7 @@ bool wxMenuBar::Checked(int id) const if (!item) return FALSE; - // TODO - return FALSE; + return item->IsChecked(); } bool wxMenuBar::Enabled(int id) const @@ -425,11 +527,9 @@ bool wxMenuBar::Enabled(int id) const if (!item) return FALSE; - // TODO - return FALSE ; + return item->IsEnabled(); } - void wxMenuBar::SetLabel(int id, const wxString& label) { wxMenu *itemMenu = NULL; @@ -438,7 +538,7 @@ void wxMenuBar::SetLabel(int id, const wxString& label) if (!item) return; - // TODO + item->SetLabel(label); } wxString wxMenuBar::GetLabel(int id) const @@ -449,31 +549,81 @@ wxString wxMenuBar::GetLabel(int id) const if (!item) return wxString(""); - // TODO - return wxString("") ; + return item->GetLabel(); } void wxMenuBar::SetLabelTop(int pos, const wxString& label) { - // TODO + wxASSERT( (pos < m_menuCount) ); + + Widget w = (Widget) m_menus[pos]->GetButtonWidget(); + if (w) + { + XmString label_str = XmStringCreateSimple ((char*) (const char*) label); + XtVaSetValues (w, + XmNlabelString, label_str, + NULL); + XmStringFree (label_str); + } } wxString wxMenuBar::GetLabelTop(int pos) const { - // TODO - return wxString(""); + wxASSERT( (pos < m_menuCount) ); + + Widget w = (Widget) m_menus[pos]->GetButtonWidget(); + if (w) + { + XmString text; + char *s; + XtVaGetValues (w, + XmNlabelString, &text, + NULL); + + if (XmStringGetLtoR (text, XmSTRING_DEFAULT_CHARSET, &s)) + { + wxString str(s); + XtFree (s); + return str; + } + else + { + return wxEmptyString; + } + } + else + return wxEmptyString; + } -bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos) +bool wxMenuBar::OnDelete(wxMenu *menu, int pos) { - // TODO - return FALSE; + // Only applies to dynamic deletion (when set in frame) + if (!m_menuBarFrame) + return TRUE; + + menu->DestroyMenu(TRUE); + return TRUE; } -bool wxMenuBar::OnAppend(wxMenu *a_menu, const char *title) +bool wxMenuBar::OnAppend(wxMenu *menu, const char *title) { - // TODO - return FALSE; + // Only applies to dynamic append (when set in frame) + if (!m_menuBarFrame) + return TRUE; + + // Probably should be an assert here + if (menu->GetParent()) + return FALSE; + + // Has already been appended + if (menu->GetButtonWidget()) + return FALSE; + + WXWidget w = menu->CreateMenu(this, GetMainWidget(), menu, title, TRUE); + menu->SetButtonWidget(w); + + return TRUE; } void wxMenuBar::Append (wxMenu * menu, const wxString& title) @@ -504,7 +654,8 @@ void wxMenuBar::Append (wxMenu * menu, const wxString& title) m_menus[m_menuCount - 1] = (wxMenu *)menu; m_titles[m_menuCount - 1] = title; - // TODO + menu->SetMenuBar(this); + menu->SetParent(this); } void wxMenuBar::Delete(wxMenu * menu, int i) @@ -531,7 +682,7 @@ void wxMenuBar::Delete(wxMenu * menu, int i) if (!OnDelete(menu, ii)) return; - menu->SetParent(NULL); + menu->SetParent((wxEvtHandler*) NULL); -- m_menuCount; for (j = ii; j < m_menuCount; j++) @@ -558,7 +709,7 @@ int wxMenuBar::FindMenuItem (const wxString& menuString, const wxString& itemStr return -1; } -wxMenuItem *wxMenuBar::FindItemForId (int Id, wxMenu ** itemMenu) const +wxMenuItem *wxMenuBar::FindItemForId (int id, wxMenu ** itemMenu) const { if (itemMenu) *itemMenu = NULL; @@ -566,33 +717,199 @@ wxMenuItem *wxMenuBar::FindItemForId (int Id, wxMenu ** itemMenu) const wxMenuItem *item = NULL; int i; for (i = 0; i < m_menuCount; i++) - if ((item = m_menus[i]->FindItemForId (Id, itemMenu))) + if ((item = m_menus[i]->FindItemForId (id, itemMenu))) return item; return NULL; } -void wxMenuBar::SetHelpString (int Id, const wxString& helpString) +void wxMenuBar::SetHelpString (int id, const wxString& helpString) { int i; for (i = 0; i < m_menuCount; i++) { - if (m_menus[i]->FindItemForId (Id)) + if (m_menus[i]->FindItemForId (id)) { - m_menus[i]->SetHelpString (Id, helpString); + m_menus[i]->SetHelpString (id, helpString); return; } } } -wxString wxMenuBar::GetHelpString (int Id) const +wxString wxMenuBar::GetHelpString (int id) const { int i; for (i = 0; i < m_menuCount; i++) { - if (m_menus[i]->FindItemForId (Id)) - return wxString(m_menus[i]->GetHelpString (Id)); + if (m_menus[i]->FindItemForId (id)) + return wxString(m_menus[i]->GetHelpString (id)); } return wxString(""); } +//// Motif-specific + +extern wxApp *wxTheApp; +static XtWorkProcId WorkProcMenuId; + +/* Since PopupMenu under Motif stills grab right mouse button events + * after it was closed, we need to delete the associated widgets to + * allow next PopUpMenu to appear... + */ + +int PostDeletionOfMenu( XtPointer* clientData ) +{ + XtRemoveWorkProc(WorkProcMenuId); + wxMenu *menu = (wxMenu *)clientData; + + if (menu->GetMainWidget()) { + wxList& list = menu->GetParent()->GetItems(); + list.DeleteObject(menu); + menu->DestroyMenu(TRUE); + } + /* Mark as no longer popped up */ + menu->m_menuId = -1; + return TRUE; +} + +void +wxMenuPopdownCallback(Widget w, XtPointer clientData, + XtPointer ptr) +{ + wxMenu *menu = (wxMenu *)clientData; + + // Added by JOREL Jean-Charles + /* Since Callbacks of MenuItems are not yet processed, we put a + * background job which will be done when system will be idle. + * What awful hack!! :( + */ + + WorkProcMenuId = XtAppAddWorkProc( + (XtAppContext) wxTheApp->GetAppContext(), + (XtWorkProc) PostDeletionOfMenu, + (XtPointer) menu ); + // Apparently not found in Motif headers + // XtVaSetValues( w, XmNpopupEnabled, XmPOPUP_DISABLED, NULL ); +} + +/* + * Create a popup or pulldown menu. + * Submenus of a popup will be pulldown. + * + */ + +WXWidget wxMenu::CreateMenu (wxMenuBar * menuBar, WXWidget parent, wxMenu * topMenu, const wxString& title, bool pullDown) +{ + Widget menu = (Widget) 0; + Widget buttonWidget = (Widget) 0; + Arg args[5]; + XtSetArg (args[0], XmNnumColumns, m_numColumns); + XtSetArg (args[1], XmNpacking, XmPACK_COLUMN); + + if (!pullDown) + { + menu = XmCreatePopupMenu ((Widget) parent, "popup", args, 2); + XtAddCallback(menu, + XmNunmapCallback, + (XtCallbackProc)wxMenuPopdownCallback, + (XtPointer)this); + } + else + { + char mnem = wxFindMnemonic (title); + wxStripMenuCodes ((char*) (const char*) title, wxBuffer); + + menu = XmCreatePulldownMenu ((Widget) parent, "pulldown", args, 2); + + XmString label_str = XmStringCreateSimple (wxBuffer); + buttonWidget = XtVaCreateManagedWidget (wxBuffer, +#if USE_GADGETS + xmCascadeButtonGadgetClass, (Widget) parent, +#else + xmCascadeButtonWidgetClass, (Widget) parent, +#endif + XmNlabelString, label_str, + XmNsubMenuId, menu, + NULL); + + if (mnem != 0) + XtVaSetValues (buttonWidget, XmNmnemonic, mnem, NULL); + + XmStringFree (label_str); + } + + m_menuWidget = (WXWidget) menu; + + m_menuBar = menuBar; + m_topLevelMenu = topMenu; + + for (wxNode * node = m_menuItems.First (); node; node = node->Next ()) + { + wxMenuItem *item = (wxMenuItem *) node->Data (); + item->CreateItem (menu, menuBar, topMenu); + } + + return buttonWidget; +} + +// Destroys the Motif implementation of the menu, +// but maintains the wxWindows data structures so we can +// do a CreateMenu again. +void wxMenu::DestroyMenu (bool full) +{ + for (wxNode * node = m_menuItems.First (); node; node = node->Next ()) + { + wxMenuItem *item = (wxMenuItem *) node->Data (); + item->SetMenuBar((wxMenuBar*) NULL); + + item->DestroyItem(full); + } // for() + + if (m_buttonWidget) + { + if (full) + { + XtVaSetValues((Widget) m_buttonWidget, XmNsubMenuId, NULL, NULL); + XtDestroyWidget ((Widget) m_buttonWidget); + m_buttonWidget = (WXWidget) 0; + } + } + if (m_menuWidget && full) + { + XtDestroyWidget((Widget) m_menuWidget); + m_menuWidget = (WXWidget) NULL; + } +} + +WXWidget wxMenu::FindMenuItem (int id, wxMenuItem ** it) const +{ + if (id == m_menuId) + { + if (it) + *it = (wxMenuItem*) NULL; + return m_buttonWidget; + } + for (wxNode * node = m_menuItems.First (); node; node = node->Next ()) + { + wxMenuItem *item = (wxMenuItem *) node->Data (); + if (item->GetId() == id) + { + if (it) + *it = item; + return item->GetButtonWidget(); + } + + if (item->GetSubMenu()) + { + WXWidget w = item->GetSubMenu()->FindMenuItem (id, it); + if (w) + { + return w; + } + } + } // for() + + if (it) + *it = (wxMenuItem*) NULL; + return (WXWidget) NULL; +} diff --git a/src/motif/menuitem.cpp b/src/motif/menuitem.cpp index 619ccde103..7ce6558e9b 100644 --- a/src/motif/menuitem.cpp +++ b/src/motif/menuitem.cpp @@ -15,6 +15,27 @@ #include "wx/menu.h" #include "wx/menuitem.h" +#include "wx/utils.h" +#include "wx/frame.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wx/motif/private.h" + +void wxMenuItemCallback (Widget w, XtPointer clientData, + XtPointer ptr); +void wxMenuItemArmCallback (Widget w, XtPointer clientData, + XtPointer ptr); +void wxMenuItemDisarmCallback (Widget w, XtPointer clientData, + XtPointer ptr); // ============================================================================ // implementation @@ -39,9 +60,9 @@ wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id, const wxString& strName, const wxString& strHelp, bool bCheckable, wxMenu *pSubMenu) : + m_strHelp(strHelp), m_bCheckable(bCheckable), - m_strName(strName), - m_strHelp(strHelp) + m_strName(strName) { wxASSERT( pParentMenu != NULL ); @@ -49,6 +70,11 @@ wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id, m_pSubMenu = pSubMenu; m_idItem = id; m_bEnabled = TRUE; + + //// Motif-specific + m_menuBar = NULL; + m_buttonWidget = (WXWidget) NULL; + m_topMenu = NULL; } wxMenuItem::~wxMenuItem() @@ -72,13 +98,19 @@ void wxMenuItem::DeleteSubMenu() void wxMenuItem::Enable(bool bDoEnable) { - if ( m_bEnabled != bDoEnable ) { - if ( m_pSubMenu == NULL ) { // normal menu item - // TODO + if ( m_bEnabled != bDoEnable ) + { + if ( m_pSubMenu == NULL ) + { // normal menu item + if (m_buttonWidget) + XtSetSensitive( (Widget) m_buttonWidget, (Boolean) bDoEnable); } else // submenu { - // TODO + // Maybe we should apply this to all items in the submenu? + // Or perhaps it works anyway. + if (m_buttonWidget) + XtSetSensitive( (Widget) m_buttonWidget, (Boolean) bDoEnable); } m_bEnabled = bDoEnable; @@ -89,8 +121,240 @@ void wxMenuItem::Check(bool bDoCheck) { wxCHECK_RET( IsCheckable(), "only checkable items may be checked" ); - if ( m_bChecked != bDoCheck ) { - // TODO + if ( m_bChecked != bDoCheck ) + { + if (m_buttonWidget && XtIsSubclass ((Widget) m_buttonWidget, xmToggleButtonGadgetClass)) + { + XtVaSetValues ( (Widget) m_buttonWidget, XmNset, (Boolean) bDoCheck, NULL); + } m_bChecked = bDoCheck; } -} \ No newline at end of file +} + +//// Motif-specific + +void wxMenuItem::CreateItem (WXWidget menu, wxMenuBar * menuBar, wxMenu * topMenu) +{ + m_menuBar = menuBar; + m_topMenu = topMenu; + + if (GetId() == -2) + { + // Id=-2 identifies a Title item. + wxStripMenuCodes ((char*) (const char*) m_strName, wxBuffer); + m_buttonWidget = (WXWidget) XtVaCreateManagedWidget (wxBuffer, + xmLabelGadgetClass, (Widget) menu, NULL); + } + else if ((!m_strName.IsNull() && m_strName != "") && (!m_pSubMenu)) + { + wxStripMenuCodes ((char*) (const char*) m_strName, wxBuffer); + if (IsCheckable()) + { + m_buttonWidget = (WXWidget) XtVaCreateManagedWidget (wxBuffer, + xmToggleButtonGadgetClass, (Widget) menu, + NULL); + XtVaSetValues ((Widget) m_buttonWidget, XmNset, (Boolean) IsChecked(), NULL); + } + else + m_buttonWidget = (WXWidget) XtVaCreateManagedWidget (wxBuffer, + xmPushButtonGadgetClass, (Widget) menu, + NULL); + char mnem = wxFindMnemonic (m_strName); + if (mnem != 0) + XtVaSetValues ((Widget) m_buttonWidget, XmNmnemonic, mnem, NULL); + + //// TODO: proper accelerator treatment. What does wxFindAccelerator + //// look for? + strcpy(wxBuffer, (char*) (const char*) m_strName); + char *accel = wxFindAccelerator (wxBuffer); + if (accel) + XtVaSetValues ((Widget) m_buttonWidget, XmNaccelerator, accel, NULL); + + // TODO: What does this do? + strcpy(wxBuffer, (char*) (const char*) m_strName); + XmString accel_str = wxFindAcceleratorText (wxBuffer); + if (accel_str) + { + XtVaSetValues ((Widget) m_buttonWidget, XmNacceleratorText, accel_str, NULL); + XmStringFree (accel_str); + } + + if (IsCheckable()) + XtAddCallback ((Widget) m_buttonWidget, + XmNvalueChangedCallback, + (XtCallbackProc) wxMenuItemCallback, + (XtPointer) this); + else + XtAddCallback ((Widget) m_buttonWidget, + XmNactivateCallback, + (XtCallbackProc) wxMenuItemCallback, + (XtPointer) this); + XtAddCallback ((Widget) m_buttonWidget, + XmNarmCallback, + (XtCallbackProc) wxMenuItemArmCallback, + (XtPointer) this); + XtAddCallback ((Widget) m_buttonWidget, + XmNdisarmCallback, + (XtCallbackProc) wxMenuItemDisarmCallback, + (XtPointer) this); + } + else if (GetId() == -1) + { + m_buttonWidget = (WXWidget) XtVaCreateManagedWidget ("separator", + xmSeparatorGadgetClass, (Widget) menu, NULL); + } + else if (m_pSubMenu) + { + m_buttonWidget = m_pSubMenu->CreateMenu (menuBar, menu, topMenu, m_strName, TRUE); + m_pSubMenu->SetButtonWidget(m_buttonWidget); + XtAddCallback ((Widget) m_buttonWidget, + XmNcascadingCallback, + (XtCallbackProc) wxMenuItemArmCallback, + (XtPointer) this); + } + if (m_buttonWidget) + XtSetSensitive ((Widget) m_buttonWidget, (Boolean) IsEnabled()); +} + +void wxMenuItem::DestroyItem(bool full) +{ + if (GetId() == -2) + { + ; // Nothing + + } + else if ((!m_strName.IsNull() && (m_strName != "")) && !m_pSubMenu) + { + if (m_buttonWidget) + { + if (IsCheckable()) + XtRemoveCallback ((Widget) m_buttonWidget, XmNvalueChangedCallback, + wxMenuItemCallback, (XtPointer) this); + else + XtRemoveCallback ((Widget) m_buttonWidget, XmNactivateCallback, + wxMenuItemCallback, (XtPointer) this); + XtRemoveCallback ((Widget) m_buttonWidget, XmNarmCallback, + wxMenuItemArmCallback, (XtPointer) this); + XtRemoveCallback ((Widget) m_buttonWidget, XmNdisarmCallback, + wxMenuItemDisarmCallback, (XtPointer) this); + } + } + else if (GetId() == -1) + { + ; // Nothing + + } + else if (GetSubMenu()) + { + if (m_buttonWidget) + { + XtRemoveCallback ((Widget) m_buttonWidget, XmNcascadingCallback, + wxMenuItemArmCallback, (XtPointer) this); + } + m_pSubMenu->DestroyMenu(full); + if (full) + m_buttonWidget = NULL; + } + + if (m_buttonWidget && full) + { + XtDestroyWidget ((Widget) m_buttonWidget); + m_buttonWidget = (WXWidget) 0; + } +} + +void wxMenuItem::SetLabel(const wxString& label) +{ + char mnem = wxFindMnemonic (label); + wxStripMenuCodes ((char*) (const char*) label, wxBuffer); + + m_strName = label; + + if (m_buttonWidget) + { + XmString label_str = XmStringCreateSimple (wxBuffer); + XtVaSetValues ((Widget) m_buttonWidget, + XmNlabelString, label_str, + NULL); + XmStringFree (label_str); + if (mnem != 0) + XtVaSetValues ((Widget) m_buttonWidget, XmNmnemonic, mnem, NULL); + strcpy(wxBuffer, (char*) (const char*) label); + char *accel = wxFindAccelerator (wxBuffer); + if (accel) + XtVaSetValues ((Widget) m_buttonWidget, XmNaccelerator, accel, NULL); + + strcpy(wxBuffer, (char*) (const char*) label); + XmString accel_str = wxFindAcceleratorText (wxBuffer); + if (accel_str) + { + XtVaSetValues ((Widget) m_buttonWidget, XmNacceleratorText, accel_str, NULL); + XmStringFree (accel_str); + } + } +} + +void wxMenuItemCallback (Widget w, XtPointer clientData, + XtPointer ptr) +{ + wxMenuItem *item = (wxMenuItem *) clientData; + if (item) + { + if (item->IsCheckable()) + { + Boolean isChecked = FALSE; + XtVaGetValues ((Widget) item->GetButtonWidget(), XmNset, & isChecked, NULL); + item->SetChecked(isChecked); + } + if (item->GetMenuBar() && item->GetMenuBar()->GetMenuBarFrame()) + { + wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, item->GetId()); + commandEvent.SetEventObject(item->GetMenuBar()->GetMenuBarFrame()); + + item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(commandEvent); + } + else if (item->GetTopMenu()) + { + wxCommandEvent event (wxEVT_COMMAND_MENU_SELECTED, item->GetId()); + event.SetEventObject(item->GetTopMenu()); + item->GetTopMenu()->ProcessCommand (event); + } + } +} + +void +wxMenuItemArmCallback (Widget w, XtPointer clientData, + XtPointer ptr) +{ + wxMenuItem *item = (wxMenuItem *) clientData; + if (item) + { + if (item->GetMenuBar() && item->GetMenuBar()->GetMenuBarFrame()) + { + wxMenuEvent menuEvent(wxEVT_MENU_HIGHLIGHT, item->GetId()); + menuEvent.SetEventObject(item->GetMenuBar()->GetMenuBarFrame()); + + item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(menuEvent); + } + } +} + +void +wxMenuItemDisarmCallback (Widget w, XtPointer clientData, + XtPointer ptr) +{ + wxMenuItem *item = (wxMenuItem *) clientData; + if (item) + { + if (item->GetMenuBar() && item->GetMenuBar()->GetMenuBarFrame()) + { + // TODO: not sure this is correct, since -1 means something + // special to event system + wxMenuEvent menuEvent(wxEVT_MENU_HIGHLIGHT, -1); + menuEvent.SetEventObject(item->GetMenuBar()->GetMenuBarFrame()); + + item->GetMenuBar()->GetMenuBarFrame()->GetEventHandler()->ProcessEvent(menuEvent); + } + } +} + diff --git a/src/motif/utils.cpp b/src/motif/utils.cpp index f7a95bce39..4567ad472d 100644 --- a/src/motif/utils.cpp +++ b/src/motif/utils.cpp @@ -28,6 +28,8 @@ #include +#include "wx/motif/private.h" + // Get full hostname (eg. DoDo.BSn-Germany.crg.de) bool wxGetHostName(char *buf, int maxSize) { @@ -322,3 +324,323 @@ wxString wxGetDisplayName() { return gs_displayName; } + +// Find the letter corresponding to the mnemonic, for Motif +char wxFindMnemonic (const char *s) +{ + char mnem = 0; + int len = strlen (s); + int i; + for (i = 0; i < len; i++) + { + if (s[i] == '&') + { + // Carefully handle && + if ((i + 1) <= len && s[i + 1] == '&') + i++; + else + { + mnem = s[i + 1]; + break; + } + } + } + return mnem; +} + +char * wxFindAccelerator (char *s) +{ +// The accelerator text is after the \t char. + while (*s && *s != '\t') + s++; + if (*s == '\0') + return (NULL); + s++; +/* + Now we need to format it as X standard: + + input output + + F7 --> F7 + Ctrl+N --> CtrlN + Alt+k --> Metak + Ctrl+Shift+A --> Ctrl ShiftA + + */ + + wxBuffer[0] = '\0'; + char *tmp = copystring (s); + s = tmp; + char *p = s; + + while (1) + { + while (*p && *p != '+') + p++; + if (*p) + { + *p = '\0'; + if (wxBuffer[0]) + strcat (wxBuffer, " "); + if (strcmp (s, "Alt")) + strcat (wxBuffer, s); + else + strcat (wxBuffer, "Meta"); + s = p + 1; + p = s; + } + else + { + strcat (wxBuffer, ""); + strcat (wxBuffer, s); + break; + } + } + delete[]tmp; + return wxBuffer; +} + +XmString wxFindAcceleratorText (char *s) +{ +// The accelerator text is after the \t char. + while (*s && *s != '\t') + s++; + if (*s == '\0') + return (NULL); + s++; + XmString text = XmStringCreateSimple (s); + return text; +} + +#include + +int wxCharCodeXToWX(KeySym keySym) +{ + int id; + switch (keySym) { + case XK_Shift_L: + case XK_Shift_R: + id = WXK_SHIFT; break; + case XK_Control_L: + case XK_Control_R: + id = WXK_CONTROL; break; + case XK_BackSpace: + id = WXK_BACK; break; + case XK_Delete: + id = WXK_DELETE; break; + case XK_Clear: + id = WXK_CLEAR; break; + case XK_Tab: + id = WXK_TAB; break; + case XK_numbersign: + id = '#'; break; + case XK_Return: + id = WXK_RETURN; break; + case XK_Escape: + id = WXK_ESCAPE; break; + case XK_Pause: + case XK_Break: + id = WXK_PAUSE; break; + case XK_Num_Lock: + id = WXK_NUMLOCK; break; + case XK_Scroll_Lock: + id = WXK_SCROLL; break; + + case XK_Home: + id = WXK_HOME; break; + case XK_End: + id = WXK_END; break; + case XK_Left: + id = WXK_LEFT; break; + case XK_Right: + id = WXK_RIGHT; break; + case XK_Up: + id = WXK_UP; break; + case XK_Down: + id = WXK_DOWN; break; + case XK_Next: + id = WXK_NEXT; break; + case XK_Prior: + id = WXK_PRIOR; break; + case XK_Menu: + id = WXK_MENU; break; + case XK_Select: + id = WXK_SELECT; break; + case XK_Cancel: + id = WXK_CANCEL; break; + case XK_Print: + id = WXK_PRINT; break; + case XK_Execute: + id = WXK_EXECUTE; break; + case XK_Insert: + id = WXK_INSERT; break; + case XK_Help: + id = WXK_HELP; break; + + case XK_KP_Multiply: + id = WXK_MULTIPLY; break; + case XK_KP_Add: + id = WXK_ADD; break; + case XK_KP_Subtract: + id = WXK_SUBTRACT; break; + case XK_KP_Divide: + id = WXK_DIVIDE; break; + case XK_KP_Decimal: + id = WXK_DECIMAL; break; + case XK_KP_Equal: + id = '='; break; + case XK_KP_Space: + id = ' '; break; + case XK_KP_Tab: + id = WXK_TAB; break; + case XK_KP_Enter: + id = WXK_RETURN; break; + case XK_KP_0: + id = WXK_NUMPAD0; break; + case XK_KP_1: + id = WXK_NUMPAD1; break; + case XK_KP_2: + id = WXK_NUMPAD2; break; + case XK_KP_3: + id = WXK_NUMPAD3; break; + case XK_KP_4: + id = WXK_NUMPAD4; break; + case XK_KP_5: + id = WXK_NUMPAD5; break; + case XK_KP_6: + id = WXK_NUMPAD6; break; + case XK_KP_7: + id = WXK_NUMPAD7; break; + case XK_KP_8: + id = WXK_NUMPAD8; break; + case XK_KP_9: + id = WXK_NUMPAD9; break; + case XK_F1: + id = WXK_F1; break; + case XK_F2: + id = WXK_F2; break; + case XK_F3: + id = WXK_F3; break; + case XK_F4: + id = WXK_F4; break; + case XK_F5: + id = WXK_F5; break; + case XK_F6: + id = WXK_F6; break; + case XK_F7: + id = WXK_F7; break; + case XK_F8: + id = WXK_F8; break; + case XK_F9: + id = WXK_F9; break; + case XK_F10: + id = WXK_F10; break; + case XK_F11: + id = WXK_F11; break; + case XK_F12: + id = WXK_F12; break; + case XK_F13: + id = WXK_F13; break; + case XK_F14: + id = WXK_F14; break; + case XK_F15: + id = WXK_F15; break; + case XK_F16: + id = WXK_F16; break; + case XK_F17: + id = WXK_F17; break; + case XK_F18: + id = WXK_F18; break; + case XK_F19: + id = WXK_F19; break; + case XK_F20: + id = WXK_F20; break; + case XK_F21: + id = WXK_F21; break; + case XK_F22: + id = WXK_F22; break; + case XK_F23: + id = WXK_F23; break; + case XK_F24: + id = WXK_F24; break; + default: + id = (keySym <= 255) ? (int)keySym : -1; + } // switch + return id; +} + +KeySym wxCharCodeWXToX(int id) +{ + KeySym keySym; + + switch (id) { + case WXK_CANCEL: keySym = XK_Cancel; break; + case WXK_BACK: keySym = XK_BackSpace; break; + case WXK_TAB: keySym = XK_Tab; break; + case WXK_CLEAR: keySym = XK_Clear; break; + case WXK_RETURN: keySym = XK_Return; break; + case WXK_SHIFT: keySym = XK_Shift_L; break; + case WXK_CONTROL: keySym = XK_Control_L; break; + case WXK_MENU : keySym = XK_Menu; break; + case WXK_PAUSE: keySym = XK_Pause; break; + case WXK_ESCAPE: keySym = XK_Escape; break; + case WXK_SPACE: keySym = ' '; break; + case WXK_PRIOR: keySym = XK_Prior; break; + case WXK_NEXT : keySym = XK_Next; break; + case WXK_END: keySym = XK_End; break; + case WXK_HOME : keySym = XK_Home; break; + case WXK_LEFT : keySym = XK_Left; break; + case WXK_UP: keySym = XK_Up; break; + case WXK_RIGHT: keySym = XK_Right; break; + case WXK_DOWN : keySym = XK_Down; break; + case WXK_SELECT: keySym = XK_Select; break; + case WXK_PRINT: keySym = XK_Print; break; + case WXK_EXECUTE: keySym = XK_Execute; break; + case WXK_INSERT: keySym = XK_Insert; break; + case WXK_DELETE: keySym = XK_Delete; break; + case WXK_HELP : keySym = XK_Help; break; + case WXK_NUMPAD0: keySym = XK_KP_0; break; + case WXK_NUMPAD1: keySym = XK_KP_1; break; + case WXK_NUMPAD2: keySym = XK_KP_2; break; + case WXK_NUMPAD3: keySym = XK_KP_3; break; + case WXK_NUMPAD4: keySym = XK_KP_4; break; + case WXK_NUMPAD5: keySym = XK_KP_5; break; + case WXK_NUMPAD6: keySym = XK_KP_6; break; + case WXK_NUMPAD7: keySym = XK_KP_7; break; + case WXK_NUMPAD8: keySym = XK_KP_8; break; + case WXK_NUMPAD9: keySym = XK_KP_9; break; + case WXK_MULTIPLY: keySym = XK_KP_Multiply; break; + case WXK_ADD: keySym = XK_KP_Add; break; + case WXK_SUBTRACT: keySym = XK_KP_Subtract; break; + case WXK_DECIMAL: keySym = XK_KP_Decimal; break; + case WXK_DIVIDE: keySym = XK_KP_Divide; break; + case WXK_F1: keySym = XK_F1; break; + case WXK_F2: keySym = XK_F2; break; + case WXK_F3: keySym = XK_F3; break; + case WXK_F4: keySym = XK_F4; break; + case WXK_F5: keySym = XK_F5; break; + case WXK_F6: keySym = XK_F6; break; + case WXK_F7: keySym = XK_F7; break; + case WXK_F8: keySym = XK_F8; break; + case WXK_F9: keySym = XK_F9; break; + case WXK_F10: keySym = XK_F10; break; + case WXK_F11: keySym = XK_F11; break; + case WXK_F12: keySym = XK_F12; break; + case WXK_F13: keySym = XK_F13; break; + case WXK_F14: keySym = XK_F14; break; + case WXK_F15: keySym = XK_F15; break; + case WXK_F16: keySym = XK_F16; break; + case WXK_F17: keySym = XK_F17; break; + case WXK_F18: keySym = XK_F18; break; + case WXK_F19: keySym = XK_F19; break; + case WXK_F20: keySym = XK_F20; break; + case WXK_F21: keySym = XK_F21; break; + case WXK_F22: keySym = XK_F22; break; + case WXK_F23: keySym = XK_F23; break; + case WXK_F24: keySym = XK_F24; break; + case WXK_NUMLOCK: keySym = XK_Num_Lock; break; + case WXK_SCROLL: keySym = XK_Scroll_Lock; break; + default: keySym = id <= 255 ? (KeySym)id : 0; + } // switch + return keySym; +} diff --git a/src/motif/window.cpp b/src/motif/window.cpp index 4287512e6f..3f2ba314ed 100644 --- a/src/motif/window.cpp +++ b/src/motif/window.cpp @@ -36,10 +36,27 @@ #endif #include + +#include +#include +#include +#include +#include + #include "wx/motif/private.h" #include +#define SCROLL_MARGIN 4 +void wxCanvasRepaintProc (Widget, XtPointer, XmDrawingAreaCallbackStruct * cbs); +void wxCanvasInputEvent (Widget drawingArea, XtPointer data, XmDrawingAreaCallbackStruct * cbs); +void wxCanvasMotionEvent (Widget, XButtonEvent * event); +void wxCanvasEnterLeave (Widget drawingArea, XtPointer clientData, XCrossingEvent * event); + +#define event_left_is_down(x) ((x)->xbutton.state & Button1Mask) +#define event_middle_is_down(x) ((x)->xbutton.state & Button2Mask) +#define event_right_is_down(x) ((x)->xbutton.state & Button3Mask) + extern wxList wxPendingDelete; #if !USE_SHARED_LIBRARY @@ -87,18 +104,84 @@ wxWindow::wxWindow() m_pDropTarget = NULL; #endif - /// MOTIF-specific + /// Motif-specific m_mainWidget = (WXWidget) 0; m_button1Pressed = FALSE; m_button2Pressed = FALSE; m_button3Pressed = FALSE; m_winCaptured = FALSE; m_isShown = TRUE; + m_hScrollBar = (WXWidget) 0; + m_vScrollBar = (WXWidget) 0; + m_borderWidget = (WXWidget) 0; + m_scrolledWindow = (WXWidget) 0; + m_drawingArea = (WXWidget) 0; + m_hScroll = FALSE; + m_vScroll = FALSE; + m_hScrollingEnabled = FALSE; + m_vScrollingEnabled = FALSE; + m_backingPixmap = (WXPixmap) 0; + m_pixmapWidth = 0; + m_pixmapHeight = 0; + m_pixmapOffsetX = 0; + m_pixmapOffsetY = 0; + m_lastTS = 0; + m_lastButton = 0; } // Destructor wxWindow::~wxWindow() { + //// Motif-specific + + // If m_drawingArea, we're a fully-fledged window with drawing area, scrollbars etc. (what wxCanvas used to be) + if (m_drawingArea) + { + // Destroy children before destroying self + DestroyChildren(); + + if (m_backingPixmap) + XFreePixmap (XtDisplay ((Widget) GetMainWidget()), (Pixmap) m_backingPixmap); + + Widget w = (Widget) m_drawingArea; + wxDeleteWindowFromTable(w); + + if (w) + XtDestroyWidget(w); + m_mainWidget = (WXWidget) 0; + + // Only if we're _really_ a canvas (not a dialog box/panel) + if (m_scrolledWindow) + { + wxDeleteWindowFromTable((Widget) m_scrolledWindow); + } + + if (m_hScrollBar) + { + XtUnmanageChild ((Widget) m_hScrollBar); + XtDestroyWidget ((Widget) m_hScrollBar); + } + if (m_vScrollBar) + { + XtUnmanageChild ((Widget) m_vScrollBar); + XtDestroyWidget ((Widget) m_vScrollBar); + } + if (m_scrolledWindow) + { + XtUnmanageChild ((Widget) m_scrolledWindow); + XtDestroyWidget ((Widget) m_scrolledWindow); + } + + if (m_borderWidget) + { + XtDestroyWidget ((Widget) m_borderWidget); + m_borderWidget = (WXWidget) 0; + } + } + + + //// Generic stuff + // Have to delete constraints/sizer FIRST otherwise // sizers may try to look at deleted windows as they // delete themselves. @@ -174,11 +257,9 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, m_sizerParent = NULL; m_autoLayout = FALSE; m_windowValidator = NULL; - #if USE_DRAG_AND_DROP m_pDropTarget = NULL; #endif - m_caretWidth = 0; m_caretHeight = 0; m_caretEnabled = FALSE; m_caretShown = FALSE; @@ -188,6 +269,29 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, m_maxSizeY = -1; m_defaultItem = NULL; m_windowParent = NULL; + + // Motif-specific + m_mainWidget = (WXWidget) 0; + m_button1Pressed = FALSE; + m_button2Pressed = FALSE; + m_button3Pressed = FALSE; + m_winCaptured = FALSE; + m_isShown = TRUE; + m_hScrollBar = (WXWidget) 0; + m_vScrollBar = (WXWidget) 0; + m_borderWidget = (WXWidget) 0; + m_scrolledWindow = (WXWidget) 0; + m_drawingArea = (WXWidget) 0; + m_hScroll = FALSE; + m_vScroll = FALSE; + m_hScrollingEnabled = FALSE; + m_vScrollingEnabled = FALSE; + m_backingPixmap = (WXPixmap) 0; + m_pixmapWidth = 0; + m_pixmapHeight = 0; + m_pixmapOffsetX = 0; + m_pixmapOffsetY = 0; + if (!parent) return FALSE; @@ -214,7 +318,92 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id, else m_windowId = id; - // TODO: create the window + //// TODO: we should probably optimize by only creating a + //// a drawing area if we have one or more scrollbars (wxVSCROLL/wxHSCROLL). + //// But for now, let's simplify things by always creating the + //// drawing area, since otherwise the translations are different. + + // New translations for getting mouse motion feedback + String translations = + ": wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\ + : wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\ + : wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\ + : wxCanvasMotionEvent() DrawingAreaInput() ManagerGadgetButtonMotion()\n\ + : DrawingAreaInput() ManagerGadgetArm()\n\ + : DrawingAreaInput() ManagerGadgetArm()\n\ + : DrawingAreaInput() ManagerGadgetArm()\n\ + : DrawingAreaInput() ManagerGadgetActivate()\n\ + : DrawingAreaInput() ManagerGadgetActivate()\n\ + : DrawingAreaInput() ManagerGadgetActivate()\n\ + : wxCanvasMotionEvent() DrawingAreaInput()\n\ + : wxCanvasMotionEvent() DrawingAreaInput()\n\ + : wxCanvasMotionEvent() DrawingAreaInput()\n\ + : DrawingAreaInput()"; + + XtActionsRec actions[1]; + actions[0].string = "wxCanvasMotionEvent"; + actions[0].proc = (XtActionProc) wxCanvasMotionEvent; + XtAppAddActions ((XtAppContext) wxTheApp->GetAppContext(), actions, 1); + + Widget parentWidget = (Widget) parent->GetClientWidget(); + if (style & wxBORDER) + m_borderWidget = (WXWidget) XtVaCreateManagedWidget ("canvasBorder", + xmFrameWidgetClass, parentWidget, + XmNshadowType, XmSHADOW_IN, + NULL); + + m_scrolledWindow = (WXWidget) XtVaCreateManagedWidget ("scrolledWindow", + xmScrolledWindowWidgetClass, m_borderWidget ? (Widget) m_borderWidget : parentWidget, + XmNspacing, 0, + XmNscrollingPolicy, XmAPPLICATION_DEFINED, + NULL); + + XtTranslations ptr; + m_drawingArea = (WXWidget) XtVaCreateWidget ((char*) (const char*) name, + xmDrawingAreaWidgetClass, (Widget) m_scrolledWindow, + XmNunitType, XmPIXELS, +// XmNresizePolicy, XmRESIZE_ANY, + XmNresizePolicy, XmRESIZE_NONE, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + XmNtranslations, ptr = XtParseTranslationTable (translations), + NULL); + /* + if (GetWindowStyleFlag() & wxOVERRIDE_KEY_TRANSLATIONS) + { + XtFree ((char *) ptr); + ptr = XtParseTranslationTable (": DrawingAreaInput()"); + XtOverrideTranslations ((Widget) m_drawingArea, ptr); + XtFree ((char *) ptr); + } + */ + + wxAddWindowToTable((Widget) m_drawingArea, this); + wxAddWindowToTable((Widget) m_scrolledWindow, this); + + /* + * This order is very important in Motif 1.2.1 + * + */ + + XtRealizeWidget ((Widget) m_scrolledWindow); + XtRealizeWidget ((Widget) m_drawingArea); + XtManageChild ((Widget) m_drawingArea); + + XtOverrideTranslations ((Widget) m_drawingArea, + ptr = XtParseTranslationTable (": resize()")); + XtFree ((char *) ptr); + + XtAddCallback ((Widget) m_drawingArea, XmNexposeCallback, (XtCallbackProc) wxCanvasRepaintProc, (XtPointer) this); + XtAddCallback ((Widget) m_drawingArea, XmNinputCallback, (XtCallbackProc) wxCanvasInputEvent, (XtPointer) this); + + /* TODO? + display = XtDisplay (scrolledWindow); + xwindow = XtWindow (drawingArea); + */ + + XtAddEventHandler ((Widget) m_drawingArea, PointerMotionHintMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask, + False, (XtEventHandler) wxCanvasEnterLeave, (XtPointer) this); return TRUE; } @@ -309,6 +498,12 @@ void wxWindow::DragAcceptFiles(bool accept) // Get total size void wxWindow::GetSize(int *x, int *y) const { + if (m_drawingArea) + { + CanvasGetSize(x, y); + return; + } + Widget widget = (Widget) GetMainWidget(); Dimension xx, yy; XtVaGetValues(widget, XmNwidth, &xx, XmNheight, &yy, NULL); @@ -317,6 +512,11 @@ void wxWindow::GetSize(int *x, int *y) const void wxWindow::GetPosition(int *x, int *y) const { + if (m_drawingArea) + { + CanvasGetPosition(x, y); + return; + } Widget widget = (Widget) GetMainWidget(); Position xx, yy; XtVaGetValues(widget, XmNx, &xx, XmNy, &yy, NULL); @@ -377,6 +577,11 @@ void wxWindow::GetClientSize(int *x, int *y) const void wxWindow::SetSize(int x, int y, int width, int height, int sizeFlags) { + if (m_drawingArea) + { + CanvasSetSize(x, y, width, height, sizeFlags); + return; + } Widget widget = (Widget) GetMainWidget(); if (x > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) @@ -396,6 +601,12 @@ void wxWindow::SetSize(int x, int y, int width, int height, int sizeFlags) void wxWindow::SetClientSize(int width, int height) { + if (m_drawingArea) + { + CanvasSetClientSize(width, height); + return; + } + Widget widget = (Widget) GetMainWidget(); if (width > -1) @@ -429,12 +640,37 @@ void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) bool wxWindow::Show(bool show) { + if (show) + { + if (m_borderWidget || m_scrolledWindow) + { + XtMapWidget(m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + } + else + { + XtMapWidget((Widget) GetMainWidget()); + } + } + else + { + if (m_borderWidget || m_scrolledWindow) + { + XtUnmapWidget(m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + } + else + { + XtUnmapWidget((Widget) GetMainWidget()); + } + } + + /* Window xwin = (Window) GetXWindow(); Display *xdisp = (Display*) GetXDisplay(); if (show) XMapWindow(xdisp, xwin); else XUnmapWindow(xdisp, xwin); + */ m_isShown = show; @@ -640,9 +876,9 @@ void wxWindow::Centre(int direction) } // Coordinates relative to the window -void wxWindow::WarpPointer (int x_pos, int y_pos) +void wxWindow::WarpPointer (int x, int y) { - // TODO + XWarpPointer (XtDisplay((Widget) GetClientWidget()), None, XtWindow((Widget) GetClientWidget()), 0, 0, 0, 0, x, y); } void wxWindow::OnEraseBackground(wxEraseEvent& event) @@ -1493,17 +1729,564 @@ void wxDeleteWindowFromTable(Widget w) // Get the underlying X window and display WXWindow wxWindow::GetXWindow() const { - return (WXWindow) XtWindow((Widget) GetMainWidget()); + return (WXWindow) XtWindow((Widget) GetMainWidget()); } WXDisplay *wxWindow::GetXDisplay() const { - return (WXDisplay*) XtDisplay((Widget) GetMainWidget()); + return (WXDisplay*) XtDisplay((Widget) GetMainWidget()); } WXWidget wxWindow::GetMainWidget() const { - return m_mainWidget; + if (m_drawingArea) + return m_drawingArea; + else + return m_mainWidget; +} + +WXWidget wxWindow::GetClientWidget() const +{ + if (m_drawingArea != (WXWidget) 0) + return m_drawingArea; + else + return m_mainWidget; } +void wxCanvasRepaintProc (Widget drawingArea, XtPointer clientData, + XmDrawingAreaCallbackStruct * cbs) +{ + if (!wxWidgetHashTable->Get ((long) (Widget) drawingArea)) + return; + + XEvent * event = cbs->event; + wxWindow * canvas = (wxWindow *) clientData; + Display * display = (Display *) canvas->GetXDisplay(); + // GC gc = (GC) canvas->GetDC()->gc; + + switch (event->type) + { + case Expose: + { + /* TODO + wxCanvasDC* canvasDC = canvas->GetDC(); + if (canvasDC) + { + if (canvasDC->onpaint_reg) + XDestroyRegion(canvasDC->onpaint_reg); + canvasDC->onpaint_reg = XCreateRegion(); + + } + */ + + int n = canvas->m_updateRects.Number(); + XRectangle* xrects = new XRectangle[n]; + int i; + for (i = 0; i < canvas->m_updateRects.Number(); i++) + { + wxRect* rect = (wxRect*) canvas->m_updateRects.Nth(i)->Data(); + xrects[i].x = rect->x; + xrects[i].y = rect->y; + xrects[i].width = rect->width; + xrects[i].height = rect->height; + /* TODO (?) Actually ignore it I think. + if (canvasDC) + XUnionRectWithRegion(&(xrects[i]), canvasDC->onpaint_reg, + canvasDC->onpaint_reg); + */ + } + /* TODO must clip the area being repainted. So we need a gc. + * Alternatively, wxPaintDC must do the clipping + * when it's created. + XSetClipRectangles(display, gc, 0, 0, xrects, n, Unsorted); + */ + + canvas->DoPaint() ; // xrects, n); + delete[] xrects; + + canvas->m_updateRects.Clear(); + + /* + if (canvasDC) + { + XDestroyRegion(canvasDC->onpaint_reg); + canvasDC->onpaint_reg = NULL; + } + + XGCValues gc_val; + gc_val.clip_mask = None; + XChangeGC(display, gc, GCClipMask, &gc_val); + */ + + break; + } + default: + { + cout << "\n\nNew Event ! is = " << event -> type << "\n"; + break; + } + } +} + +// Unable to deal with Enter/Leave without a separate EventHandler (Motif 1.1.4) +void +wxCanvasEnterLeave (Widget drawingArea, XtPointer clientData, XCrossingEvent * event) +{ + XmDrawingAreaCallbackStruct cbs; + XEvent ev; + + //if (event->mode!=NotifyNormal) + // return ; + +// ev = *((XEvent *) event); // Causes Purify error (copying too many bytes) + ((XCrossingEvent &) ev) = *event; + + cbs.reason = XmCR_INPUT; + cbs.event = &ev; + + wxCanvasInputEvent (drawingArea, (XtPointer) NULL, &cbs); +} + +// Fix to make it work under Motif 1.0 (!) +void wxCanvasMotionEvent (Widget drawingArea, XButtonEvent * event) +{ +#if XmVersion<=1000 + XmDrawingAreaCallbackStruct cbs; + XEvent ev; + + //ev.xbutton = *event; + ev = *((XEvent *) event); + cbs.reason = XmCR_INPUT; + cbs.event = &ev; + + wxCanvasInputEvent (drawingArea, (XtPointer) NULL, &cbs); +#endif +} + +void wxCanvasInputEvent (Widget drawingArea, XtPointer data, XmDrawingAreaCallbackStruct * cbs) +{ + wxWindow *canvas = (wxWindow *) wxWidgetHashTable->Get ((long) (Widget) drawingArea); + XEvent local_event; + + if (canvas==NULL) + return ; + + if (cbs->reason != XmCR_INPUT) + return; + + local_event = *(cbs->event); // We must keep a copy! + + switch (local_event.xany.type) + { + case EnterNotify: + case LeaveNotify: + case ButtonPress: + case ButtonRelease: + case MotionNotify: + { + wxEventType eventType = wxEVT_NULL; + + if (local_event.xany.type == EnterNotify) + { + //if (local_event.xcrossing.mode!=NotifyNormal) + // return ; // Ignore grab events + eventType = wxEVT_ENTER_WINDOW; +// canvas->GetEventHandler()->OnSetFocus(); + } + else if (local_event.xany.type == LeaveNotify) + { + //if (local_event.xcrossing.mode!=NotifyNormal) + // return ; // Ignore grab events + eventType = wxEVT_LEAVE_WINDOW; +// canvas->GetEventHandler()->OnKillFocus(); + } + else if (local_event.xany.type == MotionNotify) + { + eventType = wxEVT_MOTION; + if (local_event.xmotion.is_hint == NotifyHint) + { + Window root, child; + Display *dpy = XtDisplay (drawingArea); + + XQueryPointer (dpy, XtWindow (drawingArea), + &root, &child, + &local_event.xmotion.x_root, + &local_event.xmotion.y_root, + &local_event.xmotion.x, + &local_event.xmotion.y, + &local_event.xmotion.state); + } + else + { + } + } + + else if (local_event.xany.type == ButtonPress) + { + if (local_event.xbutton.button == Button1) + { + eventType = wxEVT_LEFT_DOWN; + canvas->m_button1Pressed = TRUE; + } + else if (local_event.xbutton.button == Button2) + { + eventType = wxEVT_MIDDLE_DOWN; + canvas->m_button2Pressed = TRUE; + } + else if (local_event.xbutton.button == Button3) + { + eventType = wxEVT_RIGHT_DOWN; + canvas->m_button3Pressed = TRUE; + } + } + else if (local_event.xany.type == ButtonRelease) + { + if (local_event.xbutton.button == Button1) + { + eventType = wxEVT_LEFT_UP; + canvas->m_button1Pressed = FALSE; + } + else if (local_event.xbutton.button == Button2) + { + eventType = wxEVT_MIDDLE_UP; + canvas->m_button2Pressed = FALSE; + } + else if (local_event.xbutton.button == Button3) + { + eventType = wxEVT_RIGHT_UP; + canvas->m_button3Pressed = FALSE; + } + } + + wxMouseEvent wxevent (eventType); + wxevent.m_eventHandle = (char *) &local_event; + + wxevent.m_leftDown = ((eventType == wxEVT_LEFT_DOWN) + || (event_left_is_down (&local_event) + && (eventType != wxEVT_LEFT_UP))); + wxevent.m_middleDown = ((eventType == wxEVT_MIDDLE_DOWN) + || (event_middle_is_down (&local_event) + && (eventType != wxEVT_MIDDLE_UP))); + wxevent.m_rightDown = ((eventType == wxEVT_RIGHT_DOWN) + || (event_right_is_down (&local_event) + && (eventType != wxEVT_RIGHT_UP))); + + wxevent.m_shiftDown = local_event.xbutton.state & ShiftMask; + wxevent.m_controlDown = local_event.xbutton.state & ControlMask; + wxevent.m_altDown = local_event.xbutton.state & Mod3Mask; + wxevent.m_metaDown = local_event.xbutton.state & Mod1Mask; + wxevent.SetTimestamp(local_event.xbutton.time); + + // Now check if we need to translate this event into a double click + if (TRUE) // canvas->doubleClickAllowed) + { + if (wxevent.ButtonDown()) + { + long dclickTime = XtGetMultiClickTime((Display*) wxGetDisplay()) ; + + // get button and time-stamp + int button = 0; + if (wxevent.LeftDown()) button = 1; + else if (wxevent.MiddleDown()) button = 2; + else if (wxevent.RightDown()) button = 3; + long ts = wxevent.GetTimestamp(); + // check, if single or double click + if (canvas->m_lastButton && canvas->m_lastButton==button && (ts - canvas->m_lastTS) < dclickTime) + { + // I have a dclick + canvas->m_lastButton = 0; + switch ( eventType ) + { + case wxEVT_LEFT_DOWN: + wxevent.SetEventType(wxEVT_LEFT_DCLICK); + break; + case wxEVT_MIDDLE_DOWN: + wxevent.SetEventType(wxEVT_MIDDLE_DCLICK); + break; + case wxEVT_RIGHT_DOWN: + wxevent.SetEventType(wxEVT_RIGHT_DCLICK); + break; + + default : + break; + } + + } + else + { + // not fast enough or different button + canvas->m_lastTS = ts; + canvas->m_lastButton = button; + } + } + } + + wxevent.SetId(canvas->GetId()); + wxevent.SetEventObject(canvas); + canvas->GetEventHandler()->ProcessEvent (wxevent); + /* + if (eventType == wxEVT_ENTER_WINDOW || + eventType == wxEVT_LEAVE_WINDOW || + eventType == wxEVT_MOTION + ) + return; + */ + break; + } + case KeyPress: + { + KeySym keySym; +// XComposeStatus compose; +// (void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 20, &keySym, &compose); + (void) XLookupString ((XKeyEvent *) & local_event, wxBuffer, 20, &keySym, NULL); + int id = wxCharCodeXToWX (keySym); + + wxKeyEvent event (wxEVT_CHAR); + + if (local_event.xkey.state & ShiftMask) + event.m_shiftDown = TRUE; + if (local_event.xkey.state & ControlMask) + event.m_controlDown = TRUE; + if (local_event.xkey.state & Mod3Mask) + event.m_altDown = TRUE; + if (local_event.xkey.state & Mod1Mask) + event.m_metaDown = TRUE; + event.SetEventObject(canvas); + event.m_keyCode = id; + event.SetTimestamp(local_event.xkey.time); + + if (id > -1) + { + // Implement wxFrame::OnCharHook by checking ancestor. + wxWindow *parent = canvas->GetParent(); + while (parent && !parent->IsKindOf(CLASSINFO(wxFrame))) + parent = parent->GetParent(); + + if (parent) + { + event.SetEventType(wxEVT_CHAR_HOOK); + if (parent->GetEventHandler()->ProcessEvent(event)) + return; + event.SetEventType(wxEVT_CHAR); + } + + canvas->GetEventHandler()->ProcessEvent (event); + } + break; + } + case FocusIn: + { + if (local_event.xfocus.detail != NotifyPointer) + { + wxFocusEvent event(wxEVT_SET_FOCUS, canvas->GetId()); + event.SetEventObject(canvas); + canvas->GetEventHandler()->ProcessEvent(event); + } + break; + } + case FocusOut: + { + if (local_event.xfocus.detail != NotifyPointer) + { + wxFocusEvent event(wxEVT_KILL_FOCUS, canvas->GetId()); + event.SetEventObject(canvas); + canvas->GetEventHandler()->ProcessEvent(event); + } + break; + } + default: + break; + } +} + +void wxWindow::DoPaint() +{ + //TODO : make a temporary gc so we can do the XCopyArea below + if (0) // m_backingPixmap) + { + /* + Widget drawingArea = (Widget) m_drawingArea; + // int orig = GetDC()->GetLogicalFunction(); + // GetDC()->SetLogicalFunction (wxCOPY); + + // TODO: it may not be necessary to store m_pixmapOffsetX/Y; we + // should be able to calculate them. + XCopyArea (XtDisplay (drawingArea), m_backingPixmap, XtWindow (drawingArea), GetDC ()->gc, + m_pixmapOffsetX, m_pixmapOffsetY, + m_pixmapWidth, m_pixmapHeight, + 0, 0); + + // GetDC()->SetLogicalFunction (orig); + */ + } + else + { + wxPaintEvent event(GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } +} + +// SetSize, but as per old wxCanvas (with drawing widget etc.) +void wxWindow::CanvasSetSize (int x, int y, int w, int h, int sizeFlags) +{ + Widget drawingArea = (Widget) m_drawingArea; + bool managed = XtIsManaged(m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + + if (managed) + XtUnmanageChild (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + XtVaSetValues((Widget) m_drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL); + + if (x > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) + { + XtVaSetValues (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow, + XmNx, x, NULL); + } + + if (y > -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE)) + { + XtVaSetValues (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow, + XmNy, y, NULL); + } + + if (w > -1) + { + if (m_borderWidget) + { + XtVaSetValues ((Widget) m_borderWidget, XmNwidth, w, NULL); + short thick, margin; + XtVaGetValues ((Widget) m_borderWidget, + XmNshadowThickness, &thick, + XmNmarginWidth, &margin, + NULL); + w -= 2 * (thick + margin); + } + + XtVaSetValues ((Widget) m_scrolledWindow, XmNwidth, w, NULL); + + Dimension spacing; + Widget sbar; + XtVaGetValues ((Widget) m_scrolledWindow, + XmNspacing, &spacing, + XmNverticalScrollBar, &sbar, + NULL); + Dimension wsbar; + if (sbar) + XtVaGetValues (sbar, XmNwidth, &wsbar, NULL); + else + wsbar = 0; + + w -= (spacing + wsbar); + + XtVaSetValues ((Widget) m_drawingArea, XmNwidth, w, NULL); + } + if (h > -1) + { + if (m_borderWidget) + { + XtVaSetValues ((Widget) m_borderWidget, XmNheight, h, NULL); + short thick, margin; + XtVaGetValues ((Widget) m_borderWidget, + XmNshadowThickness, &thick, + XmNmarginHeight, &margin, + NULL); + h -= 2 * (thick + margin); + } + + XtVaSetValues ((Widget) m_scrolledWindow, XmNheight, h, NULL); + + Dimension spacing; + Widget sbar; + XtVaGetValues ((Widget) m_scrolledWindow, + XmNspacing, &spacing, + XmNhorizontalScrollBar, &sbar, + NULL); + Dimension wsbar; + if (sbar) + XtVaGetValues (sbar, XmNheight, &wsbar, NULL); + else + wsbar = 0; + + h -= (spacing + wsbar); + + XtVaSetValues ((Widget) m_drawingArea, XmNheight, h, NULL); + } + if (managed) + XtManageChild (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow); + XtVaSetValues((Widget) m_drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL); + + int ww, hh; + GetClientSize (&ww, &hh); + wxSizeEvent sizeEvent(wxSize(ww, hh), GetId()); + sizeEvent.SetEventObject(this); + + GetEventHandler()->ProcessEvent(sizeEvent); +} + +void wxWindow::CanvasSetClientSize (int w, int h) +{ + Widget drawingArea = (Widget) m_drawingArea; + + XtVaSetValues((Widget) m_drawingArea, XmNresizePolicy, XmRESIZE_ANY, NULL); + + if (w > -1) + XtVaSetValues ((Widget) m_drawingArea, XmNwidth, w, NULL); + if (h > -1) + XtVaSetValues ((Widget) m_drawingArea, XmNheight, h, NULL); + /* TODO: is this necessary? + allowRepainting = FALSE; + + XSync (XtDisplay (drawingArea), FALSE); + XEvent event; + while (XtAppPending (wxTheApp->appContext)) + { + XFlush (XtDisplay (drawingArea)); + XtAppNextEvent (wxTheApp->appContext, &event); + XtDispatchEvent (&event); + } + */ + + XtVaSetValues((Widget) m_drawingArea, XmNresizePolicy, XmRESIZE_NONE, NULL); + + /* TODO + allowRepainting = TRUE; + DoRefresh (); + */ + + wxSizeEvent sizeEvent(wxSize(w, h), GetId()); + sizeEvent.SetEventObject(this); + + GetEventHandler()->ProcessEvent(sizeEvent); +} + +void wxWindow::CanvasGetClientSize (int *w, int *h) const +{ + // Must return the same thing that was set via SetClientSize + Dimension xx, yy; + XtVaGetValues ((Widget) m_drawingArea, XmNwidth, &xx, XmNheight, &yy, NULL); + *w = xx; + *h = yy; +} + +void wxWindow::CanvasGetSize (int *w, int *h) const +{ + Dimension xx, yy; + if ((Widget) m_borderWidget) + XtVaGetValues ((Widget) m_borderWidget, XmNwidth, &xx, XmNheight, &yy, NULL); + else if ((Widget) m_scrolledWindow) + XtVaGetValues ((Widget) m_scrolledWindow, XmNwidth, &xx, XmNheight, &yy, NULL); + else + XtVaGetValues ((Widget) m_drawingArea, XmNwidth, &xx, XmNheight, &yy, NULL); + + *w = xx; + *h = yy; +} + +void wxWindow::CanvasGetPosition (int *x, int *y) const +{ + Position xx, yy; + XtVaGetValues (m_borderWidget ? (Widget) m_borderWidget : (Widget) m_scrolledWindow, XmNx, &xx, XmNy, &yy, NULL); + *x = xx; + *y = yy; +} -- 2.45.2