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