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