1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "popupwin.h"
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
19 #include "wx/popupwin.h"
22 #include "wx/cursor.h"
26 #include <gdk/gdkkeysyms.h>
28 #include "wx/gtk/win_gtk.h"
30 //-----------------------------------------------------------------------------
32 //-----------------------------------------------------------------------------
34 extern void wxapp_install_idle_handler();
37 //-----------------------------------------------------------------------------
39 //-----------------------------------------------------------------------------
42 static gint
gtk_popup_button_press (GtkWidget
*widget
, GdkEvent
*gdk_event
, wxPopupWindow
* win
)
44 GtkWidget
*child
= gtk_get_event_widget (gdk_event
);
46 /* We don't ask for button press events on the grab widget, so
47 * if an event is reported directly to the grab widget, it must
48 * be on a window outside the application (and thus we remove
49 * the popup window). Otherwise, we check if the widget is a child
50 * of the grab widget, and only remove the popup window if it
59 child
= child
->parent
;
63 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
64 event
.SetEventObject( win
);
66 (void)win
->GetEventHandler()->ProcessEvent( event
);
72 //-----------------------------------------------------------------------------
73 // "focus" from m_window
74 //-----------------------------------------------------------------------------
77 static gint
gtk_dialog_focus_callback( GtkWidget
*widget
, GtkDirectionType
WXUNUSED(d
), wxWindow
*WXUNUSED(win
) )
80 wxapp_install_idle_handler();
82 // This disables GTK's tab traversal
83 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus" );
88 //-----------------------------------------------------------------------------
90 //-----------------------------------------------------------------------------
93 bool gtk_dialog_delete_callback( GtkWidget
*WXUNUSED(widget
), GdkEvent
*WXUNUSED(event
), wxPopupWindow
*win
)
96 wxapp_install_idle_handler();
105 //-----------------------------------------------------------------------------
106 // "realize" from m_widget
107 //-----------------------------------------------------------------------------
109 /* we cannot MWM hints and icons before the widget has been realized,
110 so we do this directly after realization */
114 gtk_dialog_realized_callback( GtkWidget
* WXUNUSED(widget
), wxPopupWindow
*win
)
117 wxapp_install_idle_handler();
119 /* all this is for Motif Window Manager "hints" and is supposed to be
120 recognized by other WM as well. not tested. */
121 long decor
= (long) GDK_DECOR_BORDER
;
122 long func
= (long) GDK_FUNC_MOVE
;
124 gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
);
125 gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
);
127 gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 0, 0, 1);
133 //-----------------------------------------------------------------------------
134 // InsertChild for wxPopupWindow
135 //-----------------------------------------------------------------------------
137 /* Callback for wxFrame. This very strange beast has to be used because
138 * C++ has no virtual methods in a constructor. We have to emulate a
139 * virtual function here as wxWidgets requires different ways to insert
140 * a child in container classes. */
142 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child
)
144 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
145 GTK_WIDGET(child
->m_widget
),
151 if (parent
->HasFlag(wxTAB_TRAVERSAL
))
153 /* we now allow a window to get the focus as long as it
154 doesn't have any children. */
155 GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS
);
159 //-----------------------------------------------------------------------------
161 //-----------------------------------------------------------------------------
163 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
)
164 #ifdef __WXUNIVERSAL__
165 EVT_SIZE(wxPopupWindow::OnSize
)
169 wxPopupWindow::~wxPopupWindow()
173 bool wxPopupWindow::Create( wxWindow
*parent
, int style
)
175 m_needParent
= FALSE
;
177 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
178 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") ))
180 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
184 // All dialogs should really have this style
185 m_windowStyle
|= wxTAB_TRAVERSAL
;
187 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInDialog
;
189 m_widget
= gtk_window_new( GTK_WINDOW_POPUP
);
191 if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
)))
192 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
194 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
196 gtk_signal_connect( GTK_OBJECT(m_widget
), "delete_event",
197 GTK_SIGNAL_FUNC(gtk_dialog_delete_callback
), (gpointer
)this );
199 m_wxwindow
= gtk_pizza_new();
200 gtk_widget_show( m_wxwindow
);
201 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
203 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
205 if (m_parent
) m_parent
->AddChild( this );
209 /* we cannot set MWM hints before the widget has
210 been realized, so we do this directly after realization */
211 gtk_signal_connect( GTK_OBJECT(m_widget
), "realize",
212 GTK_SIGNAL_FUNC(gtk_dialog_realized_callback
), (gpointer
) this );
214 // disable native tab traversal
215 gtk_signal_connect( GTK_OBJECT(m_widget
), "focus",
216 GTK_SIGNAL_FUNC(gtk_dialog_focus_callback
), (gpointer
)this );
218 gtk_signal_connect (GTK_OBJECT(m_widget
), "button_press_event",
219 GTK_SIGNAL_FUNC(gtk_popup_button_press
), (gpointer
)this );
224 void wxPopupWindow::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
226 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
229 void wxPopupWindow::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
231 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid dialog") );
232 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid dialog") );
234 if (m_resizing
) return; /* I don't like recursions */
240 int old_width
= m_width
;
241 int old_height
= m_height
;
243 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
245 if (x
!= -1) m_x
= x
;
246 if (y
!= -1) m_y
= y
;
247 if (width
!= -1) m_width
= width
;
248 if (height
!= -1) m_height
= height
;
259 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
261 if (width == -1) m_width = 80;
264 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
266 if (height == -1) m_height = 26;
270 int minWidth
= GetMinWidth(),
271 minHeight
= GetMinHeight(),
272 maxWidth
= GetMaxWidth(),
273 maxHeight
= GetMaxHeight();
275 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
276 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
277 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
278 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
280 if ((m_x
!= -1) || (m_y
!= -1))
282 if ((m_x
!= old_x
) || (m_y
!= old_y
))
284 /* we set the position here and when showing the dialog
285 for the first time in idle time */
286 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
290 if ((m_width
!= old_width
) || (m_height
!= old_height
))
292 gtk_widget_set_usize( m_widget
, m_width
, m_height
);
294 /* actual resizing is deferred to GtkOnSize in idle time and
295 when showing the dialog */
303 void wxPopupWindow::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
), int width
, int height
)
305 // due to a bug in gtk, x,y are always 0
309 if ((m_height
== height
) && (m_width
== width
) && (m_sizeSet
)) return;
310 if (!m_wxwindow
) return;
315 /* FIXME: is this a hack? */
316 /* Since for some reason GTK will revert to using maximum size ever set
317 for this window, we have to set geometry hints maxsize to match size
318 given. Also set the to that minsize since resizing isn't possible
322 gint flag
= GDK_HINT_MAX_SIZE
| GDK_HINT_MIN_SIZE
; // GDK_HINT_POS;
324 geom
.min_width
= m_width
;
325 geom
.min_height
= m_height
;
326 geom
.max_width
= m_width
;
327 geom
.max_height
= m_height
;
328 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
331 (GdkWindowHints
) flag
);
336 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
337 event
.SetEventObject( this );
338 GetEventHandler()->ProcessEvent( event
);
341 void wxPopupWindow::OnInternalIdle()
343 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
344 GtkOnSize( m_x
, m_y
, m_width
, m_height
);
346 wxWindow::OnInternalIdle();
349 bool wxPopupWindow::Show( bool show
)
351 if (show
&& !m_sizeSet
)
353 /* by calling GtkOnSize here, we don't have to call
354 either after showing the frame, which would entail
355 much ugly flicker nor from within the size_allocate
356 handler, because GTK 1.1.X forbids that. */
358 GtkOnSize( m_x
, m_y
, m_width
, m_height
);
361 bool ret
= wxWindow::Show( show
);
366 #endif // wxUSE_POPUPWIN