1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/popupwin.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
15 #include "wx/popupwin.h"
20 #include "wx/cursor.h"
25 #include <gdk/gdkkeysyms.h>
27 #include "wx/gtk1/win_gtk.h"
29 //-----------------------------------------------------------------------------
31 //-----------------------------------------------------------------------------
33 extern void wxapp_install_idle_handler();
36 //-----------------------------------------------------------------------------
38 //-----------------------------------------------------------------------------
41 static gint
gtk_popup_button_press (GtkWidget
*widget
, GdkEvent
*gdk_event
, wxPopupWindow
* win
)
43 GtkWidget
*child
= gtk_get_event_widget (gdk_event
);
45 /* We don't ask for button press events on the grab widget, so
46 * if an event is reported directly to the grab widget, it must
47 * be on a window outside the application (and thus we remove
48 * the popup window). Otherwise, we check if the widget is a child
49 * of the grab widget, and only remove the popup window if it
58 child
= child
->parent
;
62 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
63 event
.SetEventObject( win
);
65 (void)win
->GetEventHandler()->ProcessEvent( event
);
71 //-----------------------------------------------------------------------------
72 // "focus" from m_window
73 //-----------------------------------------------------------------------------
76 static gint
gtk_dialog_focus_callback( GtkWidget
*widget
, GtkDirectionType
WXUNUSED(d
), wxWindow
*WXUNUSED(win
) )
79 wxapp_install_idle_handler();
81 // This disables GTK's tab traversal
82 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus" );
87 //-----------------------------------------------------------------------------
89 //-----------------------------------------------------------------------------
92 bool gtk_dialog_delete_callback( GtkWidget
*WXUNUSED(widget
), GdkEvent
*WXUNUSED(event
), wxPopupWindow
*win
)
95 wxapp_install_idle_handler();
104 //-----------------------------------------------------------------------------
105 // "realize" from m_widget
106 //-----------------------------------------------------------------------------
108 /* we cannot MWM hints and icons before the widget has been realized,
109 so we do this directly after realization */
113 gtk_dialog_realized_callback( GtkWidget
* WXUNUSED(widget
), wxPopupWindow
*win
)
116 wxapp_install_idle_handler();
118 /* all this is for Motif Window Manager "hints" and is supposed to be
119 recognized by other WM as well. not tested. */
120 long decor
= (long) GDK_DECOR_BORDER
;
121 long func
= (long) GDK_FUNC_MOVE
;
123 gdk_window_set_decorations( win
->m_widget
->window
, (GdkWMDecoration
)decor
);
124 gdk_window_set_functions( win
->m_widget
->window
, (GdkWMFunction
)func
);
126 gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 0, 0, 1);
132 //-----------------------------------------------------------------------------
133 // InsertChild for wxPopupWindow
134 //-----------------------------------------------------------------------------
136 /* Callback for wxFrame. This very strange beast has to be used because
137 * C++ has no virtual methods in a constructor. We have to emulate a
138 * virtual function here as wxWidgets requires different ways to insert
139 * a child in container classes. */
141 static void wxInsertChildInDialog( wxPopupWindow
* parent
, wxWindow
* child
)
143 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
144 GTK_WIDGET(child
->m_widget
),
150 if (parent
->HasFlag(wxTAB_TRAVERSAL
))
152 /* we now allow a window to get the focus as long as it
153 doesn't have any children. */
154 GTK_WIDGET_UNSET_FLAGS( parent
->m_wxwindow
, GTK_CAN_FOCUS
);
158 //-----------------------------------------------------------------------------
160 //-----------------------------------------------------------------------------
162 BEGIN_EVENT_TABLE(wxPopupWindow
,wxPopupWindowBase
)
163 #ifdef __WXUNIVERSAL__
164 EVT_SIZE(wxPopupWindow::OnSize
)
168 wxPopupWindow::~wxPopupWindow()
172 bool wxPopupWindow::Create( wxWindow
*parent
, int style
)
174 m_needParent
= false;
176 if (!PreCreation( parent
, wxDefaultPosition
, wxDefaultSize
) ||
177 !CreateBase( parent
, -1, wxDefaultPosition
, wxDefaultSize
, style
, wxDefaultValidator
, wxT("popup") ))
179 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
183 // Unlike windows, top level windows are created hidden by default.
186 // All dialogs should really have this style
187 m_windowStyle
|= wxTAB_TRAVERSAL
;
189 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInDialog
;
191 m_widget
= gtk_window_new( GTK_WINDOW_POPUP
);
193 if ((m_parent
) && (GTK_IS_WINDOW(m_parent
->m_widget
)))
194 gtk_window_set_transient_for( GTK_WINDOW(m_widget
), GTK_WINDOW(m_parent
->m_widget
) );
196 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
198 gtk_signal_connect( GTK_OBJECT(m_widget
), "delete_event",
199 GTK_SIGNAL_FUNC(gtk_dialog_delete_callback
), (gpointer
)this );
201 m_wxwindow
= gtk_pizza_new();
202 gtk_widget_show( m_wxwindow
);
203 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
205 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
207 if (m_parent
) m_parent
->AddChild( this );
211 /* we cannot set MWM hints before the widget has
212 been realized, so we do this directly after realization */
213 gtk_signal_connect( GTK_OBJECT(m_widget
), "realize",
214 GTK_SIGNAL_FUNC(gtk_dialog_realized_callback
), (gpointer
) this );
216 // disable native tab traversal
217 gtk_signal_connect( GTK_OBJECT(m_widget
), "focus",
218 GTK_SIGNAL_FUNC(gtk_dialog_focus_callback
), (gpointer
)this );
220 gtk_signal_connect (GTK_OBJECT(m_widget
), "button_press_event",
221 GTK_SIGNAL_FUNC(gtk_popup_button_press
), (gpointer
)this );
226 void wxPopupWindow::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
228 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
231 void wxPopupWindow::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
233 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid dialog") );
234 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid dialog") );
236 if (m_resizing
) return; /* I don't like recursions */
242 int old_width
= m_width
;
243 int old_height
= m_height
;
245 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
247 if (x
!= -1) m_x
= x
;
248 if (y
!= -1) m_y
= y
;
249 if (width
!= -1) m_width
= width
;
250 if (height
!= -1) m_height
= height
;
261 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
263 if (width == -1) m_width = 80;
266 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
268 if (height == -1) m_height = 26;
272 int minWidth
= GetMinWidth(),
273 minHeight
= GetMinHeight(),
274 maxWidth
= GetMaxWidth(),
275 maxHeight
= GetMaxHeight();
277 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
278 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
279 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
280 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
282 if ((m_x
!= -1) || (m_y
!= -1))
284 if ((m_x
!= old_x
) || (m_y
!= old_y
))
286 /* we set the position here and when showing the dialog
287 for the first time in idle time */
288 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
292 if ((m_width
!= old_width
) || (m_height
!= old_height
))
294 gtk_widget_set_usize( m_widget
, m_width
, m_height
);
296 /* actual resizing is deferred to GtkOnSize in idle time and
297 when showing the dialog */
305 void wxPopupWindow::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
), int width
, int height
)
307 // due to a bug in gtk, x,y are always 0
311 if ((m_height
== height
) && (m_width
== width
) && (m_sizeSet
)) return;
312 if (!m_wxwindow
) return;
317 /* FIXME: is this a hack? */
318 /* Since for some reason GTK will revert to using maximum size ever set
319 for this window, we have to set geometry hints maxsize to match size
320 given. Also set the to that minsize since resizing isn't possible
324 gint flag
= GDK_HINT_MAX_SIZE
| GDK_HINT_MIN_SIZE
; // GDK_HINT_POS;
326 geom
.min_width
= m_width
;
327 geom
.min_height
= m_height
;
328 geom
.max_width
= m_width
;
329 geom
.max_height
= m_height
;
330 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
333 (GdkWindowHints
) flag
);
338 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
339 event
.SetEventObject( this );
340 GetEventHandler()->ProcessEvent( event
);
343 void wxPopupWindow::OnInternalIdle()
345 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
346 GtkOnSize( m_x
, m_y
, m_width
, m_height
);
348 wxWindow::OnInternalIdle();
351 bool wxPopupWindow::Show( bool show
)
353 if (show
&& !m_sizeSet
)
355 /* by calling GtkOnSize here, we don't have to call
356 either after showing the frame, which would entail
357 much ugly flicker nor from within the size_allocate
358 handler, because GTK 1.1.X forbids that. */
360 GtkOnSize( m_x
, m_y
, m_width
, m_height
);
363 bool ret
= wxWindow::Show( show
);
368 #endif // wxUSE_POPUPWIN