]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/popupwin.cpp
rebaked after adding new string-related headers
[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"
c8326d64 20 #include "wx/cursor.h"
670f9935
WS
21#endif // WX_PRECOMP
22
9f41d601
RR
23#include <gdk/gdk.h>
24#include <gtk/gtk.h>
25#include <gdk/gdkkeysyms.h>
26
84833214 27#include "wx/gtk/private.h" //for idle stuff
9f41d601
RR
28#include "wx/gtk/win_gtk.h"
29
f7204798
RR
30//-----------------------------------------------------------------------------
31// "button_press"
32//-----------------------------------------------------------------------------
33
865bb325 34extern "C" {
f7204798
RR
35static gint gtk_popup_button_press (GtkWidget *widget, GdkEvent *gdk_event, wxPopupWindow* win )
36{
37 GtkWidget *child = gtk_get_event_widget (gdk_event);
38
33c0d0ed
RR
39 /* Ignore events sent out before we connected to the signal */
40 if (win->m_time >= ((GdkEventButton*)gdk_event)->time)
41 return FALSE;
42
43 /* We don't ask for button press events on the grab widget, so
44 * if an event is reported directly to the grab widget, it must
45 * be on a window outside the application (and thus we remove
46 * the popup window). Otherwise, we check if the widget is a child
47 * of the grab widget, and only remove the popup window if it
48 * is not. */
f7204798
RR
49 if (child != widget)
50 {
51 while (child)
88d19775
MR
52 {
53 if (child == widget)
54 return FALSE;
f7204798
RR
55 child = child->parent;
56 }
57 }
58
59 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
60 event.SetEventObject( win );
61
62 (void)win->GetEventHandler()->ProcessEvent( event );
63
64 return TRUE;
65}
865bb325 66}
f7204798 67
9f41d601
RR
68//-----------------------------------------------------------------------------
69// "delete_event"
70//-----------------------------------------------------------------------------
71
865bb325 72extern "C" {
9f41d601
RR
73bool gtk_dialog_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxPopupWindow *win )
74{
75 if (g_isIdle)
76 wxapp_install_idle_handler();
77
78 if (win->IsEnabled())
79 win->Close();
80
81 return TRUE;
82}
865bb325 83}
9f41d601 84
9f41d601
RR
85//-----------------------------------------------------------------------------
86// "realize" from m_widget
87//-----------------------------------------------------------------------------
88
89/* we cannot MWM hints and icons before the widget has been realized,
90 so we do this directly after realization */
91
865bb325 92extern "C" {
9f41d601
RR
93static gint
94gtk_dialog_realized_callback( GtkWidget * WXUNUSED(widget), wxPopupWindow *win )
95{
96 if (g_isIdle)
97 wxapp_install_idle_handler();
98
99 /* all this is for Motif Window Manager "hints" and is supposed to be
100 recognized by other WM as well. not tested. */
101 long decor = (long) GDK_DECOR_BORDER;
102 long func = (long) GDK_FUNC_MOVE ;
103
104 gdk_window_set_decorations( win->m_widget->window, (GdkWMDecoration)decor);
105 gdk_window_set_functions( win->m_widget->window, (GdkWMFunction)func);
106
43a52404 107 gtk_window_set_resizable(GTK_WINDOW(win->m_widget), FALSE);
9f41d601
RR
108
109 return FALSE;
110}
865bb325 111}
9f41d601
RR
112
113//-----------------------------------------------------------------------------
114// InsertChild for wxPopupWindow
115//-----------------------------------------------------------------------------
116
117/* Callback for wxFrame. This very strange beast has to be used because
118 * C++ has no virtual methods in a constructor. We have to emulate a
77ffb593 119 * virtual function here as wxWidgets requires different ways to insert
9f41d601
RR
120 * a child in container classes. */
121
122static void wxInsertChildInDialog( wxPopupWindow* parent, wxWindow* child )
123{
124 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
88d19775
MR
125 GTK_WIDGET(child->m_widget),
126 child->m_x,
127 child->m_y,
128 child->m_width,
129 child->m_height );
9f41d601
RR
130
131 if (parent->HasFlag(wxTAB_TRAVERSAL))
132 {
133 /* we now allow a window to get the focus as long as it
134 doesn't have any children. */
135 GTK_WIDGET_UNSET_FLAGS( parent->m_wxwindow, GTK_CAN_FOCUS );
136 }
137}
138
139//-----------------------------------------------------------------------------
140// wxPopupWindow
141//-----------------------------------------------------------------------------
142
8f0db49c
VS
143BEGIN_EVENT_TABLE(wxPopupWindow,wxPopupWindowBase)
144#ifdef __WXUNIVERSAL__
6522713c 145 EVT_SIZE(wxPopupWindow::OnSize)
8f0db49c 146#endif
9f41d601
RR
147END_EVENT_TABLE()
148
ad9fb033
RR
149wxPopupWindow::~wxPopupWindow()
150{
ad9fb033
RR
151}
152
9f41d601
RR
153bool wxPopupWindow::Create( wxWindow *parent, int style )
154{
670f9935 155 m_needParent = false;
9f41d601
RR
156
157 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
2b5f62a0 158 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("popup") ))
9f41d601
RR
159 {
160 wxFAIL_MSG( wxT("wxPopupWindow creation failed") );
670f9935 161 return false;
9f41d601
RR
162 }
163
da19de36
RR
164 // Unlike windows, top level windows are created hidden by default.
165 m_isShown = false;
88d19775 166
9f41d601
RR
167 // All dialogs should really have this style
168 m_windowStyle |= wxTAB_TRAVERSAL;
169
170 m_insertCallback = (wxInsertChildFunction) wxInsertChildInDialog;
171
172 m_widget = gtk_window_new( GTK_WINDOW_POPUP );
173
174 if ((m_parent) && (GTK_IS_WINDOW(m_parent->m_widget)))
175 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
176
177 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
178
9fa72bd2
MR
179 g_signal_connect (m_widget, "delete_event",
180 G_CALLBACK (gtk_dialog_delete_callback), this);
9f41d601
RR
181
182 m_wxwindow = gtk_pizza_new();
183 gtk_widget_show( m_wxwindow );
184 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
185
186 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
187
188 if (m_parent) m_parent->AddChild( this );
189
190 PostCreation();
191
192 /* we cannot set MWM hints before the widget has
193 been realized, so we do this directly after realization */
9fa72bd2
MR
194 g_signal_connect (m_widget, "realize",
195 G_CALLBACK (gtk_dialog_realized_callback), this);
9f41d601 196
33c0d0ed
RR
197 m_time = gtk_get_current_event_time();
198
9fa72bd2
MR
199 g_signal_connect (m_widget, "button_press_event",
200 G_CALLBACK (gtk_popup_button_press), this);
88d19775 201
670f9935 202 return true;
9f41d601
RR
203}
204
205void wxPopupWindow::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
206{
207 wxFAIL_MSG( wxT("DoMoveWindow called for wxPopupWindow") );
208}
209
210void wxPopupWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
211{
212 wxASSERT_MSG( (m_widget != NULL), wxT("invalid dialog") );
213 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid dialog") );
214
215 if (m_resizing) return; /* I don't like recursions */
670f9935 216 m_resizing = true;
9f41d601
RR
217
218 int old_x = m_x;
219 int old_y = m_y;
220
221 int old_width = m_width;
222 int old_height = m_height;
223
224 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
225 {
226 if (x != -1) m_x = x;
227 if (y != -1) m_y = y;
228 if (width != -1) m_width = width;
229 if (height != -1) m_height = height;
230 }
231 else
232 {
233 m_x = x;
234 m_y = y;
235 m_width = width;
236 m_height = height;
237 }
238
239/*
240 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
241 {
242 if (width == -1) m_width = 80;
243 }
244
245 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
246 {
247 if (height == -1) m_height = 26;
248 }
249*/
250
e7dda1ff
VS
251 int minWidth = GetMinWidth(),
252 minHeight = GetMinHeight(),
253 maxWidth = GetMaxWidth(),
254 maxHeight = GetMaxHeight();
255
256 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
257 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
258 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
259 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
9f41d601
RR
260
261 if ((m_x != -1) || (m_y != -1))
262 {
263 if ((m_x != old_x) || (m_y != old_y))
264 {
265 /* we set the position here and when showing the dialog
266 for the first time in idle time */
cd6645a2
MR
267 // Where does that happen in idle time? I do not see it anywhere - MR
268 gtk_window_move( GTK_WINDOW(m_widget), m_x, m_y );
9f41d601
RR
269 }
270 }
271
272 if ((m_width != old_width) || (m_height != old_height))
273 {
370dc79c 274 gtk_widget_set_size_request( m_widget, m_width, m_height );
9f41d601
RR
275
276 /* actual resizing is deferred to GtkOnSize in idle time and
277 when showing the dialog */
670f9935 278 m_sizeSet = false;
9f41d601
RR
279
280 }
281
670f9935 282 m_resizing = false;
9f41d601
RR
283}
284
b5e31cc8 285void wxPopupWindow::GtkOnSize()
9f41d601 286{
b5e31cc8 287 if (m_sizeSet) return;
9f41d601
RR
288 if (!m_wxwindow) return;
289
ef00dc09 290 /* FIXME: is this a hack? */
7e027698
RR
291 /* Since for some reason GTK will revert to using maximum size ever set
292 for this window, we have to set geometry hints maxsize to match size
293 given. Also set the to that minsize since resizing isn't possible
294 anyway. */
9f41d601
RR
295
296 /* set size hints */
7e027698 297 gint flag = GDK_HINT_MAX_SIZE | GDK_HINT_MIN_SIZE; // GDK_HINT_POS;
9f41d601 298 GdkGeometry geom;
7e027698
RR
299 geom.min_width = m_width;
300 geom.min_height = m_height;
ef00dc09
RR
301 geom.max_width = m_width;
302 geom.max_height = m_height;
9f41d601
RR
303 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
304 (GtkWidget*) NULL,
305 &geom,
306 (GdkWindowHints) flag );
307
ef00dc09 308
670f9935 309 m_sizeSet = true;
9f41d601
RR
310
311 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
312 event.SetEventObject( this );
313 GetEventHandler()->ProcessEvent( event );
314}
315
316void wxPopupWindow::OnInternalIdle()
317{
318 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
b5e31cc8 319 GtkOnSize();
9f41d601
RR
320
321 wxWindow::OnInternalIdle();
322}
323
324bool wxPopupWindow::Show( bool show )
325{
326 if (show && !m_sizeSet)
327 {
328 /* by calling GtkOnSize here, we don't have to call
329 either after showing the frame, which would entail
330 much ugly flicker nor from within the size_allocate
331 handler, because GTK 1.1.X forbids that. */
332
b5e31cc8 333 GtkOnSize();
9f41d601 334 }
88d19775 335
9f41d601 336 bool ret = wxWindow::Show( show );
88d19775 337
9f41d601
RR
338 return ret;
339}
340
f3ecfad1 341#endif // wxUSE_POPUPWIN