]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/window.cpp
1f40d20ec17365b4ab6c0b443fa23a55ce6151a9
[wxWidgets.git] / src / gtk1 / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #ifdef __GNUG__
12 #pragma implementation "window.h"
13 #endif
14
15 #include "wx/defs.h"
16 #include "wx/window.h"
17 #include "wx/dc.h"
18 #include "wx/frame.h"
19 #include "wx/app.h"
20 #include "wx/layout.h"
21 #include "wx/utils.h"
22 #include "wx/dialog.h"
23 #include "wx/msgdlg.h"
24
25 #if wxUSE_DRAG_AND_DROP
26 #include "wx/dnd.h"
27 #endif
28
29 #if wxUSE_TOOLTIPS
30 #include "wx/tooltip.h"
31 #endif
32
33 #include "wx/menu.h"
34 #include "wx/statusbr.h"
35 #include "wx/intl.h"
36 #include "wx/settings.h"
37 #include "wx/log.h"
38
39 #include <math.h>
40
41 #include "gdk/gdk.h"
42 #include "gtk/gtk.h"
43 #include "gdk/gdkprivate.h"
44 #include "gdk/gdkkeysyms.h"
45 #include "wx/gtk/win_gtk.h"
46
47 //-----------------------------------------------------------------------------
48 // documentation on internals
49 //-----------------------------------------------------------------------------
50
51 /*
52 I have been asked several times about writing some documentation about
53 the GTK port of wxWindows, especially its internal structures. Obviously,
54 you cannot understand wxGTK without knowing a little about the GTK, but
55 some more information about what the wxWindow, which is the base class
56 for all other window classes, does seems required as well.
57
58 What does wxWindow do? It contains the common interface for the following
59 jobs of its descendants:
60
61 1) Define the rudimentary behaviour common to all window classes, such as
62 resizing, intercepting user input (so as to make it possible to use these
63 events for special purposes in a derived class), window names etc.
64
65 2) Provide the possibility to contain and manage children, if the derived
66 class is allowed to contain children, which holds true for those window
67 classes which do not display a native GTK widget. To name them, these
68 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
69 work classes are a special case and are handled a bit differently from
70 the rest. The same holds true for the wxNotebook class.
71
72 3) Provide the possibility to draw into a client area of a window. This,
73 too, only holds true for classes that do not display a native GTK widget
74 as above.
75
76 4) Provide the entire mechanism for scrolling widgets. This actual inter-
77 face for this is usually in wxScrolledWindow, but the GTK implementation
78 is in this class.
79
80 5) A multitude of helper or extra methods for special purposes, such as
81 Drag'n'Drop, managing validators etc.
82
83 Normally one might expect, that one wxWindows window would always correspond
84 to one GTK widget. Under GTK, there is no such allround widget that has all
85 the functionality. Moreover, the GTK defines a client area as a different
86 widget from the actual widget you are handling. Last but not least some
87 special classes (e.g. wxFrame) handle different categories of widgets and
88 still have the possibility to draw something in the client area.
89 It was therefore required to write a special purpose GTK widget, that would
90 represent a client area in the sense of wxWindows capable to do the jobs
91 2), 3) and 4). I have written this class and it resides in win_gtk.c of
92 this directory.
93
94 All windows must have a widget, with which they interact with other under-
95 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
96 thw wxWindow class has a member variable called m_widget which holds a
97 pointer to this widget. When the window class represents a GTK native widget,
98 this is (in most cases) the only GTK widget the class manages. E.g. the
99 wxStatitText class handles only a GtkLabel widget a pointer to which you
100 can find in m_widget (defined in wxWindow)
101
102 When the class has a client area for drawing into and for containing children
103 it has to handle the client area widget (of the type GtkMyFixed, defined in
104 win_gtk.c), but there could be any number of widgets, handled by a class
105 The common rule for all windows is only, that the widget that interacts with
106 the rest of GTK must be referenced in m_widget and all other widgets must be
107 children of this widget on the GTK level. The top-most widget, which also
108 represents the client area, must be in the m_wxwindow field and must be of
109 the type GtkMyFixed.
110
111 As I said, the window classes that display a GTK native widget only have
112 one widget, so in the case of e.g. the wxButton class m_widget holds a
113 pointer to a GtkButton widget. But windows with client areas (for drawing
114 and children) have a m_widget field that is a pointer to a GtkScrolled-
115 Window and a m_wxwindow field that is pointer to a GtkMyFixed and this
116 one is (in the GTK sense) a child of the GtkScrolledWindow.
117
118 If the m_wxwindow field is set, then all input to this widget is inter-
119 cepted and sent to the wxWindows class. If not, all input to the widget
120 that gets pointed to by m_widget gets intercepted and sent to the class.
121
122 */
123
124 //-----------------------------------------------------------------------------
125 // debug
126 //-----------------------------------------------------------------------------
127
128 #ifdef __WXDEBUG__
129
130 static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
131 GdkEvent *WXUNUSED(event),
132 const wxChar *name )
133 {
134 wxPrintf( _T("FOCUS NOW AT: ") );
135 wxPrintf( name );
136 wxPrintf( _T("\n") );
137
138 return FALSE;
139 }
140
141 void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
142 {
143 wxString tmp = name;
144 tmp += _T(" FROM ");
145 tmp += window;
146
147 wxChar *s = new wxChar[tmp.Length()+1];
148
149 wxStrcpy( s, tmp );
150
151 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
152 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
153 }
154
155 #endif
156
157 //-----------------------------------------------------------------------------
158 // data
159 //-----------------------------------------------------------------------------
160
161 extern wxList wxPendingDelete;
162 extern bool g_blockEventsOnDrag;
163 extern bool g_blockEventsOnScroll;
164 extern bool g_isIdle;
165 static bool g_capturing = FALSE;
166 static wxWindow *g_focusWindow = (wxWindow*) NULL;
167
168 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
169 the last click here */
170 static guint32 gs_timeLastClick = 0;
171
172 //-----------------------------------------------------------------------------
173 // idle system
174 //-----------------------------------------------------------------------------
175
176 extern void wxapp_install_idle_handler();
177 extern bool g_isIdle;
178
179 #if (GTK_MINOR_VERSION > 0)
180
181 //-----------------------------------------------------------------------------
182 // local code (see below)
183 //-----------------------------------------------------------------------------
184
185 static void draw_frame( GtkWidget *widget, wxWindow *win )
186 {
187 if (!win->HasVMT()) return;
188
189 int dw = 0;
190 int dh = 0;
191
192 if (win->m_hasScrolling)
193 {
194 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
195 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(widget)->klass );
196
197 /*
198 GtkWidget *hscrollbar = scroll_window->hscrollbar;
199 GtkWidget *vscrollbar = scroll_window->vscrollbar;
200
201 we use this instead: range.slider_width = 11 + 2*2pts edge
202 */
203
204 if (scroll_window->vscrollbar_visible)
205 {
206 dw += 15; /* dw += vscrollbar->allocation.width; */
207 dw += scroll_class->scrollbar_spacing;
208 }
209
210 if (scroll_window->hscrollbar_visible)
211 {
212 dh += 15; /* dh += hscrollbar->allocation.height; */
213 dw += scroll_class->scrollbar_spacing;
214 }
215 }
216
217 int dx = 0;
218 int dy = 0;
219 if (GTK_WIDGET_NO_WINDOW (widget))
220 {
221 dx += widget->allocation.x;
222 dy += widget->allocation.y;
223 }
224
225 if (win->m_windowStyle & wxRAISED_BORDER)
226 {
227 gtk_draw_shadow( widget->style,
228 widget->window,
229 GTK_STATE_NORMAL,
230 GTK_SHADOW_OUT,
231 dx, dy,
232 win->m_width-dw, win->m_height-dh );
233 return;
234 }
235
236 if (win->m_windowStyle & wxSUNKEN_BORDER)
237 {
238 gtk_draw_shadow( widget->style,
239 widget->window,
240 GTK_STATE_NORMAL,
241 GTK_SHADOW_IN,
242 dx, dy,
243 win->m_width-dw, win->m_height-dh );
244 return;
245 }
246 }
247
248 //-----------------------------------------------------------------------------
249 // "expose_event" of m_widget
250 //-----------------------------------------------------------------------------
251
252 static void gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
253 {
254 if (gdk_event->count > 0) return;
255 draw_frame( widget, win );
256 }
257
258 //-----------------------------------------------------------------------------
259 // "draw" of m_wxwindow
260 //-----------------------------------------------------------------------------
261
262 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindow *win )
263 {
264 draw_frame( widget, win );
265 }
266
267 #endif
268
269 //-----------------------------------------------------------------------------
270 // "expose_event" of m_wxwindow
271 //-----------------------------------------------------------------------------
272
273 static void gtk_window_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxWindow *win )
274 {
275 if (g_isIdle) wxapp_install_idle_handler();
276
277 if (!win->HasVMT()) return;
278
279 win->m_updateRegion.Union( gdk_event->area.x,
280 gdk_event->area.y,
281 gdk_event->area.width,
282 gdk_event->area.height );
283
284 if (gdk_event->count > 0) return;
285
286 /*
287 printf( "OnExpose from " );
288 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
289 printf( win->GetClassInfo()->GetClassName() );
290 printf( ".\n" );
291 */
292
293 wxPaintEvent event( win->GetId() );
294 event.SetEventObject( win );
295 win->GetEventHandler()->ProcessEvent( event );
296
297 win->m_updateRegion.Clear();
298 }
299
300 //-----------------------------------------------------------------------------
301 // "draw" of m_wxwindow
302 //-----------------------------------------------------------------------------
303
304 static void gtk_window_draw_callback( GtkWidget *WXUNUSED(widget), GdkRectangle *rect, wxWindow *win )
305 {
306 if (g_isIdle) wxapp_install_idle_handler();
307
308 if (!win->HasVMT()) return;
309
310 win->m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
311
312 wxPaintEvent event( win->GetId() );
313 event.SetEventObject( win );
314 win->GetEventHandler()->ProcessEvent( event );
315
316 win->m_updateRegion.Clear();
317 }
318
319 //-----------------------------------------------------------------------------
320 // "key_press_event" from any window
321 //-----------------------------------------------------------------------------
322
323 static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
324 {
325 if (g_isIdle) wxapp_install_idle_handler();
326
327 if (!win->HasVMT()) return FALSE;
328 if (g_blockEventsOnDrag) return FALSE;
329
330 /*
331 wxPrintf( _T("OnKeyPress from ") );
332 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
333 wxPrintf( win->GetClassInfo()->GetClassName() );
334 wxPrintf( _T(".\n") );
335 */
336
337 long key_code = 0;
338 switch (gdk_event->keyval)
339 {
340 case GDK_BackSpace: key_code = WXK_BACK; break;
341 case GDK_ISO_Left_Tab:
342 case GDK_KP_Tab:
343 case GDK_Tab: key_code = WXK_TAB; break;
344 case GDK_Linefeed: key_code = WXK_RETURN; break;
345 case GDK_Clear: key_code = WXK_CLEAR; break;
346 case GDK_Return: key_code = WXK_RETURN; break;
347 case GDK_Pause: key_code = WXK_PAUSE; break;
348 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
349 case GDK_Escape: key_code = WXK_ESCAPE; break;
350 case GDK_Delete: key_code = WXK_DELETE; break;
351 case GDK_Home: key_code = WXK_HOME; break;
352 case GDK_Left: key_code = WXK_LEFT; break;
353 case GDK_Up: key_code = WXK_UP; break;
354 case GDK_Right: key_code = WXK_RIGHT; break;
355 case GDK_Down: key_code = WXK_DOWN; break;
356 case GDK_Prior: key_code = WXK_PRIOR; break;
357 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
358 case GDK_Next: key_code = WXK_NEXT; break;
359 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
360 case GDK_End: key_code = WXK_END; break;
361 case GDK_Begin: key_code = WXK_HOME; break;
362 case GDK_Select: key_code = WXK_SELECT; break;
363 case GDK_Print: key_code = WXK_PRINT; break;
364 case GDK_Execute: key_code = WXK_EXECUTE; break;
365 case GDK_Insert: key_code = WXK_INSERT; break;
366 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
367 case GDK_KP_Enter: key_code = WXK_RETURN; break;
368 case GDK_KP_Home: key_code = WXK_HOME; break;
369 case GDK_KP_Left: key_code = WXK_LEFT; break;
370 case GDK_KP_Up: key_code = WXK_UP; break;
371 case GDK_KP_Right: key_code = WXK_RIGHT; break;
372 case GDK_KP_Down: key_code = WXK_DOWN; break;
373 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
374 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
375 case GDK_KP_Next: key_code = WXK_NEXT; break;
376 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
377 case GDK_KP_End: key_code = WXK_END; break;
378 case GDK_KP_Begin: key_code = WXK_HOME; break;
379 case GDK_KP_Insert: key_code = WXK_INSERT; break;
380 case GDK_KP_Delete: key_code = WXK_DELETE; break;
381 case GDK_KP_Multiply: key_code = WXK_MULTIPLY; break;
382 case GDK_KP_Add: key_code = WXK_ADD; break;
383 case GDK_KP_Separator: key_code = WXK_SEPARATOR; break;
384 case GDK_KP_Subtract: key_code = WXK_SUBTRACT; break;
385 case GDK_KP_Decimal: key_code = WXK_DECIMAL; break;
386 case GDK_KP_Divide: key_code = WXK_DIVIDE; break;
387 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
388 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
389 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
390 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
391 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
392 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
393 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
394 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
395 case GDK_KP_8: key_code = WXK_NUMPAD7; break;
396 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
397 case GDK_F1: key_code = WXK_F1; break;
398 case GDK_F2: key_code = WXK_F2; break;
399 case GDK_F3: key_code = WXK_F3; break;
400 case GDK_F4: key_code = WXK_F4; break;
401 case GDK_F5: key_code = WXK_F5; break;
402 case GDK_F6: key_code = WXK_F6; break;
403 case GDK_F7: key_code = WXK_F7; break;
404 case GDK_F8: key_code = WXK_F8; break;
405 case GDK_F9: key_code = WXK_F9; break;
406 case GDK_F10: key_code = WXK_F10; break;
407 case GDK_F11: key_code = WXK_F11; break;
408 case GDK_F12: key_code = WXK_F12; break;
409 default:
410 {
411 if ((gdk_event->keyval >= 0x20) && (gdk_event->keyval <= 0xFF))
412 key_code = gdk_event->keyval;
413 }
414 }
415
416 if (!key_code) return FALSE;
417
418 wxKeyEvent event( wxEVT_KEY_DOWN );
419 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
420 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
421 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
422 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
423 event.m_keyCode = key_code;
424 event.m_x = 0;
425 event.m_y = 0;
426 event.SetEventObject( win );
427
428 bool ret = win->GetEventHandler()->ProcessEvent( event );
429
430 if (!ret)
431 {
432 wxWindow *ancestor = win;
433 while (ancestor)
434 {
435 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
436 if (command != -1)
437 {
438 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
439 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
440 break;
441 }
442 ancestor = ancestor->GetParent();
443 }
444 }
445
446 // win is a control: tab can be propagated up
447 if ( (!ret) &&
448 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
449 ((win->m_windowStyle & wxTE_PROCESS_TAB) == 0))
450 {
451 wxNavigationKeyEvent new_event;
452 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
453 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
454 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
455 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
456 new_event.SetCurrentFocus( win );
457 ret = win->GetEventHandler()->ProcessEvent( new_event );
458 }
459
460 if ( (!ret) &&
461 (gdk_event->keyval == GDK_Escape) )
462 {
463 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
464 new_event.SetEventObject( win );
465 ret = win->GetEventHandler()->ProcessEvent( new_event );
466 }
467
468 /*
469 Damn, I forgot why this didn't work, but it didn't work.
470
471 // win is a panel: up can be propagated to the panel
472 if ((!ret) && (win->m_wxwindow) && (win->m_parent) && (win->m_parent->AcceptsFocus()) &&
473 (gdk_event->keyval == GDK_Up))
474 {
475 win->m_parent->SetFocus();
476 ret = TRUE;
477 }
478
479 // win is a panel: left/right can be propagated to the panel
480 if ((!ret) && (win->m_wxwindow) &&
481 ((gdk_event->keyval == GDK_Right) || (gdk_event->keyval == GDK_Left) ||
482 (gdk_event->keyval == GDK_Up) || (gdk_event->keyval == GDK_Down)))
483 {
484 wxNavigationKeyEvent new_event;
485 new_event.SetDirection( (gdk_event->keyval == GDK_Right) || (gdk_event->keyval == GDK_Down) );
486 new_event.SetCurrentFocus( win );
487 ret = win->GetEventHandler()->ProcessEvent( new_event );
488 }
489 */
490
491 if (ret)
492 {
493 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
494 return TRUE;
495 }
496
497 return FALSE;
498 }
499
500 //-----------------------------------------------------------------------------
501 // "key_release_event" from any window
502 //-----------------------------------------------------------------------------
503
504 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
505 {
506 if (g_isIdle) wxapp_install_idle_handler();
507
508 if (!win->HasVMT()) return FALSE;
509 if (g_blockEventsOnDrag) return FALSE;
510
511 /*
512 printf( "OnKeyRelease from " );
513 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
514 printf( win->GetClassInfo()->GetClassName() );
515 printf( ".\n" );
516 */
517
518 long key_code = 0;
519 switch (gdk_event->keyval)
520 {
521 case GDK_BackSpace: key_code = WXK_BACK; break;
522 case GDK_ISO_Left_Tab:
523 case GDK_KP_Tab:
524 case GDK_Tab: key_code = WXK_TAB; break;
525 case GDK_Linefeed: key_code = WXK_RETURN; break;
526 case GDK_Clear: key_code = WXK_CLEAR; break;
527 case GDK_Return: key_code = WXK_RETURN; break;
528 case GDK_Pause: key_code = WXK_PAUSE; break;
529 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
530 case GDK_Escape: key_code = WXK_ESCAPE; break;
531 case GDK_Delete: key_code = WXK_DELETE; break;
532 case GDK_Home: key_code = WXK_HOME; break;
533 case GDK_Left: key_code = WXK_LEFT; break;
534 case GDK_Up: key_code = WXK_UP; break;
535 case GDK_Right: key_code = WXK_RIGHT; break;
536 case GDK_Down: key_code = WXK_DOWN; break;
537 case GDK_Prior: key_code = WXK_PRIOR; break;
538 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
539 case GDK_Next: key_code = WXK_NEXT; break;
540 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
541 case GDK_End: key_code = WXK_END; break;
542 case GDK_Begin: key_code = WXK_HOME; break;
543 case GDK_Select: key_code = WXK_SELECT; break;
544 case GDK_Print: key_code = WXK_PRINT; break;
545 case GDK_Execute: key_code = WXK_EXECUTE; break;
546 case GDK_Insert: key_code = WXK_INSERT; break;
547 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
548 case GDK_KP_Enter: key_code = WXK_RETURN; break;
549 case GDK_KP_Home: key_code = WXK_HOME; break;
550 case GDK_KP_Left: key_code = WXK_LEFT; break;
551 case GDK_KP_Up: key_code = WXK_UP; break;
552 case GDK_KP_Right: key_code = WXK_RIGHT; break;
553 case GDK_KP_Down: key_code = WXK_DOWN; break;
554 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
555 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
556 case GDK_KP_Next: key_code = WXK_NEXT; break;
557 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
558 case GDK_KP_End: key_code = WXK_END; break;
559 case GDK_KP_Begin: key_code = WXK_HOME; break;
560 case GDK_KP_Insert: key_code = WXK_INSERT; break;
561 case GDK_KP_Delete: key_code = WXK_DELETE; break;
562 case GDK_KP_Multiply: key_code = WXK_MULTIPLY; break;
563 case GDK_KP_Add: key_code = WXK_ADD; break;
564 case GDK_KP_Separator: key_code = WXK_SEPARATOR; break;
565 case GDK_KP_Subtract: key_code = WXK_SUBTRACT; break;
566 case GDK_KP_Decimal: key_code = WXK_DECIMAL; break;
567 case GDK_KP_Divide: key_code = WXK_DIVIDE; break;
568 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
569 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
570 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
571 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
572 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
573 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
574 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
575 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
576 case GDK_KP_8: key_code = WXK_NUMPAD7; break;
577 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
578 case GDK_F1: key_code = WXK_F1; break;
579 case GDK_F2: key_code = WXK_F2; break;
580 case GDK_F3: key_code = WXK_F3; break;
581 case GDK_F4: key_code = WXK_F4; break;
582 case GDK_F5: key_code = WXK_F5; break;
583 case GDK_F6: key_code = WXK_F6; break;
584 case GDK_F7: key_code = WXK_F7; break;
585 case GDK_F8: key_code = WXK_F8; break;
586 case GDK_F9: key_code = WXK_F9; break;
587 case GDK_F10: key_code = WXK_F10; break;
588 case GDK_F11: key_code = WXK_F11; break;
589 case GDK_F12: key_code = WXK_F12; break;
590 default:
591 {
592 if ((gdk_event->keyval >= 0x20) && (gdk_event->keyval <= 0xFF))
593 key_code = gdk_event->keyval;
594 }
595 }
596
597 if (!key_code) return FALSE;
598
599 wxKeyEvent event( wxEVT_KEY_UP );
600 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
601 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
602 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
603 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
604 event.m_keyCode = key_code;
605 event.m_x = 0;
606 event.m_y = 0;
607 event.SetEventObject( win );
608
609 if (win->GetEventHandler()->ProcessEvent( event ))
610 {
611 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
612 return TRUE;
613 }
614
615 return FALSE;
616 }
617
618 //-----------------------------------------------------------------------------
619 // "button_press_event"
620 //-----------------------------------------------------------------------------
621
622 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
623 {
624 if (g_isIdle) wxapp_install_idle_handler();
625
626 /*
627 wxPrintf( _T("1) OnButtonPress from ") );
628 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
629 wxPrintf( win->GetClassInfo()->GetClassName() );
630 wxPrintf( _T(".\n") );
631 */
632
633 if (!win->HasVMT()) return FALSE;
634 if (g_blockEventsOnDrag) return TRUE;
635 if (g_blockEventsOnScroll) return TRUE;
636
637 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
638
639 if (win->m_wxwindow)
640 {
641 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
642 {
643 gtk_widget_grab_focus (win->m_wxwindow);
644
645 /*
646 wxPrintf( _T("GrabFocus from ") );
647 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
648 wxPrintf( win->GetClassInfo()->GetClassName() );
649 wxPrintf( _T(".\n") );
650 */
651
652 }
653 /*
654 else
655 {
656 wxPrintf( _T("No GrabFocus from ") );
657 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
658 wxPrintf( win->GetClassInfo()->GetClassName() );
659 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
660 wxPrintf( _T(" because it already has") );
661 wxPrintf( _T(".\n") );
662 }
663 */
664 }
665
666 /*
667 wxPrintf( _T("2) OnButtonPress from ") );
668 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
669 wxPrintf( win->GetClassInfo()->GetClassName() );
670 wxPrintf( _T(".\n") );
671 */
672
673 wxEventType event_type = wxEVT_LEFT_DOWN;
674
675 if (gdk_event->button == 1)
676 {
677 switch (gdk_event->type)
678 {
679 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
680 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
681 default: break;
682 }
683 }
684 else if (gdk_event->button == 2)
685 {
686 switch (gdk_event->type)
687 {
688 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
689 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
690 default: break;
691 }
692 }
693 else if (gdk_event->button == 3)
694 {
695 switch (gdk_event->type)
696 {
697 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
698 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
699 default: break;
700 }
701 }
702
703 wxMouseEvent event( event_type );
704 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
705 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
706 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
707 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
708 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
709 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
710 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
711
712 event.m_x = (long)gdk_event->x;
713 event.m_y = (long)gdk_event->y;
714
715 // Some control don't have their own X window and thus cannot get
716 // any events.
717
718 if (!g_capturing)
719 {
720 wxNode *node = win->GetChildren().First();
721 while (node)
722 {
723 wxWindow *child = (wxWindow*)node->Data();
724
725 if (child->m_isStaticBox)
726 {
727 // wxStaticBox is transparent in the box itself
728 int x = event.m_x;
729 int y = event.m_y;
730 int xx1 = child->m_x;
731 int yy1 = child->m_y;
732 int xx2 = child->m_x + child->m_width;
733 int yy2 = child->m_x + child->m_height;
734
735 // left
736 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
737 // right
738 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
739 // top
740 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
741 // bottom
742 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
743 {
744 win = child;
745 event.m_x -= child->m_x;
746 event.m_y -= child->m_y;
747 break;
748 }
749
750 }
751 else
752 {
753 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
754 (child->m_x <= event.m_x) &&
755 (child->m_y <= event.m_y) &&
756 (child->m_x+child->m_width >= event.m_x) &&
757 (child->m_y+child->m_height >= event.m_y))
758 {
759 win = child;
760 event.m_x -= child->m_x;
761 event.m_y -= child->m_y;
762 break;
763 }
764 }
765 node = node->Next();
766 }
767 }
768
769 event.SetEventObject( win );
770
771 gs_timeLastClick = gdk_event->time;
772
773 if (win->GetEventHandler()->ProcessEvent( event ))
774 {
775 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
776 return TRUE;
777 }
778
779 return FALSE;
780 }
781
782 //-----------------------------------------------------------------------------
783 // "button_release_event"
784 //-----------------------------------------------------------------------------
785
786 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
787 {
788 if (g_isIdle) wxapp_install_idle_handler();
789
790 if (!win->HasVMT()) return FALSE;
791 if (g_blockEventsOnDrag) return FALSE;
792 if (g_blockEventsOnScroll) return FALSE;
793
794 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
795
796 /*
797 printf( "OnButtonRelease from " );
798 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
799 printf( win->GetClassInfo()->GetClassName() );
800 printf( ".\n" );
801 */
802
803 wxEventType event_type = wxEVT_NULL;
804
805 switch (gdk_event->button)
806 {
807 case 1: event_type = wxEVT_LEFT_UP; break;
808 case 2: event_type = wxEVT_MIDDLE_UP; break;
809 case 3: event_type = wxEVT_RIGHT_UP; break;
810 }
811
812 wxMouseEvent event( event_type );
813 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
814 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
815 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
816 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
817 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
818 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
819 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
820 event.m_x = (long)gdk_event->x;
821 event.m_y = (long)gdk_event->y;
822
823 // Some control don't have their own X window and thus cannot get
824 // any events.
825
826 if (!g_capturing)
827 {
828 wxNode *node = win->GetChildren().First();
829 while (node)
830 {
831 wxWindow *child = (wxWindow*)node->Data();
832
833 if (child->m_isStaticBox)
834 {
835 // wxStaticBox is transparent in the box itself
836 int x = event.m_x;
837 int y = event.m_y;
838 int xx1 = child->m_x;
839 int yy1 = child->m_y;
840 int xx2 = child->m_x + child->m_width;
841 int yy2 = child->m_x + child->m_height;
842
843 // left
844 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
845 // right
846 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
847 // top
848 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
849 // bottom
850 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
851 {
852 win = child;
853 event.m_x -= child->m_x;
854 event.m_y -= child->m_y;
855 break;
856 }
857
858 }
859 else
860 {
861 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
862 (child->m_x <= event.m_x) &&
863 (child->m_y <= event.m_y) &&
864 (child->m_x+child->m_width >= event.m_x) &&
865 (child->m_y+child->m_height >= event.m_y))
866 {
867 win = child;
868 event.m_x -= child->m_x;
869 event.m_y -= child->m_y;
870 break;
871 }
872 }
873 node = node->Next();
874 }
875 }
876
877 event.SetEventObject( win );
878
879 if (win->GetEventHandler()->ProcessEvent( event ))
880 {
881 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
882 return TRUE;
883 }
884
885 return FALSE;
886 }
887
888 //-----------------------------------------------------------------------------
889 // "motion_notify_event"
890 //-----------------------------------------------------------------------------
891
892 static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
893 {
894 if (g_isIdle) wxapp_install_idle_handler();
895
896 if (!win->HasVMT()) return FALSE;
897 if (g_blockEventsOnDrag) return FALSE;
898 if (g_blockEventsOnScroll) return FALSE;
899
900 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
901
902 if (gdk_event->is_hint)
903 {
904 int x = 0;
905 int y = 0;
906 GdkModifierType state;
907 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
908 gdk_event->x = x;
909 gdk_event->y = y;
910 gdk_event->state = state;
911 }
912
913 /*
914 printf( "OnMotion from " );
915 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
916 printf( win->GetClassInfo()->GetClassName() );
917 printf( ".\n" );
918 */
919
920 wxMouseEvent event( wxEVT_MOTION );
921 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
922 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
923 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
924 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
925 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
926 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
927 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
928
929 event.m_x = (long)gdk_event->x;
930 event.m_y = (long)gdk_event->y;
931
932 // Some control don't have their own X window and thus cannot get
933 // any events.
934
935 if (!g_capturing)
936 {
937 wxNode *node = win->GetChildren().First();
938 while (node)
939 {
940 wxWindow *child = (wxWindow*)node->Data();
941
942 if (child->m_isStaticBox)
943 {
944 // wxStaticBox is transparent in the box itself
945 int x = event.m_x;
946 int y = event.m_y;
947 int xx1 = child->m_x;
948 int yy1 = child->m_y;
949 int xx2 = child->m_x + child->m_width;
950 int yy2 = child->m_x + child->m_height;
951
952 // left
953 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
954 // right
955 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
956 // top
957 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
958 // bottom
959 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
960 {
961 win = child;
962 event.m_x -= child->m_x;
963 event.m_y -= child->m_y;
964 break;
965 }
966
967 }
968 else
969 {
970 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
971 (child->m_x <= event.m_x) &&
972 (child->m_y <= event.m_y) &&
973 (child->m_x+child->m_width >= event.m_x) &&
974 (child->m_y+child->m_height >= event.m_y))
975 {
976 win = child;
977 event.m_x -= child->m_x;
978 event.m_y -= child->m_y;
979 break;
980 }
981 }
982 node = node->Next();
983 }
984 }
985
986 event.SetEventObject( win );
987
988 if (win->GetEventHandler()->ProcessEvent( event ))
989 {
990 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
991 return TRUE;
992 }
993
994 return FALSE;
995 }
996
997 //-----------------------------------------------------------------------------
998 // "focus_in_event"
999 //-----------------------------------------------------------------------------
1000
1001 static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1002 {
1003 if (g_isIdle) wxapp_install_idle_handler();
1004
1005 if (!win->HasVMT()) return FALSE;
1006 if (g_blockEventsOnDrag) return FALSE;
1007
1008 g_focusWindow = win;
1009
1010 if (win->m_wxwindow)
1011 {
1012 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
1013 {
1014 GTK_WIDGET_SET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
1015 /*
1016 printf( "SetFocus flag from " );
1017 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1018 printf( win->GetClassInfo()->GetClassName() );
1019 printf( ".\n" );
1020 */
1021 }
1022 }
1023
1024
1025 /*
1026 wxPrintf( _T("OnSetFocus from ") );
1027 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1028 wxPrintf( win->GetClassInfo()->GetClassName() );
1029 wxPrintf( _T(" ") );
1030 wxPrintf( win->GetLabel() );
1031 wxPrintf( _T(".\n") );
1032 */
1033
1034 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1035 event.SetEventObject( win );
1036
1037 if (win->GetEventHandler()->ProcessEvent( event ))
1038 {
1039 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1040 return TRUE;
1041 }
1042
1043 return FALSE;
1044 }
1045
1046 //-----------------------------------------------------------------------------
1047 // "focus_out_event"
1048 //-----------------------------------------------------------------------------
1049
1050 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1051 {
1052 if (g_isIdle) wxapp_install_idle_handler();
1053
1054 if (!win->HasVMT()) return FALSE;
1055 if (g_blockEventsOnDrag) return FALSE;
1056
1057 if (win->m_wxwindow)
1058 {
1059 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
1060 GTK_WIDGET_UNSET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
1061 }
1062
1063 /*
1064 wxPrintf( _T("OnKillFocus from ") );
1065 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1066 wxPrintf( win->GetClassInfo()->GetClassName() );
1067 wxPrintf( _T(" ") );
1068 wxPrintf( win->GetLabel() );
1069 wxPrintf( _T(".\n") );
1070 */
1071
1072 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1073 event.SetEventObject( win );
1074
1075 if (win->GetEventHandler()->ProcessEvent( event ))
1076 {
1077 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1078 return TRUE;
1079 }
1080
1081 return FALSE;
1082 }
1083
1084 //-----------------------------------------------------------------------------
1085 // "enter_notify_event"
1086 //-----------------------------------------------------------------------------
1087
1088 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1089 {
1090 if (g_isIdle) wxapp_install_idle_handler();
1091
1092 if (!win->HasVMT()) return FALSE;
1093 if (g_blockEventsOnDrag) return FALSE;
1094
1095 if (widget->window != gdk_event->window) return FALSE;
1096
1097 if ((widget->window) && (win->m_cursor.Ok()))
1098 gdk_window_set_cursor( widget->window, win->m_cursor.GetCursor() );
1099
1100 /*
1101 printf( "OnEnter from " );
1102 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1103 printf( win->GetClassInfo()->GetClassName() );
1104 printf( ".\n" );
1105 */
1106
1107 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1108 event.SetEventObject( win );
1109
1110 int x = 0;
1111 int y = 0;
1112 GdkModifierType state = (GdkModifierType)0;
1113
1114 gdk_window_get_pointer( widget->window, &x, &y, &state );
1115
1116 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1117 event.m_controlDown = (state & GDK_CONTROL_MASK);
1118 event.m_altDown = (state & GDK_MOD1_MASK);
1119 event.m_metaDown = (state & GDK_MOD2_MASK);
1120 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1121 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1122 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1123
1124 event.m_x = (long)x;
1125 event.m_y = (long)y;
1126
1127 if (win->GetEventHandler()->ProcessEvent( event ))
1128 {
1129 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1130 return TRUE;
1131 }
1132
1133 return FALSE;
1134 }
1135
1136 //-----------------------------------------------------------------------------
1137 // "leave_notify_event"
1138 //-----------------------------------------------------------------------------
1139
1140 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1141 {
1142 if (g_isIdle) wxapp_install_idle_handler();
1143
1144 if (!win->HasVMT()) return FALSE;
1145 if (g_blockEventsOnDrag) return FALSE;
1146
1147 if (widget->window != gdk_event->window) return FALSE;
1148
1149 if (widget->window)
1150 gdk_window_set_cursor( widget->window, wxSTANDARD_CURSOR->GetCursor() );
1151
1152 /*
1153 printf( "OnLeave from " );
1154 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1155 printf( win->GetClassInfo()->GetClassName() );
1156 printf( ".\n" );
1157 */
1158
1159 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1160 event.SetEventObject( win );
1161
1162 int x = 0;
1163 int y = 0;
1164 GdkModifierType state = (GdkModifierType)0;
1165
1166 gdk_window_get_pointer( widget->window, &x, &y, &state );
1167
1168 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1169 event.m_controlDown = (state & GDK_CONTROL_MASK);
1170 event.m_altDown = (state & GDK_MOD1_MASK);
1171 event.m_metaDown = (state & GDK_MOD2_MASK);
1172 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1173 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1174 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1175
1176 event.m_x = (long)x;
1177 event.m_y = (long)y;
1178
1179 if (win->GetEventHandler()->ProcessEvent( event ))
1180 {
1181 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1182 return TRUE;
1183 }
1184
1185 return FALSE;
1186 }
1187
1188 //-----------------------------------------------------------------------------
1189 // "value_changed" from m_vAdjust
1190 //-----------------------------------------------------------------------------
1191
1192 static void gtk_window_vscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1193 {
1194 if (g_isIdle) wxapp_install_idle_handler();
1195
1196 if (g_blockEventsOnDrag) return;
1197
1198 /*
1199 printf( "OnVScroll from " );
1200 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1201 printf( win->GetClassInfo()->GetClassName() );
1202 printf( ".\n" );
1203 */
1204
1205 if (!win->HasVMT()) return;
1206
1207 float diff = win->m_vAdjust->value - win->m_oldVerticalPos;
1208 if (fabs(diff) < 0.2) return;
1209 win->m_oldVerticalPos = win->m_vAdjust->value;
1210
1211 wxEventType command = wxEVT_NULL;
1212
1213 float line_step = win->m_vAdjust->step_increment;
1214 float page_step = win->m_vAdjust->page_increment;
1215
1216 if (win->m_isScrolling)
1217 {
1218 command = wxEVT_SCROLL_THUMBTRACK;
1219 }
1220 else
1221 {
1222 if (fabs(win->m_vAdjust->value-win->m_vAdjust->lower) < 0.2) command = wxEVT_SCROLL_BOTTOM;
1223 else if (fabs(win->m_vAdjust->value-win->m_vAdjust->upper) < 0.2) command = wxEVT_SCROLL_TOP;
1224 else if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLL_LINEDOWN;
1225 else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLL_LINEUP;
1226 else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLL_PAGEDOWN;
1227 else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLL_PAGEUP;
1228 else command = wxEVT_SCROLL_THUMBTRACK;
1229 }
1230
1231 int value = (int)(win->m_vAdjust->value+0.5);
1232
1233 wxScrollEvent event( command, win->GetId(), value, wxVERTICAL );
1234 event.SetEventObject( win );
1235 win->GetEventHandler()->ProcessEvent( event );
1236 }
1237
1238 //-----------------------------------------------------------------------------
1239 // "value_changed" from m_hAdjust
1240 //-----------------------------------------------------------------------------
1241
1242 static void gtk_window_hscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1243 {
1244 if (g_isIdle) wxapp_install_idle_handler();
1245
1246 if (g_blockEventsOnDrag) return;
1247
1248 /*
1249 printf( "OnHScroll from " );
1250 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1251 printf( win->GetClassInfo()->GetClassName() );
1252 printf( ".\n" );
1253 */
1254
1255 if (!win->HasVMT()) return;
1256
1257 float diff = win->m_hAdjust->value - win->m_oldHorizontalPos;
1258 if (fabs(diff) < 0.2) return;
1259 win->m_oldHorizontalPos = win->m_hAdjust->value;
1260
1261 wxEventType command = wxEVT_NULL;
1262
1263 float line_step = win->m_hAdjust->step_increment;
1264 float page_step = win->m_hAdjust->page_increment;
1265
1266 if (win->m_isScrolling)
1267 {
1268 command = wxEVT_SCROLL_THUMBTRACK;
1269 }
1270 else
1271 {
1272 if (fabs(win->m_hAdjust->value-win->m_hAdjust->lower) < 0.2) command = wxEVT_SCROLL_BOTTOM;
1273 else if (fabs(win->m_hAdjust->value-win->m_hAdjust->upper) < 0.2) command = wxEVT_SCROLL_TOP;
1274 else if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLL_LINEDOWN;
1275 else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLL_LINEUP;
1276 else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLL_PAGEDOWN;
1277 else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLL_PAGEUP;
1278 else command = wxEVT_SCROLL_THUMBTRACK;
1279 }
1280
1281 int value = (int)(win->m_hAdjust->value+0.5);
1282
1283 wxScrollEvent event( command, win->GetId(), value, wxHORIZONTAL );
1284 event.SetEventObject( win );
1285 win->GetEventHandler()->ProcessEvent( event );
1286 }
1287
1288 //-----------------------------------------------------------------------------
1289 // "changed" from m_vAdjust
1290 //-----------------------------------------------------------------------------
1291
1292 static void gtk_window_vscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1293 {
1294 if (g_isIdle) wxapp_install_idle_handler();
1295
1296 if (g_blockEventsOnDrag) return;
1297
1298 /*
1299 printf( "OnVScroll change from " );
1300 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1301 printf( win->GetClassInfo()->GetClassName() );
1302 printf( ".\n" );
1303 */
1304
1305 if (!win->HasVMT()) return;
1306
1307 wxEventType command = wxEVT_SCROLL_THUMBTRACK;
1308 int value = (int)(win->m_vAdjust->value+0.5);
1309
1310 wxScrollEvent event( command, win->GetId(), value, wxVERTICAL );
1311 event.SetEventObject( win );
1312 win->GetEventHandler()->ProcessEvent( event );
1313 }
1314
1315 //-----------------------------------------------------------------------------
1316 // "changed" from m_hAdjust
1317 //-----------------------------------------------------------------------------
1318
1319 static void gtk_window_hscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1320 {
1321 if (g_isIdle) wxapp_install_idle_handler();
1322
1323 if (g_blockEventsOnDrag) return;
1324
1325 /*
1326 printf( "OnHScroll change from " );
1327 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1328 printf( win->GetClassInfo()->GetClassName() );
1329 printf( ".\n" );
1330 */
1331
1332 if (!win->HasVMT()) return;
1333
1334 wxEventType command = wxEVT_SCROLL_THUMBTRACK;
1335 int value = (int)(win->m_hAdjust->value+0.5);
1336
1337 wxScrollEvent event( command, win->GetId(), value, wxHORIZONTAL );
1338 event.SetEventObject( win );
1339 win->GetEventHandler()->ProcessEvent( event );
1340 }
1341
1342 //-----------------------------------------------------------------------------
1343 // "button_press_event" from scrollbar
1344 //-----------------------------------------------------------------------------
1345
1346 static gint gtk_scrollbar_button_press_callback( GtkRange *WXUNUSED(widget),
1347 GdkEventButton *WXUNUSED(gdk_event),
1348 wxWindow *win )
1349 {
1350 if (g_isIdle) wxapp_install_idle_handler();
1351
1352 // don't test here as we can release the mouse while being over
1353 // a different window then the slider
1354 //
1355 // if (gdk_event->window != widget->slider) return FALSE;
1356
1357 win->m_isScrolling = TRUE;
1358 g_blockEventsOnScroll = TRUE;
1359
1360 return FALSE;
1361 }
1362
1363 //-----------------------------------------------------------------------------
1364 // "button_release_event" from scrollbar
1365 //-----------------------------------------------------------------------------
1366
1367 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
1368 GdkEventButton *WXUNUSED(gdk_event),
1369 wxWindow *win )
1370 {
1371 if (g_isIdle) wxapp_install_idle_handler();
1372
1373 // don't test here as we can release the mouse while being over
1374 // a different window then the slider
1375 //
1376 // if (gdk_event->window != widget->slider) return FALSE;
1377
1378 GtkScrolledWindow *s_window = GTK_SCROLLED_WINDOW(win->m_widget);
1379
1380 if (widget == GTK_RANGE(s_window->vscrollbar))
1381 gtk_signal_emit_by_name( GTK_OBJECT(win->m_hAdjust), "value_changed" );
1382 else
1383 gtk_signal_emit_by_name( GTK_OBJECT(win->m_vAdjust), "value_changed" );
1384
1385 win->m_isScrolling = FALSE;
1386 g_blockEventsOnScroll = FALSE;
1387
1388 return FALSE;
1389 }
1390
1391 //-----------------------------------------------------------------------------
1392 // "realize" from m_widget
1393 //-----------------------------------------------------------------------------
1394
1395 /* we cannot set colours, fonts and cursors before the widget has
1396 been realized, so we do this directly after realization */
1397
1398 static gint
1399 gtk_window_realized_callback( GtkWidget *widget, wxWindow *win )
1400 {
1401 if (g_isIdle) wxapp_install_idle_handler();
1402
1403 if (win->m_font != *wxSWISS_FONT)
1404 {
1405 wxFont font( win->m_font );
1406 win->m_font = wxNullFont;
1407 win->SetFont( font );
1408 }
1409
1410 if (win->m_backgroundColour != wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ))
1411 {
1412 wxColour bg( win->m_backgroundColour );
1413 win->m_backgroundColour = wxNullColour;
1414 win->SetBackgroundColour( bg );
1415 }
1416
1417 if (win->m_foregroundColour != *wxBLACK)
1418 {
1419 wxColour fg( win->m_foregroundColour );
1420 win->m_foregroundColour = wxNullColour;
1421 win->SetForegroundColour( fg );
1422 }
1423
1424 wxCursor cursor( win->m_cursor );
1425 win->m_cursor = wxNullCursor;
1426 win->SetCursor( cursor );
1427
1428 return FALSE;
1429 }
1430
1431 //-----------------------------------------------------------------------------
1432 // InsertChild for wxWindow.
1433 //-----------------------------------------------------------------------------
1434
1435 /* Callback for wxWindow. This very strange beast has to be used because
1436 * C++ has no virtual methods in a constructor. We have to emulate a
1437 * virtual function here as wxNotebook requires a different way to insert
1438 * a child in it. I had opted for creating a wxNotebookPage window class
1439 * which would have made this superfluous (such in the MDI window system),
1440 * but no-one was listening to me... */
1441
1442 static void wxInsertChildInWindow( wxWindow* parent, wxWindow* child )
1443 {
1444 gtk_myfixed_put( GTK_MYFIXED(parent->m_wxwindow),
1445 GTK_WIDGET(child->m_widget),
1446 child->m_x,
1447 child->m_y,
1448 child->m_width,
1449 child->m_height );
1450
1451 if (parent->m_windowStyle & wxTAB_TRAVERSAL)
1452 {
1453 /* we now allow a window to get the focus as long as it
1454 doesn't have any children. */
1455 GTK_WIDGET_UNSET_FLAGS( parent->m_wxwindow, GTK_CAN_FOCUS );
1456 }
1457 }
1458
1459 //-----------------------------------------------------------------------------
1460 // global functions
1461 //-----------------------------------------------------------------------------
1462
1463 wxWindow* wxGetActiveWindow()
1464 {
1465 return g_focusWindow;
1466 }
1467
1468 //-----------------------------------------------------------------------------
1469 // wxWindow
1470 //-----------------------------------------------------------------------------
1471
1472 IMPLEMENT_DYNAMIC_CLASS(wxWindow,wxEvtHandler)
1473
1474 BEGIN_EVENT_TABLE(wxWindow, wxEvtHandler)
1475 EVT_SIZE(wxWindow::OnSize)
1476 EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged)
1477 EVT_INIT_DIALOG(wxWindow::OnInitDialog)
1478 EVT_KEY_DOWN(wxWindow::OnKeyDown)
1479 END_EVENT_TABLE()
1480
1481 void wxWindow::Init()
1482 {
1483 m_isWindow = TRUE;
1484
1485 m_widget = (GtkWidget *) NULL;
1486 m_wxwindow = (GtkWidget *) NULL;
1487 m_parent = (wxWindow *) NULL;
1488 m_children.DeleteContents( FALSE );
1489
1490 m_x = 0;
1491 m_y = 0;
1492 m_width = 0;
1493 m_height = 0;
1494 m_minWidth = -1;
1495 m_minHeight = -1;
1496 m_maxWidth = -1;
1497 m_maxHeight = -1;
1498
1499 m_retCode = 0;
1500
1501 m_eventHandler = this;
1502 m_windowValidator = (wxValidator *) NULL;
1503
1504 m_windowId = -1;
1505
1506 m_cursor = *wxSTANDARD_CURSOR;
1507 m_font = *wxSWISS_FONT;
1508 m_windowStyle = 0;
1509 m_windowName = "noname";
1510
1511 m_constraints = (wxLayoutConstraints *) NULL;
1512 m_constraintsInvolvedIn = (wxList *) NULL;
1513 m_windowSizer = (wxSizer *) NULL;
1514 m_sizerParent = (wxWindow *) NULL;
1515 m_autoLayout = FALSE;
1516
1517 m_sizeSet = FALSE;
1518 m_hasVMT = FALSE;
1519 m_needParent = TRUE;
1520
1521 m_hasScrolling = FALSE;
1522 m_isScrolling = FALSE;
1523 m_hAdjust = (GtkAdjustment*) NULL;
1524 m_vAdjust = (GtkAdjustment*) NULL;
1525 m_oldHorizontalPos = 0.0;
1526 m_oldVerticalPos = 0.0;
1527
1528 m_isShown = FALSE;
1529 m_isEnabled = TRUE;
1530
1531 #if wxUSE_DRAG_AND_DROP
1532 m_dropTarget = (wxDropTarget*) NULL;
1533 #endif
1534 m_resizing = FALSE;
1535 m_scrollGC = (GdkGC*) NULL;
1536 m_widgetStyle = (GtkStyle*) NULL;
1537
1538 m_insertCallback = wxInsertChildInWindow;
1539
1540 m_clientObject = (wxClientData*) NULL;
1541 m_clientData = NULL;
1542
1543 m_isStaticBox = FALSE;
1544 m_acceptsFocus = FALSE;
1545
1546 #if wxUSE_TOOLTIPS
1547 m_toolTip = (wxToolTip*) NULL;
1548 #endif // wxUSE_TOOLTIPS
1549 }
1550
1551 wxWindow::wxWindow()
1552 {
1553 Init();
1554 }
1555
1556 wxWindow::wxWindow( wxWindow *parent, wxWindowID id,
1557 const wxPoint &pos, const wxSize &size,
1558 long style, const wxString &name )
1559 {
1560 Init();
1561
1562 Create( parent, id, pos, size, style, name );
1563 }
1564
1565 bool wxWindow::Create( wxWindow *parent, wxWindowID id,
1566 const wxPoint &pos, const wxSize &size,
1567 long style, const wxString &name )
1568 {
1569 wxASSERT_MSG( m_isWindow, _T("Init() must have been called before!") );
1570
1571 PreCreation( parent, id, pos, size, style, name );
1572
1573 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
1574 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
1575
1576 #ifdef __WXDEBUG__
1577 debug_focus_in( m_widget, _T("wxWindow::m_widget"), name );
1578 #endif
1579
1580 GtkScrolledWindow *s_window = GTK_SCROLLED_WINDOW(m_widget);
1581
1582 #ifdef __WXDEBUG__
1583 debug_focus_in( s_window->hscrollbar, _T("wxWindow::hsrcollbar"), name );
1584 debug_focus_in( s_window->vscrollbar, _T("wxWindow::vsrcollbar"), name );
1585 #endif
1586
1587 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
1588 scroll_class->scrollbar_spacing = 0;
1589
1590 gtk_scrolled_window_set_policy( s_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1591
1592 m_oldHorizontalPos = 0.0;
1593 m_oldVerticalPos = 0.0;
1594
1595 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(s_window->hscrollbar) );
1596 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(s_window->vscrollbar) );
1597
1598 m_wxwindow = gtk_myfixed_new();
1599
1600 #ifdef __WXDEBUG__
1601 debug_focus_in( m_wxwindow, _T("wxWindow::m_wxwindow"), name );
1602 #endif
1603
1604 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
1605
1606 #if (GTK_MINOR_VERSION > 0)
1607 GtkMyFixed *myfixed = GTK_MYFIXED(m_wxwindow);
1608
1609 if (m_windowStyle & wxRAISED_BORDER)
1610 {
1611 gtk_myfixed_set_shadow_type( myfixed, GTK_SHADOW_OUT );
1612 }
1613 else if (m_windowStyle & wxSUNKEN_BORDER)
1614 {
1615 gtk_myfixed_set_shadow_type( myfixed, GTK_SHADOW_IN );
1616 }
1617 else
1618 {
1619 gtk_myfixed_set_shadow_type( myfixed, GTK_SHADOW_NONE );
1620 }
1621 #else
1622 GtkViewport *viewport = GTK_VIEWPORT(s_window->viewport);
1623
1624 if (m_windowStyle & wxRAISED_BORDER)
1625 {
1626 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
1627 }
1628 else if (m_windowStyle & wxSUNKEN_BORDER)
1629 {
1630 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
1631 }
1632 else
1633 {
1634 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
1635 }
1636 #endif
1637
1638 /* we always allow a window to get the focus as long as it
1639 doesn't have any children. */
1640 if (m_windowStyle & wxTAB_TRAVERSAL)
1641 {
1642 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
1643 m_acceptsFocus = FALSE;
1644 }
1645 else
1646 {
1647 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
1648 m_acceptsFocus = TRUE;
1649 }
1650
1651 /* grab the actual focus */
1652 // gtk_widget_grab_focus( m_wxwindow );
1653
1654 gtk_widget_show( m_wxwindow );
1655
1656
1657 #if (GTK_MINOR_VERSION == 0)
1658 // shut the viewport up
1659 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
1660 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
1661 #endif
1662
1663 // I _really_ don't want scrollbars in the beginning
1664 m_vAdjust->lower = 0.0;
1665 m_vAdjust->upper = 1.0;
1666 m_vAdjust->value = 0.0;
1667 m_vAdjust->step_increment = 1.0;
1668 m_vAdjust->page_increment = 1.0;
1669 m_vAdjust->page_size = 5.0;
1670 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
1671 m_hAdjust->lower = 0.0;
1672 m_hAdjust->upper = 1.0;
1673 m_hAdjust->value = 0.0;
1674 m_hAdjust->step_increment = 1.0;
1675 m_hAdjust->page_increment = 1.0;
1676 m_hAdjust->page_size = 5.0;
1677 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
1678
1679 // these handlers block mouse events to any window during scrolling
1680 // such as motion events and prevent GTK and wxWindows from fighting
1681 // over where the slider should be
1682
1683 gtk_signal_connect( GTK_OBJECT(s_window->vscrollbar), "button_press_event",
1684 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
1685
1686 gtk_signal_connect( GTK_OBJECT(s_window->hscrollbar), "button_press_event",
1687 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
1688
1689 gtk_signal_connect( GTK_OBJECT(s_window->vscrollbar), "button_release_event",
1690 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
1691
1692 gtk_signal_connect( GTK_OBJECT(s_window->hscrollbar), "button_release_event",
1693 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
1694
1695 // these handlers get notified when screen updates are required either when
1696 // scrolling or when the window size (and therefore scrollbar configuration)
1697 // has changed
1698
1699 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
1700 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
1701 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
1702 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
1703
1704 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "changed",
1705 (GtkSignalFunc) gtk_window_hscroll_change_callback, (gpointer) this );
1706 gtk_signal_connect(GTK_OBJECT(m_vAdjust), "changed",
1707 (GtkSignalFunc) gtk_window_vscroll_change_callback, (gpointer) this );
1708
1709 if (m_parent) m_parent->AddChild( this );
1710
1711 (m_parent->m_insertCallback)( m_parent, this );
1712
1713 PostCreation();
1714
1715 Show( TRUE );
1716
1717 return TRUE;
1718 }
1719
1720 wxWindow::~wxWindow()
1721 {
1722 m_hasVMT = FALSE;
1723
1724 #if wxUSE_DRAG_AND_DROP
1725 if (m_dropTarget)
1726 {
1727 delete m_dropTarget;
1728 m_dropTarget = (wxDropTarget*) NULL;
1729 }
1730 #endif
1731
1732 #if wxUSE_TOOLTIPS
1733 if (m_toolTip)
1734 {
1735 delete m_toolTip;
1736 m_toolTip = (wxToolTip*) NULL;
1737 }
1738 #endif // wxUSE_TOOLTIPS
1739
1740 if (m_widget) Show( FALSE );
1741
1742 DestroyChildren();
1743
1744 if (m_parent) m_parent->RemoveChild( this );
1745
1746 if (m_widgetStyle) gtk_style_unref( m_widgetStyle );
1747
1748 if (m_scrollGC) gdk_gc_unref( m_scrollGC );
1749
1750 if (m_wxwindow) gtk_widget_destroy( m_wxwindow );
1751
1752 if (m_widget) gtk_widget_destroy( m_widget );
1753
1754 DeleteRelatedConstraints();
1755 if (m_constraints)
1756 {
1757 /* This removes any dangling pointers to this window
1758 * in other windows' constraintsInvolvedIn lists. */
1759 UnsetConstraints(m_constraints);
1760 delete m_constraints;
1761 m_constraints = (wxLayoutConstraints *) NULL;
1762 }
1763
1764 if (m_windowSizer)
1765 {
1766 delete m_windowSizer;
1767 m_windowSizer = (wxSizer *) NULL;
1768 }
1769 /* If this is a child of a sizer, remove self from parent */
1770 if (m_sizerParent) m_sizerParent->RemoveChild((wxWindow *)this);
1771
1772 /* Just in case the window has been Closed, but
1773 * we're then deleting immediately: don't leave
1774 * dangling pointers. */
1775 wxPendingDelete.DeleteObject(this);
1776
1777 /* Just in case we've loaded a top-level window via
1778 * wxWindow::LoadNativeDialog but we weren't a dialog
1779 * class */
1780 wxTopLevelWindows.DeleteObject(this);
1781
1782 if (m_windowValidator) delete m_windowValidator;
1783
1784 if (m_clientObject) delete m_clientObject;
1785 }
1786
1787 void wxWindow::PreCreation( wxWindow *parent, wxWindowID id,
1788 const wxPoint &pos, const wxSize &size,
1789 long style, const wxString &name )
1790 {
1791 wxASSERT_MSG( (!m_needParent) || (parent), _T("Need complete parent.") );
1792
1793 m_widget = (GtkWidget*) NULL;
1794 m_wxwindow = (GtkWidget*) NULL;
1795 m_hasVMT = FALSE;
1796 m_parent = parent;
1797 m_children.DeleteContents( FALSE );
1798
1799 m_width = size.x;
1800 if (m_width == -1) m_width = 20;
1801 m_height = size.y;
1802 if (m_height == -1) m_height = 20;
1803
1804 m_x = (int)pos.x;
1805 m_y = (int)pos.y;
1806
1807 if (!m_needParent) /* some reasonable defaults */
1808 {
1809 if (m_x == -1)
1810 {
1811 m_x = (gdk_screen_width () - m_width) / 2;
1812 if (m_x < 10) m_x = 10;
1813 }
1814 if (m_y == -1)
1815 {
1816 m_y = (gdk_screen_height () - m_height) / 2;
1817 if (m_y < 10) m_y = 10;
1818 }
1819 }
1820
1821 m_minWidth = -1;
1822 m_minHeight = -1;
1823 m_maxWidth = -1;
1824 m_maxHeight = -1;
1825
1826 m_retCode = 0;
1827
1828 m_eventHandler = this;
1829
1830 m_windowId = id == -1 ? wxNewId() : id;
1831
1832 m_sizeSet = FALSE;
1833
1834 m_cursor = *wxSTANDARD_CURSOR;
1835 m_font = *wxSWISS_FONT;
1836 m_backgroundColour = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
1837 m_foregroundColour = *wxBLACK;
1838 m_windowStyle = style;
1839 m_windowName = name;
1840
1841 m_constraints = (wxLayoutConstraints *) NULL;
1842 m_constraintsInvolvedIn = (wxList *) NULL;
1843 m_windowSizer = (wxSizer *) NULL;
1844 m_sizerParent = (wxWindow *) NULL;
1845 m_autoLayout = FALSE;
1846
1847 m_hasScrolling = FALSE;
1848 m_isScrolling = FALSE;
1849 m_hAdjust = (GtkAdjustment *) NULL;
1850 m_vAdjust = (GtkAdjustment *) NULL;
1851 m_oldHorizontalPos = 0.0;
1852 m_oldVerticalPos = 0.0;
1853
1854 m_isShown = FALSE;
1855 m_isEnabled = TRUE;
1856
1857 #if wxUSE_DRAG_AND_DROP
1858 m_dropTarget = (wxDropTarget *) NULL;
1859 #endif
1860 m_resizing = FALSE;
1861 m_windowValidator = (wxValidator *) NULL;
1862 m_scrollGC = (GdkGC*) NULL;
1863 m_widgetStyle = (GtkStyle*) NULL;
1864
1865 m_clientObject = (wxClientData*)NULL;
1866 m_clientData = NULL;
1867
1868 m_isStaticBox = FALSE;
1869
1870 #if wxUSE_TOOLTIPS
1871 m_toolTip = (wxToolTip*) NULL;
1872 #endif // wxUSE_TOOLTIPS
1873 }
1874
1875 void wxWindow::PostCreation()
1876 {
1877 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
1878
1879 if (m_wxwindow)
1880 {
1881 /* these get reported to wxWindows -> wxPaintEvent */
1882 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
1883 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
1884
1885 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
1886 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
1887
1888 #if (GTK_MINOR_VERSION > 0)
1889 /* these are called when the "sunken" or "raised" borders are drawn */
1890 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
1891 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
1892
1893 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
1894 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
1895 #endif
1896 }
1897
1898 GtkWidget *connect_widget = GetConnectWidget();
1899
1900 ConnectWidget( connect_widget );
1901
1902 /* we cannot set colours, fonts and cursors before the widget has
1903 been realized, so we do this directly after realization */
1904 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
1905 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
1906
1907 m_hasVMT = TRUE;
1908 }
1909
1910 void wxWindow::ConnectWidget( GtkWidget *widget )
1911 {
1912 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
1913 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
1914
1915 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
1916 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
1917
1918 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
1919 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
1920
1921 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
1922 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
1923
1924 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
1925 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
1926
1927 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
1928 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
1929
1930 gtk_signal_connect( GTK_OBJECT(widget), "focus_out_event",
1931 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
1932
1933 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
1934 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
1935
1936 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
1937 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
1938 }
1939
1940 bool wxWindow::HasVMT()
1941 {
1942 return m_hasVMT;
1943 }
1944
1945 bool wxWindow::Close( bool force )
1946 {
1947 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
1948
1949 wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
1950 event.SetEventObject(this);
1951 event.SetCanVeto(!force);
1952
1953 /* return FALSE if window wasn't closed because the application vetoed the
1954 * close event */
1955 return GetEventHandler()->ProcessEvent(event) && !event.GetVeto();
1956 }
1957
1958 bool wxWindow::Destroy()
1959 {
1960 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
1961
1962 m_hasVMT = FALSE;
1963 delete this;
1964 return TRUE;
1965 }
1966
1967 bool wxWindow::DestroyChildren()
1968 {
1969 wxNode *node;
1970 while ((node = m_children.First()) != (wxNode *)NULL)
1971 {
1972 wxWindow *child;
1973 if ((child = (wxWindow *)node->Data()) != (wxWindow *)NULL)
1974 {
1975 delete child;
1976 if (m_children.Member(child)) delete node;
1977 }
1978 }
1979 return TRUE;
1980 }
1981
1982 void wxWindow::PrepareDC( wxDC &WXUNUSED(dc) )
1983 {
1984 // are we to set fonts here ?
1985 }
1986
1987 void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
1988 {
1989 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
1990 wxASSERT_MSG( (m_parent != NULL), _T("wxWindow::SetSize requires parent.\n") );
1991
1992 if (m_resizing) return; /* I don't like recursions */
1993 m_resizing = TRUE;
1994
1995 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook page */
1996 {
1997 /* don't set the size for children of wxNotebook, just take the values. */
1998 m_x = x;
1999 m_y = y;
2000 m_width = width;
2001 m_height = height;
2002 }
2003 else
2004 {
2005 int old_width = m_width;
2006 int old_height = m_height;
2007
2008 if ((sizeFlags & wxSIZE_USE_EXISTING) == wxSIZE_USE_EXISTING)
2009 {
2010 if (x != -1) m_x = x;
2011 if (y != -1) m_y = y;
2012 if (width != -1) m_width = width;
2013 if (height != -1) m_height = height;
2014 }
2015 else
2016 {
2017 m_x = x;
2018 m_y = y;
2019 m_width = width;
2020 m_height = height;
2021 }
2022
2023 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2024 {
2025 if (width == -1) m_width = 80;
2026 }
2027
2028 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2029 {
2030 if (height == -1) m_height = 26;
2031 }
2032
2033 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2034 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2035 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2036 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2037
2038 int border = 0;
2039
2040 if (GTK_WIDGET_HAS_DEFAULT(m_widget))
2041 {
2042 /* the default button has a border around it */
2043 border = 5;
2044 }
2045
2046 /* this is the result of hours of debugging: the following code
2047 means that if we have a m_wxwindow and we set the size of
2048 m_widget, m_widget (which is a GtkScrolledWindow) does NOT
2049 automatically propagate its size down to its m_wxwindow,
2050 which is its client area. therefore, we have to tell the
2051 client area directly that it has to resize itself.
2052 this will lead to that m_widget (GtkScrolledWindow) will
2053 calculate how much size it needs for scrollbars etc and
2054 it will then call XXX_size_allocate of its child, which
2055 is m_wxwindow. m_wxwindow in turn will do the same with its
2056 children and so on. problems can arise if this happens
2057 before all the children have been realized as some widgets
2058 stupidy need to be realized during XXX_size_allocate (e.g.
2059 GtkNotebook) and they will segv if called otherwise. this
2060 emergency is tested in gtk_myfixed_size_allocate. Normally
2061 this shouldn't be needed and only gtk_widget_queue_resize()
2062 should be enough to provoke a resize at the next appropriate
2063 moment, but this seems to fail, e.g. when a wxNotebook contains
2064 a wxSplitterWindow: the splitter window's children won't
2065 show up properly resized then. */
2066
2067 gtk_myfixed_set_size( GTK_MYFIXED(m_parent->m_wxwindow),
2068 m_widget,
2069 m_x-border,
2070 m_y-border,
2071 m_width+2*border,
2072 m_height+2*border );
2073
2074 }
2075
2076 m_sizeSet = TRUE;
2077
2078 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2079 event.SetEventObject( this );
2080 GetEventHandler()->ProcessEvent( event );
2081
2082 m_resizing = FALSE;
2083 }
2084
2085 void wxWindow::OnInternalIdle()
2086 {
2087 UpdateWindowUI();
2088 }
2089
2090 void wxWindow::GetSize( int *width, int *height ) const
2091 {
2092 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2093
2094 if (width) (*width) = m_width;
2095 if (height) (*height) = m_height;
2096 }
2097
2098 void wxWindow::DoSetClientSize( int width, int height )
2099 {
2100 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2101
2102 if (!m_wxwindow)
2103 {
2104 SetSize( width, height );
2105 }
2106 else
2107 {
2108 int dw = 0;
2109 int dh = 0;
2110
2111 if (!m_hasScrolling)
2112 {
2113 GtkStyleClass *window_class = m_wxwindow->style->klass;
2114
2115 if ((m_windowStyle & wxRAISED_BORDER) ||
2116 (m_windowStyle & wxSUNKEN_BORDER))
2117 {
2118 dw += 2 * window_class->xthickness;
2119 dh += 2 * window_class->ythickness;
2120 }
2121 }
2122 else
2123 {
2124 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2125 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2126
2127 #if (GTK_MINOR_VERSION == 0)
2128 GtkWidget *viewport = scroll_window->viewport;
2129 GtkStyleClass *viewport_class = viewport->style->klass;
2130
2131 if ((m_windowStyle & wxRAISED_BORDER) ||
2132 (m_windowStyle & wxSUNKEN_BORDER))
2133 {
2134 dw += 2 * viewport_class->xthickness;
2135 dh += 2 * viewport_class->ythickness;
2136 }
2137 #endif
2138
2139 /*
2140 GtkWidget *hscrollbar = scroll_window->hscrollbar;
2141 GtkWidget *vscrollbar = scroll_window->vscrollbar;
2142
2143 we use this instead: range.slider_width = 11 + 2*2pts edge
2144 */
2145
2146 if (scroll_window->vscrollbar_visible)
2147 {
2148 dw += 15; /* dw += vscrollbar->allocation.width; */
2149 dw += scroll_class->scrollbar_spacing;
2150 }
2151
2152 if (scroll_window->hscrollbar_visible)
2153 {
2154 dh += 15; /* dh += hscrollbar->allocation.height; */
2155 dw += scroll_class->scrollbar_spacing;
2156 }
2157 }
2158
2159 SetSize( width+dw, height+dh );
2160 }
2161 }
2162
2163 void wxWindow::GetClientSize( int *width, int *height ) const
2164 {
2165 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2166
2167 if (!m_wxwindow)
2168 {
2169 if (width) (*width) = m_width;
2170 if (height) (*height) = m_height;
2171 }
2172 else
2173 {
2174 int dw = 0;
2175 int dh = 0;
2176
2177 if (!m_hasScrolling)
2178 {
2179 GtkStyleClass *window_class = m_wxwindow->style->klass;
2180
2181 if ((m_windowStyle & wxRAISED_BORDER) ||
2182 (m_windowStyle & wxSUNKEN_BORDER))
2183 {
2184 dw += 2 * window_class->xthickness;
2185 dh += 2 * window_class->ythickness;
2186 }
2187 }
2188 else
2189 {
2190 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2191 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2192
2193 #if (GTK_MINOR_VERSION == 0)
2194 GtkWidget *viewport = scroll_window->viewport;
2195 GtkStyleClass *viewport_class = viewport->style->klass;
2196
2197 if ((m_windowStyle & wxRAISED_BORDER) ||
2198 (m_windowStyle & wxSUNKEN_BORDER))
2199 {
2200 dw += 2 * viewport_class->xthickness;
2201 dh += 2 * viewport_class->ythickness;
2202 }
2203 #endif
2204 /*
2205 GtkWidget *hscrollbar = scroll_window->hscrollbar;
2206 GtkWidget *vscrollbar = scroll_window->vscrollbar;
2207
2208 we use this instead: range.slider_width = 11 + 2*2pts edge
2209 */
2210
2211 if (scroll_window->vscrollbar_visible)
2212 {
2213 dw += 15; /* dw += vscrollbar->allocation.width; */
2214 dw += scroll_class->scrollbar_spacing;
2215 }
2216
2217 if (scroll_window->hscrollbar_visible)
2218 {
2219 dh += 15; /* dh += hscrollbar->allocation.height; */
2220 dh += scroll_class->scrollbar_spacing;
2221 }
2222 }
2223
2224 if (width) (*width) = m_width - dw;
2225 if (height) (*height) = m_height - dh;
2226 }
2227 }
2228
2229 void wxWindow::GetPosition( int *x, int *y ) const
2230 {
2231 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2232
2233 if (x) (*x) = m_x;
2234 if (y) (*y) = m_y;
2235 }
2236
2237 void wxWindow::ClientToScreen( int *x, int *y )
2238 {
2239 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2240
2241 if (!m_widget->window) return;
2242
2243 GdkWindow *source = (GdkWindow *) NULL;
2244 if (m_wxwindow)
2245 source = m_wxwindow->window;
2246 else
2247 source = m_widget->window;
2248
2249 int org_x = 0;
2250 int org_y = 0;
2251 gdk_window_get_origin( source, &org_x, &org_y );
2252
2253 if (!m_wxwindow)
2254 {
2255 if (GTK_WIDGET_NO_WINDOW (m_widget))
2256 {
2257 org_x += m_widget->allocation.x;
2258 org_y += m_widget->allocation.y;
2259 }
2260 }
2261
2262 if (x) *x += org_x;
2263 if (y) *y += org_y;
2264 }
2265
2266 void wxWindow::ScreenToClient( int *x, int *y )
2267 {
2268 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2269
2270 if (!m_widget->window) return;
2271
2272 GdkWindow *source = (GdkWindow *) NULL;
2273 if (m_wxwindow)
2274 source = m_wxwindow->window;
2275 else
2276 source = m_widget->window;
2277
2278 int org_x = 0;
2279 int org_y = 0;
2280 gdk_window_get_origin( source, &org_x, &org_y );
2281
2282 if (!m_wxwindow)
2283 {
2284 if (GTK_WIDGET_NO_WINDOW (m_widget))
2285 {
2286 org_x += m_widget->allocation.x;
2287 org_y += m_widget->allocation.y;
2288 }
2289 }
2290
2291 if (x) *x -= org_x;
2292 if (y) *y -= org_y;
2293 }
2294
2295 void wxWindow::Centre( int direction )
2296 {
2297 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2298
2299 int x = m_x;
2300 int y = m_y;
2301
2302 if (m_parent)
2303 {
2304 int p_w = 0;
2305 int p_h = 0;
2306 m_parent->GetSize( &p_w, &p_h );
2307 if (direction & wxHORIZONTAL == wxHORIZONTAL) x = (p_w - m_width) / 2;
2308 if (direction & wxVERTICAL == wxVERTICAL) y = (p_h - m_height) / 2;
2309 }
2310 else
2311 {
2312 if (direction & wxHORIZONTAL == wxHORIZONTAL) x = (gdk_screen_width () - m_width) / 2;
2313 if (direction & wxVERTICAL == wxVERTICAL) y = (gdk_screen_height () - m_height) / 2;
2314 }
2315
2316 Move( x, y );
2317 }
2318
2319 void wxWindow::Fit()
2320 {
2321 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2322
2323 int maxX = 0;
2324 int maxY = 0;
2325 wxNode *node = m_children.First();
2326 while (node)
2327 {
2328 wxWindow *win = (wxWindow *)node->Data();
2329 int wx, wy, ww, wh;
2330 win->GetPosition(&wx, &wy);
2331 win->GetSize(&ww, &wh);
2332 if (wx + ww > maxX) maxX = wx + ww;
2333 if (wy + wh > maxY) maxY = wy + wh;
2334
2335 node = node->Next();
2336 }
2337
2338 SetClientSize(maxX + 7, maxY + 14);
2339 }
2340
2341 void wxWindow::SetSizeHints( int minW, int minH, int maxW, int maxH, int WXUNUSED(incW), int WXUNUSED(incH) )
2342 {
2343 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2344
2345 m_minWidth = minW;
2346 m_minHeight = minH;
2347 m_maxWidth = maxW;
2348 m_maxHeight = maxH;
2349 }
2350
2351 void wxWindow::OnSize( wxSizeEvent &WXUNUSED(event) )
2352 {
2353 /* this is commented because it also is commented
2354 in wxMSW. before I get even more questions about
2355 this. */
2356 // if (GetAutoLayout()) Layout();
2357 }
2358
2359 bool wxWindow::Show( bool show )
2360 {
2361 wxCHECK_MSG( (m_widget != NULL), FALSE, _T("invalid window") );
2362
2363 if (show == m_isShown) return TRUE;
2364
2365 if (show)
2366 gtk_widget_show( m_widget );
2367 else
2368 gtk_widget_hide( m_widget );
2369
2370 m_isShown = show;
2371
2372 return TRUE;
2373 }
2374
2375 void wxWindow::Enable( bool enable )
2376 {
2377 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2378
2379 m_isEnabled = enable;
2380
2381 gtk_widget_set_sensitive( m_widget, enable );
2382 if (m_wxwindow) gtk_widget_set_sensitive( m_wxwindow, enable );
2383 }
2384
2385 int wxWindow::GetCharHeight() const
2386 {
2387 wxCHECK_MSG( (m_widget != NULL), 12, _T("invalid window") );
2388
2389 wxCHECK_MSG( m_font.Ok(), 12, _T("invalid font") );
2390
2391 GdkFont *font = m_font.GetInternalFont( 1.0 );
2392
2393 return font->ascent + font->descent;
2394 }
2395
2396 int wxWindow::GetCharWidth() const
2397 {
2398 wxCHECK_MSG( (m_widget != NULL), 8, _T("invalid window") );
2399
2400 wxCHECK_MSG( m_font.Ok(), 8, _T("invalid font") );
2401
2402 GdkFont *font = m_font.GetInternalFont( 1.0 );
2403
2404 return gdk_string_width( font, "H" );
2405 }
2406
2407 void wxWindow::GetTextExtent( const wxString& string, int *x, int *y,
2408 int *descent, int *externalLeading, const wxFont *theFont, bool WXUNUSED(use16) ) const
2409 {
2410 wxFont fontToUse = m_font;
2411 if (theFont) fontToUse = *theFont;
2412
2413 wxCHECK_RET( fontToUse.Ok(), _T("invalid font") );
2414
2415 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
2416 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
2417 if (y) (*y) = font->ascent + font->descent;
2418 if (descent) (*descent) = font->descent;
2419 if (externalLeading) (*externalLeading) = 0; // ??
2420 }
2421
2422 void wxWindow::MakeModal( bool modal )
2423 {
2424 return;
2425
2426 // Disable all other windows
2427 if (this->IsKindOf(CLASSINFO(wxDialog)) || this->IsKindOf(CLASSINFO(wxFrame)))
2428 {
2429 wxNode *node = wxTopLevelWindows.First();
2430 while (node)
2431 {
2432 wxWindow *win = (wxWindow *)node->Data();
2433 if (win != this) win->Enable(!modal);
2434
2435 node = node->Next();
2436 }
2437 }
2438 }
2439
2440 void wxWindow::OnKeyDown( wxKeyEvent &event )
2441 {
2442 event.SetEventType( wxEVT_CHAR );
2443
2444 if (!GetEventHandler()->ProcessEvent( event ))
2445 {
2446 event.Skip();
2447 }
2448 }
2449
2450 void wxWindow::SetFocus()
2451 {
2452 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2453
2454 GtkWidget *connect_widget = GetConnectWidget();
2455 if (connect_widget)
2456 {
2457 if (GTK_WIDGET_CAN_FOCUS(connect_widget) /*&& !GTK_WIDGET_HAS_FOCUS (connect_widget)*/ )
2458 {
2459 gtk_widget_grab_focus (connect_widget);
2460 }
2461 else if (GTK_IS_CONTAINER(connect_widget))
2462 {
2463 gtk_container_focus( GTK_CONTAINER(connect_widget), GTK_DIR_TAB_FORWARD );
2464 }
2465 else
2466 {
2467 }
2468 }
2469 }
2470
2471 wxWindow *wxWindow::FindFocus()
2472 {
2473 return g_focusWindow;
2474 }
2475
2476 bool wxWindow::AcceptsFocus() const
2477 {
2478 return IsEnabled() && IsShown() && m_acceptsFocus;
2479 }
2480
2481 void wxWindow::AddChild( wxWindow *child )
2482 {
2483 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2484 wxCHECK_RET( (child != NULL), _T("invalid child") );
2485
2486 m_children.Append( child );
2487 }
2488
2489 wxWindow *wxWindow::ReParent( wxWindow *newParent )
2490 {
2491 wxCHECK_MSG( (m_widget != NULL), (wxWindow*) NULL, _T("invalid window") );
2492
2493 wxWindow *oldParent = GetParent();
2494
2495 if (oldParent) oldParent->RemoveChild( this );
2496
2497 gtk_widget_unparent( m_widget );
2498
2499 if (newParent)
2500 {
2501 newParent->AddChild( this );
2502 (newParent->m_insertCallback)( newParent, this );
2503 }
2504
2505 return oldParent;
2506 }
2507
2508 void wxWindow::RemoveChild( wxWindow *child )
2509 {
2510 m_children.DeleteObject( child );
2511 child->m_parent = (wxWindow *) NULL;
2512 }
2513
2514 void wxWindow::SetReturnCode( int retCode )
2515 {
2516 m_retCode = retCode;
2517 }
2518
2519 int wxWindow::GetReturnCode()
2520 {
2521 return m_retCode;
2522 }
2523
2524 void wxWindow::Raise()
2525 {
2526 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2527
2528 if (!m_widget->window) return;
2529
2530 if (m_widget) gdk_window_raise( m_widget->window );
2531 }
2532
2533 void wxWindow::Lower()
2534 {
2535 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2536
2537 if (!m_widget->window) return;
2538
2539 if (m_widget) gdk_window_lower( m_widget->window );
2540 }
2541
2542 wxEvtHandler *wxWindow::GetEventHandler() const
2543 {
2544 return m_eventHandler;
2545 }
2546
2547 void wxWindow::SetEventHandler( wxEvtHandler *handler )
2548 {
2549 m_eventHandler = handler;
2550 }
2551
2552 void wxWindow::PushEventHandler(wxEvtHandler *handler)
2553 {
2554 handler->SetNextHandler(GetEventHandler());
2555 SetEventHandler(handler);
2556 }
2557
2558 wxEvtHandler *wxWindow::PopEventHandler(bool deleteHandler)
2559 {
2560 if (GetEventHandler())
2561 {
2562 wxEvtHandler *handlerA = GetEventHandler();
2563 wxEvtHandler *handlerB = handlerA->GetNextHandler();
2564 handlerA->SetNextHandler((wxEvtHandler *) NULL);
2565 SetEventHandler(handlerB);
2566 if (deleteHandler)
2567 {
2568 delete handlerA;
2569 return (wxEvtHandler*) NULL;
2570 }
2571 else
2572 return handlerA;
2573 }
2574 else
2575 return (wxEvtHandler *) NULL;
2576 }
2577
2578 wxValidator *wxWindow::GetValidator()
2579 {
2580 return m_windowValidator;
2581 }
2582
2583 void wxWindow::SetValidator( const wxValidator& validator )
2584 {
2585 if (m_windowValidator) delete m_windowValidator;
2586 m_windowValidator = (wxValidator*)validator.Clone();
2587 if (m_windowValidator) m_windowValidator->SetWindow(this);
2588 }
2589
2590 void wxWindow::SetClientObject( wxClientData *data )
2591 {
2592 if (m_clientObject) delete m_clientObject;
2593 m_clientObject = data;
2594 }
2595
2596 wxClientData *wxWindow::GetClientObject()
2597 {
2598 return m_clientObject;
2599 }
2600
2601 void wxWindow::SetClientData( void *data )
2602 {
2603 m_clientData = data;
2604 }
2605
2606 void *wxWindow::GetClientData()
2607 {
2608 return m_clientData;
2609 }
2610
2611 bool wxWindow::IsBeingDeleted()
2612 {
2613 return FALSE;
2614 }
2615
2616 void wxWindow::SetId( wxWindowID id )
2617 {
2618 m_windowId = id;
2619 }
2620
2621 wxWindowID wxWindow::GetId() const
2622 {
2623 return m_windowId;
2624 }
2625
2626 void wxWindow::SetCursor( const wxCursor &cursor )
2627 {
2628 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2629
2630 if (cursor.Ok())
2631 {
2632 if (cursor == m_cursor) return;
2633 m_cursor = cursor;
2634 }
2635 else
2636 {
2637 m_cursor = *wxSTANDARD_CURSOR;
2638 }
2639
2640 if (!m_widget->window) return;
2641
2642 gdk_window_set_cursor( m_widget->window, m_cursor.GetCursor() );
2643
2644 if ((m_wxwindow) && (m_wxwindow->window))
2645 gdk_window_set_cursor( m_wxwindow->window, m_cursor.GetCursor() );
2646 }
2647
2648 void wxWindow::WarpPointer( int WXUNUSED(x), int WXUNUSED(y) )
2649 {
2650 // TODO
2651 }
2652
2653 void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
2654 {
2655 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2656
2657 if (!m_widget->window) return;
2658
2659 if (eraseBackground && m_wxwindow && m_wxwindow->window)
2660 {
2661 if (rect)
2662 {
2663 gdk_window_clear_area( m_wxwindow->window,
2664 rect->x, rect->y,
2665 rect->width, rect->height );
2666 }
2667 else
2668 {
2669 gdk_window_clear( m_wxwindow->window );
2670 }
2671 }
2672
2673 if (!rect)
2674 {
2675 if (m_wxwindow)
2676 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
2677 else
2678 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
2679 }
2680 else
2681 {
2682 GdkRectangle gdk_rect;
2683 gdk_rect.x = rect->x;
2684 gdk_rect.y = rect->y;
2685 gdk_rect.width = rect->width;
2686 gdk_rect.height = rect->height;
2687
2688 if (m_wxwindow)
2689 gtk_widget_draw( m_wxwindow, &gdk_rect );
2690 else
2691 gtk_widget_draw( m_widget, &gdk_rect );
2692 }
2693 }
2694
2695 wxRegion wxWindow::GetUpdateRegion() const
2696 {
2697 return m_updateRegion;
2698 }
2699
2700 bool wxWindow::IsExposed( int x, int y) const
2701 {
2702 return (m_updateRegion.Contains( x, y ) != wxOutRegion );
2703 }
2704
2705 bool wxWindow::IsExposed( int x, int y, int w, int h ) const
2706 {
2707 return (m_updateRegion.Contains( x, y, w, h ) != wxOutRegion );
2708 }
2709
2710 bool wxWindow::IsExposed( const wxPoint& pt ) const
2711 {
2712 return (m_updateRegion.Contains( pt.x, pt.y ) != wxOutRegion );
2713 }
2714
2715 bool wxWindow::IsExposed( const wxRect& rect ) const
2716 {
2717 return (m_updateRegion.Contains( rect.x, rect.y, rect.width, rect.height ) != wxOutRegion );
2718 }
2719
2720 void wxWindow::Clear()
2721 {
2722 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2723
2724 if (!m_widget->window) return;
2725
2726 if (m_wxwindow && m_wxwindow->window)
2727 {
2728 gdk_window_clear( m_wxwindow->window );
2729 }
2730 }
2731
2732 #if wxUSE_TOOLTIPS
2733 void wxWindow::SetToolTip( const wxString &tip )
2734 {
2735 if (m_toolTip)
2736 {
2737 m_toolTip->SetTip( tip );
2738 }
2739 else
2740 {
2741 SetToolTip( new wxToolTip( tip ) );
2742 }
2743
2744 // setting empty tooltip text does not remove the tooltip any more for
2745 // wxMSW compatibility - use SetToolTip((wxToolTip *)NULL) for this
2746 }
2747
2748 void wxWindow::SetToolTip( wxToolTip *tip )
2749 {
2750 if (m_toolTip)
2751 {
2752 m_toolTip->SetTip( (char*) NULL );
2753 delete m_toolTip;
2754 }
2755
2756 m_toolTip = tip;
2757
2758 if (m_toolTip)
2759 m_toolTip->Apply( this );
2760 }
2761
2762 void wxWindow::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
2763 {
2764 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConv_current->cWX2MB(tip), (gchar*) NULL );
2765 }
2766 #endif // wxUSE_TOOLTIPS
2767
2768 wxColour wxWindow::GetBackgroundColour() const
2769 {
2770 return m_backgroundColour;
2771 }
2772
2773 void wxWindow::SetBackgroundColour( const wxColour &colour )
2774 {
2775 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2776
2777 if (m_backgroundColour == colour) return;
2778
2779 m_backgroundColour = colour;
2780 if (!m_backgroundColour.Ok()) return;
2781
2782 GtkWidget *connect_widget = GetConnectWidget();
2783 if (!connect_widget->window) return;
2784
2785 if (m_wxwindow && m_wxwindow->window)
2786 {
2787 /* wxMSW doesn't clear the window here. I don't do that
2788 either to provide compatibility. call Clear() to do
2789 the job. */
2790
2791 m_backgroundColour.CalcPixel( gdk_window_get_colormap( m_wxwindow->window ) );
2792 gdk_window_set_background( m_wxwindow->window, m_backgroundColour.GetColor() );
2793 }
2794
2795 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
2796
2797 if (sysbg.Red() == colour.Red() &&
2798 sysbg.Green() == colour.Green() &&
2799 sysbg.Blue() == colour.Blue())
2800 {
2801 m_backgroundColour = wxNullColour;
2802 ApplyWidgetStyle();
2803 m_backgroundColour = sysbg;
2804 }
2805 else
2806 {
2807 ApplyWidgetStyle();
2808 }
2809 }
2810
2811 wxColour wxWindow::GetForegroundColour() const
2812 {
2813 return m_foregroundColour;
2814 }
2815
2816 void wxWindow::SetForegroundColour( const wxColour &colour )
2817 {
2818 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2819
2820 if (m_foregroundColour == colour) return;
2821
2822 m_foregroundColour = colour;
2823 if (!m_foregroundColour.Ok()) return;
2824
2825 if (!m_widget->window) return;
2826
2827 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
2828 if (sysbg.Red() == colour.Red() &&
2829 sysbg.Green() == colour.Green() &&
2830 sysbg.Blue() == colour.Blue())
2831 {
2832 m_backgroundColour = wxNullColour;
2833 ApplyWidgetStyle();
2834 m_backgroundColour = sysbg;
2835 }
2836 else
2837 {
2838 ApplyWidgetStyle();
2839 }
2840 }
2841
2842 GtkStyle *wxWindow::GetWidgetStyle()
2843 {
2844 if (m_widgetStyle) gtk_style_unref( m_widgetStyle );
2845
2846 m_widgetStyle =
2847 gtk_style_copy(
2848 gtk_widget_get_style( m_widget ) );
2849
2850 return m_widgetStyle;
2851 }
2852
2853 void wxWindow::SetWidgetStyle()
2854 {
2855 GtkStyle *style = GetWidgetStyle();
2856
2857 gdk_font_unref( style->font );
2858 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
2859
2860 if (m_foregroundColour.Ok())
2861 {
2862 m_foregroundColour.CalcPixel( gdk_window_get_colormap( m_widget->window ) );
2863 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
2864 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
2865 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
2866 }
2867
2868 if (m_backgroundColour.Ok())
2869 {
2870 m_backgroundColour.CalcPixel( gdk_window_get_colormap( m_widget->window ) );
2871 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
2872 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
2873 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
2874 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
2875 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
2876 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
2877 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
2878 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
2879 }
2880 }
2881
2882 void wxWindow::ApplyWidgetStyle()
2883 {
2884 }
2885
2886 bool wxWindow::Validate()
2887 {
2888 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2889
2890 wxNode *node = m_children.First();
2891 while (node)
2892 {
2893 wxWindow *child = (wxWindow *)node->Data();
2894 if (child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->Validate(this))
2895 {
2896 return FALSE;
2897 }
2898 node = node->Next();
2899 }
2900 return TRUE;
2901 }
2902
2903 bool wxWindow::TransferDataToWindow()
2904 {
2905 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2906
2907 wxNode *node = m_children.First();
2908 while (node)
2909 {
2910 wxWindow *child = (wxWindow *)node->Data();
2911 if (child->GetValidator() && /* child->GetValidator()->Ok() && */
2912 !child->GetValidator()->TransferToWindow() )
2913 {
2914 wxMessageBox( _("Application Error"), _("Could not transfer data to window"), wxOK|wxICON_EXCLAMATION );
2915 return FALSE;
2916 }
2917 node = node->Next();
2918 }
2919 return TRUE;
2920 }
2921
2922 bool wxWindow::TransferDataFromWindow()
2923 {
2924 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2925
2926 wxNode *node = m_children.First();
2927 while (node)
2928 {
2929 wxWindow *child = (wxWindow *)node->Data();
2930 if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->TransferFromWindow() )
2931 {
2932 return FALSE;
2933 }
2934 node = node->Next();
2935 }
2936 return TRUE;
2937 }
2938
2939 void wxWindow::SetAcceleratorTable( const wxAcceleratorTable& accel )
2940 {
2941 m_acceleratorTable = accel;
2942 }
2943
2944 void wxWindow::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
2945 {
2946 TransferDataToWindow();
2947 }
2948
2949 void wxWindow::InitDialog()
2950 {
2951 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2952
2953 wxInitDialogEvent event(GetId());
2954 event.SetEventObject( this );
2955 GetEventHandler()->ProcessEvent(event);
2956 }
2957
2958 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
2959 {
2960 menu->SetInvokingWindow( win );
2961 wxNode *node = menu->GetItems().First();
2962 while (node)
2963 {
2964 wxMenuItem *menuitem = (wxMenuItem*)node->Data();
2965 if (menuitem->IsSubMenu())
2966 {
2967 SetInvokingWindow( menuitem->GetSubMenu(), win );
2968 }
2969 node = node->Next();
2970 }
2971 }
2972
2973 static gint gs_pop_x = 0;
2974 static gint gs_pop_y = 0;
2975
2976 static void pop_pos_callback( GtkMenu *menu, gint *x, gint *y, wxWindow *win )
2977 {
2978 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
2979 *x = gs_pop_x;
2980 *y = gs_pop_y;
2981 }
2982
2983 bool wxWindow::PopupMenu( wxMenu *menu, int x, int y )
2984 {
2985 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2986
2987 wxCHECK_MSG( menu != NULL, FALSE, _T("invalid popup-menu") );
2988
2989 SetInvokingWindow( menu, this );
2990
2991 menu->UpdateUI();
2992
2993 gs_pop_x = x;
2994 gs_pop_y = y;
2995
2996 gtk_menu_popup(
2997 GTK_MENU(menu->m_menu),
2998 (GtkWidget *) NULL, // parent menu shell
2999 (GtkWidget *) NULL, // parent menu item
3000 (GtkMenuPositionFunc) pop_pos_callback,
3001 (gpointer) this, // client data
3002 0, // button used to activate it
3003 0 //gs_timeLastClick // the time of activation
3004 );
3005 return TRUE;
3006 }
3007
3008 #if wxUSE_DRAG_AND_DROP
3009
3010 void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
3011 {
3012 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3013
3014 GtkWidget *dnd_widget = GetConnectWidget();
3015
3016 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3017
3018 if (m_dropTarget) delete m_dropTarget;
3019 m_dropTarget = dropTarget;
3020
3021 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3022 }
3023
3024 wxDropTarget *wxWindow::GetDropTarget() const
3025 {
3026 return m_dropTarget;
3027 }
3028
3029 #endif
3030
3031 GtkWidget* wxWindow::GetConnectWidget()
3032 {
3033 GtkWidget *connect_widget = m_widget;
3034 if (m_wxwindow) connect_widget = m_wxwindow;
3035
3036 return connect_widget;
3037 }
3038
3039 bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
3040 {
3041 if (m_wxwindow) return (window == m_wxwindow->window);
3042 return (window == m_widget->window);
3043 }
3044
3045 void wxWindow::SetFont( const wxFont &font )
3046 {
3047 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3048
3049 if (m_font == font) return;
3050
3051 if (((wxFont*)&font)->Ok())
3052 m_font = font;
3053 else
3054 m_font = *wxSWISS_FONT;
3055
3056 if (!m_widget->window) return;
3057
3058 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
3059 if (sysbg.Red() == m_backgroundColour.Red() &&
3060 sysbg.Green() == m_backgroundColour.Green() &&
3061 sysbg.Blue() == m_backgroundColour.Blue())
3062 {
3063 m_backgroundColour = wxNullColour;
3064 ApplyWidgetStyle();
3065 m_backgroundColour = sysbg;
3066 }
3067 else
3068 {
3069 ApplyWidgetStyle();
3070 }
3071 }
3072
3073 void wxWindow::SetWindowStyleFlag( long flag )
3074 {
3075 m_windowStyle = flag;
3076 }
3077
3078 long wxWindow::GetWindowStyleFlag() const
3079 {
3080 return m_windowStyle;
3081 }
3082
3083 void wxWindow::CaptureMouse()
3084 {
3085 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3086
3087 wxCHECK_RET( g_capturing == FALSE, _T("CaptureMouse called twice") );
3088
3089 if (!m_widget->window) return;
3090
3091 GtkWidget *connect_widget = GetConnectWidget();
3092 gtk_grab_add( connect_widget );
3093 gdk_pointer_grab( connect_widget->window, FALSE,
3094 (GdkEventMask)
3095 (GDK_BUTTON_PRESS_MASK |
3096 GDK_BUTTON_RELEASE_MASK |
3097 GDK_POINTER_MOTION_MASK),
3098 (GdkWindow *) NULL,
3099 (GdkCursor *) NULL,
3100 GDK_CURRENT_TIME );
3101 g_capturing = TRUE;
3102 }
3103
3104 void wxWindow::ReleaseMouse()
3105 {
3106 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3107
3108 wxCHECK_RET( g_capturing == TRUE, _T("ReleaseMouse called twice") );
3109
3110 if (!m_widget->window) return;
3111
3112 GtkWidget *connect_widget = GetConnectWidget();
3113 gtk_grab_remove( connect_widget );
3114 gdk_pointer_ungrab ( GDK_CURRENT_TIME );
3115 g_capturing = FALSE;
3116 }
3117
3118 void wxWindow::SetTitle( const wxString &WXUNUSED(title) )
3119 {
3120 }
3121
3122 wxString wxWindow::GetTitle() const
3123 {
3124 return (wxString&)m_windowName;
3125 }
3126
3127 wxString wxWindow::GetLabel() const
3128 {
3129 return GetTitle();
3130 }
3131
3132 void wxWindow::SetName( const wxString &name )
3133 {
3134 m_windowName = name;
3135 }
3136
3137 wxString wxWindow::GetName() const
3138 {
3139 return (wxString&)m_windowName;
3140 }
3141
3142 bool wxWindow::IsShown() const
3143 {
3144 return m_isShown;
3145 }
3146
3147 bool wxWindow::IsRetained()
3148 {
3149 return FALSE;
3150 }
3151
3152 wxWindow *wxWindow::FindWindow( long id )
3153 {
3154 if (id == m_windowId) return this;
3155 wxNode *node = m_children.First();
3156 while (node)
3157 {
3158 wxWindow *child = (wxWindow*)node->Data();
3159 wxWindow *res = child->FindWindow( id );
3160 if (res) return res;
3161 node = node->Next();
3162 }
3163 return (wxWindow *) NULL;
3164 }
3165
3166 wxWindow *wxWindow::FindWindow( const wxString& name )
3167 {
3168 if (name == m_windowName) return this;
3169 wxNode *node = m_children.First();
3170 while (node)
3171 {
3172 wxWindow *child = (wxWindow*)node->Data();
3173 wxWindow *res = child->FindWindow( name );
3174 if (res) return res;
3175 node = node->Next();
3176 }
3177 return (wxWindow *) NULL;
3178 }
3179
3180 void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
3181 int range, bool refresh )
3182 {
3183 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3184
3185 wxCHECK_RET( m_wxwindow != NULL, _T("window needs client area for scrolling") );
3186
3187 m_hasScrolling = TRUE;
3188
3189 if (orient == wxHORIZONTAL)
3190 {
3191 float fpos = (float)pos;
3192 float frange = (float)range;
3193 float fthumb = (float)thumbVisible;
3194 if (fpos > frange-fthumb) fpos = frange-fthumb;
3195 if (fpos < 0.0) fpos = 0.0;
3196
3197 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3198 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3199 {
3200 SetScrollPos( orient, pos, refresh );
3201 return;
3202 }
3203
3204 m_oldHorizontalPos = fpos;
3205
3206 m_hAdjust->lower = 0.0;
3207 m_hAdjust->upper = frange;
3208 m_hAdjust->value = fpos;
3209 m_hAdjust->step_increment = 1.0;
3210 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3211 m_hAdjust->page_size = fthumb;
3212 }
3213 else
3214 {
3215 float fpos = (float)pos;
3216 float frange = (float)range;
3217 float fthumb = (float)thumbVisible;
3218 if (fpos > frange-fthumb) fpos = frange-fthumb;
3219 if (fpos < 0.0) fpos = 0.0;
3220
3221 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3222 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3223 {
3224 SetScrollPos( orient, pos, refresh );
3225 return;
3226 }
3227
3228 m_oldVerticalPos = fpos;
3229
3230 m_vAdjust->lower = 0.0;
3231 m_vAdjust->upper = frange;
3232 m_vAdjust->value = fpos;
3233 m_vAdjust->step_increment = 1.0;
3234 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3235 m_vAdjust->page_size = fthumb;
3236 }
3237
3238 if (m_wxwindow)
3239 {
3240 if (orient == wxHORIZONTAL)
3241 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3242 else
3243 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3244
3245 gtk_widget_set_usize( m_widget, m_width, m_height );
3246 }
3247 }
3248
3249 void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3250 {
3251 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3252
3253 wxCHECK_RET( m_wxwindow != NULL, _T("window needs client area for scrolling") );
3254
3255 if (orient == wxHORIZONTAL)
3256 {
3257 float fpos = (float)pos;
3258 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3259 if (fpos < 0.0) fpos = 0.0;
3260 m_oldHorizontalPos = fpos;
3261
3262 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3263 m_hAdjust->value = fpos;
3264 }
3265 else
3266 {
3267 float fpos = (float)pos;
3268 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3269 if (fpos < 0.0) fpos = 0.0;
3270 m_oldVerticalPos = fpos;
3271
3272 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3273 m_vAdjust->value = fpos;
3274 }
3275
3276 if (!m_isScrolling)
3277 {
3278 if (m_wxwindow->window)
3279 {
3280 if (orient == wxHORIZONTAL)
3281 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3282 else
3283 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3284 }
3285 }
3286 }
3287
3288 int wxWindow::GetScrollThumb( int orient ) const
3289 {
3290 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid window") );
3291
3292 wxCHECK_MSG( m_wxwindow != NULL, 0, _T("window needs client area for scrolling") );
3293
3294 if (orient == wxHORIZONTAL)
3295 return (int)(m_hAdjust->page_size+0.5);
3296 else
3297 return (int)(m_vAdjust->page_size+0.5);
3298 }
3299
3300 int wxWindow::GetScrollPos( int orient ) const
3301 {
3302 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid window") );
3303
3304 wxCHECK_MSG( m_wxwindow != NULL, 0, _T("window needs client area for scrolling") );
3305
3306 if (orient == wxHORIZONTAL)
3307 return (int)(m_hAdjust->value+0.5);
3308 else
3309 return (int)(m_vAdjust->value+0.5);
3310 }
3311
3312 int wxWindow::GetScrollRange( int orient ) const
3313 {
3314 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid window") );
3315
3316 wxCHECK_MSG( m_wxwindow != NULL, 0, _T("window needs client area for scrolling") );
3317
3318 if (orient == wxHORIZONTAL)
3319 return (int)(m_hAdjust->upper+0.5);
3320 else
3321 return (int)(m_vAdjust->upper+0.5);
3322 }
3323
3324 void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3325 {
3326 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3327
3328 wxCHECK_RET( m_wxwindow != NULL, _T("window needs client area for scrolling") );
3329
3330 wxNode *node = m_children.First();
3331 while (node)
3332 {
3333 wxWindow *child = (wxWindow*) node->Data();
3334 child->Move( child->m_x + dx, child->m_y + dy );
3335 node = node->Next();
3336 }
3337
3338 int cw = 0;
3339 int ch = 0;
3340 GetClientSize( &cw, &ch );
3341
3342 int w = cw - abs(dx);
3343 int h = ch - abs(dy);
3344 if ((h < 0) || (w < 0))
3345 {
3346 Refresh();
3347 return;
3348 }
3349 int s_x = 0;
3350 int s_y = 0;
3351 if (dx < 0) s_x = -dx;
3352 if (dy < 0) s_y = -dy;
3353 int d_x = 0;
3354 int d_y = 0;
3355 if (dx > 0) d_x = dx;
3356 if (dy > 0) d_y = dy;
3357
3358 if (!m_scrollGC)
3359 {
3360 m_scrollGC = gdk_gc_new( m_wxwindow->window );
3361 gdk_gc_set_exposures( m_scrollGC, TRUE );
3362 }
3363
3364 gdk_window_copy_area( m_wxwindow->window, m_scrollGC, d_x, d_y,
3365 m_wxwindow->window, s_x, s_y, w, h );
3366
3367 wxRect rect;
3368 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
3369 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
3370 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
3371 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
3372
3373 Refresh( TRUE, &rect );
3374 }
3375
3376 //-------------------------------------------------------------------------------------
3377 // Layout
3378 //-------------------------------------------------------------------------------------
3379
3380 wxLayoutConstraints *wxWindow::GetConstraints() const
3381 {
3382 return m_constraints;
3383 }
3384
3385 void wxWindow::SetConstraints( wxLayoutConstraints *constraints )
3386 {
3387 if (m_constraints)
3388 {
3389 UnsetConstraints(m_constraints);
3390 delete m_constraints;
3391 }
3392 m_constraints = constraints;
3393 if (m_constraints)
3394 {
3395 // Make sure other windows know they're part of a 'meaningful relationship'
3396 if (m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this))
3397 m_constraints->left.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3398 if (m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this))
3399 m_constraints->top.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3400 if (m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this))
3401 m_constraints->right.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3402 if (m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this))
3403 m_constraints->bottom.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3404 if (m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this))
3405 m_constraints->width.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3406 if (m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this))
3407 m_constraints->height.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3408 if (m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this))
3409 m_constraints->centreX.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3410 if (m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this))
3411 m_constraints->centreY.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
3412 }
3413 ;
3414 }
3415 ;
3416
3417 void wxWindow::SetAutoLayout( bool autoLayout )
3418 {
3419 m_autoLayout = autoLayout;
3420 }
3421
3422 bool wxWindow::GetAutoLayout() const
3423 {
3424 return m_autoLayout;
3425 }
3426
3427 wxSizer *wxWindow::GetSizer() const
3428 {
3429 return m_windowSizer;
3430 }
3431
3432 void wxWindow::SetSizerParent( wxWindow *win )
3433 {
3434 m_sizerParent = win;
3435 }
3436
3437 wxWindow *wxWindow::GetSizerParent() const
3438 {
3439 return m_sizerParent;
3440 }
3441
3442 // This removes any dangling pointers to this window
3443 // in other windows' constraintsInvolvedIn lists.
3444 void wxWindow::UnsetConstraints(wxLayoutConstraints *c)
3445 {
3446 if (c)
3447 {
3448 if (c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this))
3449 c->left.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3450 if (c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this))
3451 c->top.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3452 if (c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this))
3453 c->right.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3454 if (c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this))
3455 c->bottom.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3456 if (c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this))
3457 c->width.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3458 if (c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this))
3459 c->height.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3460 if (c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this))
3461 c->centreX.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3462 if (c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this))
3463 c->centreY.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
3464 }
3465 }
3466
3467 // Back-pointer to other windows we're involved with, so if we delete
3468 // this window, we must delete any constraints we're involved with.
3469 void wxWindow::AddConstraintReference(wxWindow *otherWin)
3470 {
3471 if (!m_constraintsInvolvedIn)
3472 m_constraintsInvolvedIn = new wxList;
3473 if (!m_constraintsInvolvedIn->Member(otherWin))
3474 m_constraintsInvolvedIn->Append(otherWin);
3475 }
3476
3477 // REMOVE back-pointer to other windows we're involved with.
3478 void wxWindow::RemoveConstraintReference(wxWindow *otherWin)
3479 {
3480 if (m_constraintsInvolvedIn)
3481 m_constraintsInvolvedIn->DeleteObject(otherWin);
3482 }
3483
3484 // Reset any constraints that mention this window
3485 void wxWindow::DeleteRelatedConstraints()
3486 {
3487 if (m_constraintsInvolvedIn)
3488 {
3489 wxNode *node = m_constraintsInvolvedIn->First();
3490 while (node)
3491 {
3492 wxWindow *win = (wxWindow *)node->Data();
3493 wxNode *next = node->Next();
3494 wxLayoutConstraints *constr = win->GetConstraints();
3495
3496 // Reset any constraints involving this window
3497 if (constr)
3498 {
3499 constr->left.ResetIfWin((wxWindow *)this);
3500 constr->top.ResetIfWin((wxWindow *)this);
3501 constr->right.ResetIfWin((wxWindow *)this);
3502 constr->bottom.ResetIfWin((wxWindow *)this);
3503 constr->width.ResetIfWin((wxWindow *)this);
3504 constr->height.ResetIfWin((wxWindow *)this);
3505 constr->centreX.ResetIfWin((wxWindow *)this);
3506 constr->centreY.ResetIfWin((wxWindow *)this);
3507 }
3508 delete node;
3509 node = next;
3510 }
3511 delete m_constraintsInvolvedIn;
3512 m_constraintsInvolvedIn = (wxList *) NULL;
3513 }
3514 }
3515
3516 void wxWindow::SetSizer(wxSizer *sizer)
3517 {
3518 m_windowSizer = sizer;
3519 if (sizer)
3520 sizer->SetSizerParent((wxWindow *)this);
3521 }
3522
3523 /*
3524 * New version
3525 */
3526
3527 bool wxWindow::Layout()
3528 {
3529 if (GetConstraints())
3530 {
3531 int w, h;
3532 GetClientSize(&w, &h);
3533 GetConstraints()->width.SetValue(w);
3534 GetConstraints()->height.SetValue(h);
3535 }
3536
3537 // If top level (one sizer), evaluate the sizer's constraints.
3538 if (GetSizer())
3539 {
3540 int noChanges;
3541 GetSizer()->ResetConstraints(); // Mark all constraints as unevaluated
3542 GetSizer()->LayoutPhase1(&noChanges);
3543 GetSizer()->LayoutPhase2(&noChanges);
3544 GetSizer()->SetConstraintSizes(); // Recursively set the real window sizes
3545
3546 return TRUE;
3547 }
3548 else
3549 {
3550 // Otherwise, evaluate child constraints
3551 ResetConstraints(); // Mark all constraints as unevaluated
3552 DoPhase(1); // Just one phase need if no sizers involved
3553 DoPhase(2);
3554 SetConstraintSizes(); // Recursively set the real window sizes
3555 }
3556 return TRUE;
3557 }
3558
3559
3560 // Do a phase of evaluating constraints:
3561 // the default behaviour. wxSizers may do a similar
3562 // thing, but also impose their own 'constraints'
3563 // and order the evaluation differently.
3564 bool wxWindow::LayoutPhase1(int *noChanges)
3565 {
3566 wxLayoutConstraints *constr = GetConstraints();
3567 if (constr)
3568 {
3569 return constr->SatisfyConstraints((wxWindow *)this, noChanges);
3570 }
3571 else
3572 return TRUE;
3573 }
3574
3575 bool wxWindow::LayoutPhase2(int *noChanges)
3576 {
3577 *noChanges = 0;
3578
3579 // Layout children
3580 DoPhase(1);
3581 DoPhase(2);
3582 return TRUE;
3583 }
3584
3585 // Do a phase of evaluating child constraints
3586 bool wxWindow::DoPhase(int phase)
3587 {
3588 int noIterations = 0;
3589 int maxIterations = 500;
3590 int noChanges = 1;
3591 int noFailures = 0;
3592 wxList succeeded;
3593 while ((noChanges > 0) && (noIterations < maxIterations))
3594 {
3595 noChanges = 0;
3596 noFailures = 0;
3597 wxNode *node = m_children.First();
3598 while (node)
3599 {
3600 wxWindow *child = (wxWindow *)node->Data();
3601 if (!child->IsKindOf(CLASSINFO(wxFrame)) && !child->IsKindOf(CLASSINFO(wxDialog)))
3602 {
3603 wxLayoutConstraints *constr = child->GetConstraints();
3604 if (constr)
3605 {
3606 if (succeeded.Member(child))
3607 {
3608 }
3609 else
3610 {
3611 int tempNoChanges = 0;
3612 bool success = ( (phase == 1) ? child->LayoutPhase1(&tempNoChanges) : child->LayoutPhase2(&tempNoChanges) ) ;
3613 noChanges += tempNoChanges;
3614 if (success)
3615 {
3616 succeeded.Append(child);
3617 }
3618 }
3619 }
3620 }
3621 node = node->Next();
3622 }
3623 noIterations ++;
3624 }
3625 return TRUE;
3626 }
3627
3628 void wxWindow::ResetConstraints()
3629 {
3630 wxLayoutConstraints *constr = GetConstraints();
3631 if (constr)
3632 {
3633 constr->left.SetDone(FALSE);
3634 constr->top.SetDone(FALSE);
3635 constr->right.SetDone(FALSE);
3636 constr->bottom.SetDone(FALSE);
3637 constr->width.SetDone(FALSE);
3638 constr->height.SetDone(FALSE);
3639 constr->centreX.SetDone(FALSE);
3640 constr->centreY.SetDone(FALSE);
3641 }
3642 wxNode *node = m_children.First();
3643 while (node)
3644 {
3645 wxWindow *win = (wxWindow *)node->Data();
3646 if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog)))
3647 win->ResetConstraints();
3648 node = node->Next();
3649 }
3650 }
3651
3652 // Need to distinguish between setting the 'fake' size for
3653 // windows and sizers, and setting the real values.
3654 void wxWindow::SetConstraintSizes(bool recurse)
3655 {
3656 wxLayoutConstraints *constr = GetConstraints();
3657 if (constr && constr->left.GetDone() && constr->right.GetDone() &&
3658 constr->width.GetDone() && constr->height.GetDone())
3659 {
3660 int x = constr->left.GetValue();
3661 int y = constr->top.GetValue();
3662 int w = constr->width.GetValue();
3663 int h = constr->height.GetValue();
3664
3665 // If we don't want to resize this window, just move it...
3666 if ((constr->width.GetRelationship() != wxAsIs) ||
3667 (constr->height.GetRelationship() != wxAsIs))
3668 {
3669 // Calls Layout() recursively. AAAGH. How can we stop that.
3670 // Simply take Layout() out of non-top level OnSizes.
3671 SizerSetSize(x, y, w, h);
3672 }
3673 else
3674 {
3675 SizerMove(x, y);
3676 }
3677 }
3678 else if (constr)
3679 {
3680 wxChar *windowClass = this->GetClassInfo()->GetClassName();
3681
3682 wxString winName;
3683 if (GetName() == _T(""))
3684 winName = _T("unnamed");
3685 else
3686 winName = GetName();
3687 wxLogDebug( _T("Constraint(s) not satisfied for window of type %s, name %s:\n"),
3688 (const wxChar *)windowClass,
3689 (const wxChar *)winName);
3690 if (!constr->left.GetDone()) wxLogDebug( _T(" unsatisfied 'left' constraint.\n") );
3691 if (!constr->right.GetDone()) wxLogDebug( _T(" unsatisfied 'right' constraint.\n") );
3692 if (!constr->width.GetDone()) wxLogDebug( _T(" unsatisfied 'width' constraint.\n") );
3693 if (!constr->height.GetDone()) wxLogDebug( _T(" unsatisfied 'height' constraint.\n") );
3694 wxLogDebug( _T("Please check constraints: try adding AsIs() constraints.\n") );
3695 }
3696
3697 if (recurse)
3698 {
3699 wxNode *node = m_children.First();
3700 while (node)
3701 {
3702 wxWindow *win = (wxWindow *)node->Data();
3703 if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog)))
3704 win->SetConstraintSizes();
3705 node = node->Next();
3706 }
3707 }
3708 }
3709
3710 // This assumes that all sizers are 'on' the same
3711 // window, i.e. the parent of this window.
3712 void wxWindow::TransformSizerToActual(int *x, int *y) const
3713 {
3714 if (!m_sizerParent || m_sizerParent->IsKindOf(CLASSINFO(wxDialog)) ||
3715 m_sizerParent->IsKindOf(CLASSINFO(wxFrame)) )
3716 return;
3717
3718 int xp, yp;
3719 m_sizerParent->GetPosition(&xp, &yp);
3720 m_sizerParent->TransformSizerToActual(&xp, &yp);
3721 *x += xp;
3722 *y += yp;
3723 }
3724
3725 void wxWindow::SizerSetSize(int x, int y, int w, int h)
3726 {
3727 int xx = x;
3728 int yy = y;
3729 TransformSizerToActual(&xx, &yy);
3730 SetSize(xx, yy, w, h);
3731 }
3732
3733 void wxWindow::SizerMove(int x, int y)
3734 {
3735 int xx = x;
3736 int yy = y;
3737 TransformSizerToActual(&xx, &yy);
3738 Move(xx, yy);
3739 }
3740
3741 // Only set the size/position of the constraint (if any)
3742 void wxWindow::SetSizeConstraint(int x, int y, int w, int h)
3743 {
3744 wxLayoutConstraints *constr = GetConstraints();
3745 if (constr)
3746 {
3747 if (x != -1)
3748 {
3749 constr->left.SetValue(x);
3750 constr->left.SetDone(TRUE);
3751 }
3752 if (y != -1)
3753 {
3754 constr->top.SetValue(y);
3755 constr->top.SetDone(TRUE);
3756 }
3757 if (w != -1)
3758 {
3759 constr->width.SetValue(w);
3760 constr->width.SetDone(TRUE);
3761 }
3762 if (h != -1)
3763 {
3764 constr->height.SetValue(h);
3765 constr->height.SetDone(TRUE);
3766 }
3767 }
3768 }
3769
3770 void wxWindow::MoveConstraint(int x, int y)
3771 {
3772 wxLayoutConstraints *constr = GetConstraints();
3773 if (constr)
3774 {
3775 if (x != -1)
3776 {
3777 constr->left.SetValue(x);
3778 constr->left.SetDone(TRUE);
3779 }
3780 if (y != -1)
3781 {
3782 constr->top.SetValue(y);
3783 constr->top.SetDone(TRUE);
3784 }
3785 }
3786 }
3787
3788 void wxWindow::GetSizeConstraint(int *w, int *h) const
3789 {
3790 wxLayoutConstraints *constr = GetConstraints();
3791 if (constr)
3792 {
3793 *w = constr->width.GetValue();
3794 *h = constr->height.GetValue();
3795 }
3796 else
3797 GetSize(w, h);
3798 }
3799
3800 void wxWindow::GetClientSizeConstraint(int *w, int *h) const
3801 {
3802 wxLayoutConstraints *constr = GetConstraints();
3803 if (constr)
3804 {
3805 *w = constr->width.GetValue();
3806 *h = constr->height.GetValue();
3807 }
3808 else
3809 GetClientSize(w, h);
3810 }
3811
3812 void wxWindow::GetPositionConstraint(int *x, int *y) const
3813 {
3814 wxLayoutConstraints *constr = GetConstraints();
3815 if (constr)
3816 {
3817 *x = constr->left.GetValue();
3818 *y = constr->top.GetValue();
3819 }
3820 else
3821 GetPosition(x, y);
3822 }
3823