]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/popupwin.cpp
don't give an error when editing of the items label is cancelled (patch 1482176)
[wxWidgets.git] / src / gtk / popupwin.cpp
CommitLineData
9f41d601 1/////////////////////////////////////////////////////////////////////////////
670f9935 2// Name: src/gtk/popupwin.cpp
9f41d601
RR
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
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
f3ecfad1
VS
12
13#if wxUSE_POPUPWIN
14
9f41d601 15#include "wx/popupwin.h"
670f9935
WS
16
17#ifndef WX_PRECOMP
18 #include "wx/app.h"
76b49cf4 19 #include "wx/frame.h"
670f9935
WS
20#endif // WX_PRECOMP
21
9f41d601
RR
22#include "wx/cursor.h"
23
24#include <gdk/gdk.h>
25#include <gtk/gtk.h>
26#include <gdk/gdkkeysyms.h>
27
84833214 28#include "wx/gtk/private.h" //for idle stuff
9f41d601
RR
29#include "wx/gtk/win_gtk.h"
30
f7204798
RR
31//-----------------------------------------------------------------------------
32// "button_press"
33//-----------------------------------------------------------------------------
34
865bb325 35extern "C" {
f7204798
RR
36static gint gtk_popup_button_press (GtkWidget *widget, GdkEvent *gdk_event, wxPopupWindow* win )
37{
38 GtkWidget *child = gtk_get_event_widget (gdk_event);
39
33c0d0ed
RR
40 /* Ignore events sent out before we connected to the signal */
41 if (win->m_time >= ((GdkEventButton*)gdk_event)->time)
42 return FALSE;
43
44 /* We don't ask for button press events on the grab widget, so
45 * if an event is reported directly to the grab widget, it must
46 * be on a window outside the application (and thus we remove
47 * the popup window). Otherwise, we check if the widget is a child
48 * of the grab widget, and only remove the popup window if it
49 * is not. */
f7204798
RR
50 if (child != widget)
51 {
52 while (child)
88d19775
MR
53 {
54 if (child == widget)
55 return FALSE;
f7204798
RR
56 child = child->parent;
57 }
58 }
59
60 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
61 event.SetEventObject( win );
62
63 (void)win->GetEventHandler()->ProcessEvent( event );
64
65 return TRUE;
66}
865bb325 67}
f7204798 68
9f41d601
RR
69//-----------------------------------------------------------------------------
70// "focus" from m_window
71//-----------------------------------------------------------------------------
72
865bb325 73extern "C" {
9f41d601
RR
74static gint gtk_dialog_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
75{
76 if (g_isIdle)
77 wxapp_install_idle_handler();
78
33c0d0ed 79 /* This disables GTK's tab traversal */
9fa72bd2 80 g_signal_stop_emission_by_name (widget, "focus");
9f41d601
RR
81 return TRUE;
82}
865bb325 83}
9f41d601
RR
84
85//-----------------------------------------------------------------------------
86// "delete_event"
87//-----------------------------------------------------------------------------
88
865bb325 89extern "C" {
9f41d601
RR
90bool gtk_dialog_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxPopupWindow *win )
91{
92 if (g_isIdle)
93 wxapp_install_idle_handler();
94
95 if (win->IsEnabled())
96 win->Close();
97
98 return TRUE;
99}
865bb325 100}
9f41d601 101
9f41d601
RR
102//-----------------------------------------------------------------------------
103// "realize" from m_widget
104//-----------------------------------------------------------------------------
105
106/* we cannot MWM hints and icons before the widget has been realized,
107 so we do this directly after realization */
108
865bb325 109extern "C" {
9f41d601
RR
110static gint
111gtk_dialog_realized_callback( GtkWidget * WXUNUSED(widget), wxPopupWindow *win )
112{
113 if (g_isIdle)
114 wxapp_install_idle_handler();
115
116 /* all this is for Motif Window Manager "hints" and is supposed to be
117 recognized by other WM as well. not tested. */
118 long decor = (long) GDK_DECOR_BORDER;
119 long func = (long) GDK_FUNC_MOVE ;
120
121 gdk_window_set_decorations( win->m_widget->window, (GdkWMDecoration)decor);
122 gdk_window_set_functions( win->m_widget->window, (GdkWMFunction)func);
123
43a52404 124 gtk_window_set_resizable(GTK_WINDOW(win->m_widget), FALSE);
9f41d601
RR
125
126 return FALSE;
127}
865bb325 128}
9f41d601
RR
129
130//-----------------------------------------------------------------------------
131// InsertChild for wxPopupWindow
132//-----------------------------------------------------------------------------
133
134/* Callback for wxFrame. This very strange beast has to be used because
135 * C++ has no virtual methods in a constructor. We have to emulate a
77ffb593 136 * virtual function here as wxWidgets requires different ways to insert
9f41d601
RR
137 * a child in container classes. */
138
139static void wxInsertChildInDialog( wxPopupWindow* parent, wxWindow* child )
140{
141 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
88d19775
MR
142 GTK_WIDGET(child->m_widget),
143 child->m_x,
144 child->m_y,
145 child->m_width,
146 child->m_height );
9f41d601
RR
147
148 if (parent->HasFlag(wxTAB_TRAVERSAL))
149 {
150 /* we now allow a window to get the focus as long as it
151 doesn't have any children. */
152 GTK_WIDGET_UNSET_FLAGS( parent->m_wxwindow, GTK_CAN_FOCUS );
153 }
154}
155
156//-----------------------------------------------------------------------------
157// wxPopupWindow
158//-----------------------------------------------------------------------------
159
8f0db49c
VS
160BEGIN_EVENT_TABLE(wxPopupWindow,wxPopupWindowBase)
161#ifdef __WXUNIVERSAL__
6522713c 162 EVT_SIZE(wxPopupWindow::OnSize)
8f0db49c 163#endif
9f41d601
RR
164END_EVENT_TABLE()
165
ad9fb033
RR
166wxPopupWindow::~wxPopupWindow()
167{
ad9fb033
RR
168}
169
9f41d601
RR
170bool wxPopupWindow::Create( wxWindow *parent, int style )
171{
670f9935 172 m_needParent = false;
9f41d601
RR
173
174 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
2b5f62a0 175 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("popup") ))
9f41d601
RR
176 {
177 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
670f9935 178 return false;
9f41d601
RR
179 }
180
da19de36
RR
181 // Unlike windows, top level windows are created hidden by default.
182 m_isShown = false;
88d19775 183
9f41d601
RR
184 // All dialogs should really have this style
185 m_windowStyle |= wxTAB_TRAVERSAL;
186
187 m_insertCallback = (wxInsertChildFunction) wxInsertChildInDialog;
188
189 m_widget = gtk_window_new( GTK_WINDOW_POPUP );
190
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) );
193
194 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
195
9fa72bd2
MR
196 g_signal_connect (m_widget, "delete_event",
197 G_CALLBACK (gtk_dialog_delete_callback), this);
9f41d601
RR
198
199 m_wxwindow = gtk_pizza_new();
200 gtk_widget_show( m_wxwindow );
201 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
202
203 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
204
205 if (m_parent) m_parent->AddChild( this );
206
207 PostCreation();
208
209 /* we cannot set MWM hints before the widget has
210 been realized, so we do this directly after realization */
9fa72bd2
MR
211 g_signal_connect (m_widget, "realize",
212 G_CALLBACK (gtk_dialog_realized_callback), this);
9f41d601 213
f7204798 214 // disable native tab traversal
9fa72bd2
MR
215 g_signal_connect (m_widget, "focus",
216 G_CALLBACK (gtk_dialog_focus_callback), this);
9f41d601 217
33c0d0ed
RR
218 m_time = gtk_get_current_event_time();
219
9fa72bd2
MR
220 g_signal_connect (m_widget, "button_press_event",
221 G_CALLBACK (gtk_popup_button_press), this);
88d19775 222
670f9935 223 return true;
9f41d601
RR
224}
225
226void wxPopupWindow::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
227{
228 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
229}
230
231void wxPopupWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
232{
233 wxASSERT_MSG( (m_widget != NULL), wxT("invalid dialog") );
234 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid dialog") );
235
236 if (m_resizing) return; /* I don't like recursions */
670f9935 237 m_resizing = true;
9f41d601
RR
238
239 int old_x = m_x;
240 int old_y = m_y;
241
242 int old_width = m_width;
243 int old_height = m_height;
244
245 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
246 {
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;
251 }
252 else
253 {
254 m_x = x;
255 m_y = y;
256 m_width = width;
257 m_height = height;
258 }
259
260/*
261 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
262 {
263 if (width == -1) m_width = 80;
264 }
265
266 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
267 {
268 if (height == -1) m_height = 26;
269 }
270*/
271
e7dda1ff
VS
272 int minWidth = GetMinWidth(),
273 minHeight = GetMinHeight(),
274 maxWidth = GetMaxWidth(),
275 maxHeight = GetMaxHeight();
276
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;
9f41d601
RR
281
282 if ((m_x != -1) || (m_y != -1))
283 {
284 if ((m_x != old_x) || (m_y != old_y))
285 {
286 /* we set the position here and when showing the dialog
287 for the first time in idle time */
cd6645a2
MR
288 // Where does that happen in idle time? I do not see it anywhere - MR
289 gtk_window_move( GTK_WINDOW(m_widget), m_x, m_y );
9f41d601
RR
290 }
291 }
292
293 if ((m_width != old_width) || (m_height != old_height))
294 {
370dc79c 295 gtk_widget_set_size_request( m_widget, m_width, m_height );
9f41d601
RR
296
297 /* actual resizing is deferred to GtkOnSize in idle time and
298 when showing the dialog */
670f9935 299 m_sizeSet = false;
9f41d601
RR
300
301 }
302
670f9935 303 m_resizing = false;
9f41d601
RR
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
670f9935 337 m_sizeSet = true;
9f41d601
RR
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 }
88d19775 363
9f41d601 364 bool ret = wxWindow::Show( show );
88d19775 365
9f41d601
RR
366 return ret;
367}
368
f3ecfad1 369#endif // wxUSE_POPUPWIN