]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/popupwin.cpp
Fix memory leak when a spacer is added, and crash when a window is added before wxSiz...
[wxWidgets.git] / src / gtk1 / popupwin.cpp
CommitLineData
9f41d601
RR
1/////////////////////////////////////////////////////////////////////////////
2// Name: popupwin.cpp
3// Purpose:
4// Author: Robert Roebling
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
9f41d601
RR
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2 10#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
9f41d601
RR
11#pragma implementation "popupwin.h"
12#endif
13
14f355c2
VS
14// For compilers that support precompilation, includes "wx.h".
15#include "wx/wxprec.h"
f3ecfad1
VS
16
17#if wxUSE_POPUPWIN
18
9f41d601
RR
19#include "wx/popupwin.h"
20#include "wx/frame.h"
21#include "wx/app.h"
22#include "wx/cursor.h"
23
24#include <gdk/gdk.h>
25#include <gtk/gtk.h>
26#include <gdk/gdkkeysyms.h>
27
28#include "wx/gtk/win_gtk.h"
29
30//-----------------------------------------------------------------------------
31// idle system
32//-----------------------------------------------------------------------------
33
34extern void wxapp_install_idle_handler();
35extern bool g_isIdle;
36
f7204798
RR
37//-----------------------------------------------------------------------------
38// "button_press"
39//-----------------------------------------------------------------------------
40
865bb325 41extern "C" {
f7204798
RR
42static gint gtk_popup_button_press (GtkWidget *widget, GdkEvent *gdk_event, wxPopupWindow* win )
43{
44 GtkWidget *child = gtk_get_event_widget (gdk_event);
45
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
51 * is not.
52 */
53 if (child != widget)
54 {
55 while (child)
56 {
57 if (child == widget)
58 return FALSE;
59 child = child->parent;
60 }
61 }
62
63 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
64 event.SetEventObject( win );
65
66 (void)win->GetEventHandler()->ProcessEvent( event );
67
68 return TRUE;
69}
865bb325 70}
f7204798 71
9f41d601
RR
72//-----------------------------------------------------------------------------
73// "focus" from m_window
74//-----------------------------------------------------------------------------
75
865bb325 76extern "C" {
9f41d601
RR
77static gint gtk_dialog_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
78{
79 if (g_isIdle)
80 wxapp_install_idle_handler();
81
82 // This disables GTK's tab traversal
83 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus" );
84 return TRUE;
85}
865bb325 86}
9f41d601
RR
87
88//-----------------------------------------------------------------------------
89// "delete_event"
90//-----------------------------------------------------------------------------
91
865bb325 92extern "C" {
9f41d601
RR
93bool gtk_dialog_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxPopupWindow *win )
94{
95 if (g_isIdle)
96 wxapp_install_idle_handler();
97
98 if (win->IsEnabled())
99 win->Close();
100
101 return TRUE;
102}
865bb325 103}
9f41d601 104
9f41d601
RR
105//-----------------------------------------------------------------------------
106// "realize" from m_widget
107//-----------------------------------------------------------------------------
108
109/* we cannot MWM hints and icons before the widget has been realized,
110 so we do this directly after realization */
111
865bb325 112extern "C" {
9f41d601
RR
113static gint
114gtk_dialog_realized_callback( GtkWidget * WXUNUSED(widget), wxPopupWindow *win )
115{
116 if (g_isIdle)
117 wxapp_install_idle_handler();
118
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 ;
123
124 gdk_window_set_decorations( win->m_widget->window, (GdkWMDecoration)decor);
125 gdk_window_set_functions( win->m_widget->window, (GdkWMFunction)func);
126
f7204798 127 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 0, 0, 1);
9f41d601
RR
128
129 return FALSE;
130}
865bb325 131}
9f41d601
RR
132
133//-----------------------------------------------------------------------------
134// InsertChild for wxPopupWindow
135//-----------------------------------------------------------------------------
136
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
77ffb593 139 * virtual function here as wxWidgets requires different ways to insert
9f41d601
RR
140 * a child in container classes. */
141
142static void wxInsertChildInDialog( wxPopupWindow* parent, wxWindow* child )
143{
144 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
145 GTK_WIDGET(child->m_widget),
146 child->m_x,
147 child->m_y,
148 child->m_width,
149 child->m_height );
150
151 if (parent->HasFlag(wxTAB_TRAVERSAL))
152 {
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 );
156 }
157}
158
159//-----------------------------------------------------------------------------
160// wxPopupWindow
161//-----------------------------------------------------------------------------
162
8f0db49c
VS
163BEGIN_EVENT_TABLE(wxPopupWindow,wxPopupWindowBase)
164#ifdef __WXUNIVERSAL__
6522713c 165 EVT_SIZE(wxPopupWindow::OnSize)
8f0db49c 166#endif
9f41d601
RR
167END_EVENT_TABLE()
168
ad9fb033
RR
169wxPopupWindow::~wxPopupWindow()
170{
ad9fb033
RR
171}
172
9f41d601
RR
173bool wxPopupWindow::Create( wxWindow *parent, int style )
174{
175 m_needParent = FALSE;
176
177 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
2b5f62a0 178 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("popup") ))
9f41d601
RR
179 {
180 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
181 return FALSE;
182 }
183
da19de36
RR
184 // Unlike windows, top level windows are created hidden by default.
185 m_isShown = false;
186
9f41d601
RR
187 // All dialogs should really have this style
188 m_windowStyle |= wxTAB_TRAVERSAL;
189
190 m_insertCallback = (wxInsertChildFunction) wxInsertChildInDialog;
191
192 m_widget = gtk_window_new( GTK_WINDOW_POPUP );
193
194 if ((m_parent) && (GTK_IS_WINDOW(m_parent->m_widget)))
195 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
196
197 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
198
199 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
200 GTK_SIGNAL_FUNC(gtk_dialog_delete_callback), (gpointer)this );
201
202 m_wxwindow = gtk_pizza_new();
203 gtk_widget_show( m_wxwindow );
204 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
205
206 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
207
208 if (m_parent) m_parent->AddChild( this );
209
210 PostCreation();
211
212 /* we cannot set MWM hints before the widget has
213 been realized, so we do this directly after realization */
214 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
215 GTK_SIGNAL_FUNC(gtk_dialog_realized_callback), (gpointer) this );
216
f7204798 217 // disable native tab traversal
9f41d601
RR
218 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
219 GTK_SIGNAL_FUNC(gtk_dialog_focus_callback), (gpointer)this );
220
fbe99a7e
RR
221 gtk_signal_connect (GTK_OBJECT(m_widget), "button_press_event",
222 GTK_SIGNAL_FUNC(gtk_popup_button_press), (gpointer)this );
f7204798 223
9f41d601
RR
224 return TRUE;
225}
226
227void wxPopupWindow::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
228{
229 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
230}
231
232void wxPopupWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
233{
234 wxASSERT_MSG( (m_widget != NULL), wxT("invalid dialog") );
235 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid dialog") );
236
237 if (m_resizing) return; /* I don't like recursions */
238 m_resizing = TRUE;
239
240 int old_x = m_x;
241 int old_y = m_y;
242
243 int old_width = m_width;
244 int old_height = m_height;
245
246 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
247 {
248 if (x != -1) m_x = x;
249 if (y != -1) m_y = y;
250 if (width != -1) m_width = width;
251 if (height != -1) m_height = height;
252 }
253 else
254 {
255 m_x = x;
256 m_y = y;
257 m_width = width;
258 m_height = height;
259 }
260
261/*
262 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
263 {
264 if (width == -1) m_width = 80;
265 }
266
267 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
268 {
269 if (height == -1) m_height = 26;
270 }
271*/
272
e7dda1ff
VS
273 int minWidth = GetMinWidth(),
274 minHeight = GetMinHeight(),
275 maxWidth = GetMaxWidth(),
276 maxHeight = GetMaxHeight();
277
278 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
279 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
280 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
281 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
9f41d601
RR
282
283 if ((m_x != -1) || (m_y != -1))
284 {
285 if ((m_x != old_x) || (m_y != old_y))
286 {
287 /* we set the position here and when showing the dialog
288 for the first time in idle time */
289 gtk_widget_set_uposition( m_widget, m_x, m_y );
290 }
291 }
292
293 if ((m_width != old_width) || (m_height != old_height))
294 {
295 gtk_widget_set_usize( m_widget, m_width, m_height );
296
297 /* actual resizing is deferred to GtkOnSize in idle time and
298 when showing the dialog */
299 m_sizeSet = FALSE;
300
301 }
302
303 m_resizing = FALSE;
304}
305
306void wxPopupWindow::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y), int width, int height )
307{
308 // due to a bug in gtk, x,y are always 0
309 // m_x = x;
310 // m_y = y;
311
312 if ((m_height == height) && (m_width == width) && (m_sizeSet)) return;
313 if (!m_wxwindow) return;
314
315 m_width = width;
316 m_height = height;
317
ef00dc09 318 /* FIXME: is this a hack? */
7e027698
RR
319 /* Since for some reason GTK will revert to using maximum size ever set
320 for this window, we have to set geometry hints maxsize to match size
321 given. Also set the to that minsize since resizing isn't possible
322 anyway. */
9f41d601
RR
323
324 /* set size hints */
7e027698 325 gint flag = GDK_HINT_MAX_SIZE | GDK_HINT_MIN_SIZE; // GDK_HINT_POS;
9f41d601 326 GdkGeometry geom;
7e027698
RR
327 geom.min_width = m_width;
328 geom.min_height = m_height;
ef00dc09
RR
329 geom.max_width = m_width;
330 geom.max_height = m_height;
9f41d601
RR
331 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
332 (GtkWidget*) NULL,
333 &geom,
334 (GdkWindowHints) flag );
335
ef00dc09 336
9f41d601
RR
337 m_sizeSet = TRUE;
338
339 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
340 event.SetEventObject( this );
341 GetEventHandler()->ProcessEvent( event );
342}
343
344void wxPopupWindow::OnInternalIdle()
345{
346 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
347 GtkOnSize( m_x, m_y, m_width, m_height );
348
349 wxWindow::OnInternalIdle();
350}
351
352bool wxPopupWindow::Show( bool show )
353{
354 if (show && !m_sizeSet)
355 {
356 /* by calling GtkOnSize here, we don't have to call
357 either after showing the frame, which would entail
358 much ugly flicker nor from within the size_allocate
359 handler, because GTK 1.1.X forbids that. */
360
361 GtkOnSize( m_x, m_y, m_width, m_height );
362 }
ad9fb033 363
9f41d601 364 bool ret = wxWindow::Show( show );
ad9fb033 365
9f41d601
RR
366 return ret;
367}
368
f3ecfad1 369#endif // wxUSE_POPUPWIN