1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "window.h"
16 #define XWarpPointer XWARPPOINTER
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
24 #include "wx/layout.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
29 #if wxUSE_DRAG_AND_DROP
34 #include "wx/tooltip.h"
42 #include "wx/textctrl.h"
46 #include "wx/statusbr.h"
48 #include "wx/settings.h"
52 #include "wx/thread.h"
57 #include "wx/gtk/private.h"
58 #include <gdk/gdkprivate.h>
59 #include <gdk/gdkkeysyms.h>
63 #include <gtk/gtkprivate.h>
65 #include "wx/gtk/win_gtk.h"
68 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
70 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
73 //-----------------------------------------------------------------------------
74 // documentation on internals
75 //-----------------------------------------------------------------------------
78 I have been asked several times about writing some documentation about
79 the GTK port of wxWindows, especially its internal structures. Obviously,
80 you cannot understand wxGTK without knowing a little about the GTK, but
81 some more information about what the wxWindow, which is the base class
82 for all other window classes, does seems required as well.
86 What does wxWindow do? It contains the common interface for the following
87 jobs of its descendants:
89 1) Define the rudimentary behaviour common to all window classes, such as
90 resizing, intercepting user input (so as to make it possible to use these
91 events for special purposes in a derived class), window names etc.
93 2) Provide the possibility to contain and manage children, if the derived
94 class is allowed to contain children, which holds true for those window
95 classes which do not display a native GTK widget. To name them, these
96 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
97 work classes are a special case and are handled a bit differently from
98 the rest. The same holds true for the wxNotebook class.
100 3) Provide the possibility to draw into a client area of a window. This,
101 too, only holds true for classes that do not display a native GTK widget
104 4) Provide the entire mechanism for scrolling widgets. This actual inter-
105 face for this is usually in wxScrolledWindow, but the GTK implementation
108 5) A multitude of helper or extra methods for special purposes, such as
109 Drag'n'Drop, managing validators etc.
111 6) Display a border (sunken, raised, simple or none).
113 Normally one might expect, that one wxWindows window would always correspond
114 to one GTK widget. Under GTK, there is no such allround widget that has all
115 the functionality. Moreover, the GTK defines a client area as a different
116 widget from the actual widget you are handling. Last but not least some
117 special classes (e.g. wxFrame) handle different categories of widgets and
118 still have the possibility to draw something in the client area.
119 It was therefore required to write a special purpose GTK widget, that would
120 represent a client area in the sense of wxWindows capable to do the jobs
121 2), 3) and 4). I have written this class and it resides in win_gtk.c of
124 All windows must have a widget, with which they interact with other under-
125 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
126 thw wxWindow class has a member variable called m_widget which holds a
127 pointer to this widget. When the window class represents a GTK native widget,
128 this is (in most cases) the only GTK widget the class manages. E.g. the
129 wxStatitText class handles only a GtkLabel widget a pointer to which you
130 can find in m_widget (defined in wxWindow)
132 When the class has a client area for drawing into and for containing children
133 it has to handle the client area widget (of the type GtkPizza, defined in
134 win_gtk.c), but there could be any number of widgets, handled by a class
135 The common rule for all windows is only, that the widget that interacts with
136 the rest of GTK must be referenced in m_widget and all other widgets must be
137 children of this widget on the GTK level. The top-most widget, which also
138 represents the client area, must be in the m_wxwindow field and must be of
141 As I said, the window classes that display a GTK native widget only have
142 one widget, so in the case of e.g. the wxButton class m_widget holds a
143 pointer to a GtkButton widget. But windows with client areas (for drawing
144 and children) have a m_widget field that is a pointer to a GtkScrolled-
145 Window and a m_wxwindow field that is pointer to a GtkPizza and this
146 one is (in the GTK sense) a child of the GtkScrolledWindow.
148 If the m_wxwindow field is set, then all input to this widget is inter-
149 cepted and sent to the wxWindows class. If not, all input to the widget
150 that gets pointed to by m_widget gets intercepted and sent to the class.
154 The design of scrolling in wxWindows is markedly different from that offered
155 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
156 clicking on a scrollbar belonging to scrolled window will inevitably move
157 the window. In wxWindows, the scrollbar will only emit an event, send this
158 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
159 which actually moves the window and its subchildren. Note that GtkPizza
160 memorizes how much it has been scrolled but that wxWindows forgets this
161 so that the two coordinates systems have to be kept in synch. This is done
162 in various places using the pizza->xoffset and pizza->yoffset values.
166 Singularily the most broken code in GTK is the code that is supposes to
167 inform subwindows (child windows) about new positions. Very often, duplicate
168 events are sent without changes in size or position, equally often no
169 events are sent at all (All this is due to a bug in the GtkContainer code
170 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
171 GTK's own system and it simply waits for size events for toplevel windows
172 and then iterates down the respective size events to all window. This has
173 the disadvantage, that windows might get size events before the GTK widget
174 actually has the reported size. This doesn't normally pose any problem, but
175 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
176 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
177 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
178 window that is used for OpenGl output really has that size (as reported by
183 If someone at some point of time feels the immense desire to have a look at,
184 change or attempt to optimse the Refresh() logic, this person will need an
185 intimate understanding of what a "draw" and what an "expose" events are and
186 what there are used for, in particular when used in connection with GTK's
187 own windowless widgets. Beware.
191 Cursors, too, have been a constant source of pleasure. The main difficulty
192 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
193 for the parent. To prevent this from doing too much harm, I use idle time
194 to set the cursor over and over again, starting from the toplevel windows
195 and ending with the youngest generation (speaking of parent and child windows).
196 Also don't forget that cursors (like much else) are connected to GdkWindows,
197 not GtkWidgets and that the "window" field of a GtkWidget might very well
198 point to the GdkWindow of the parent widget (-> "window less widget") and
199 that the two obviously have very different meanings.
203 //-----------------------------------------------------------------------------
205 //-----------------------------------------------------------------------------
207 extern wxList wxPendingDelete
;
208 extern bool g_blockEventsOnDrag
;
209 extern bool g_blockEventsOnScroll
;
210 extern wxCursor g_globalCursor
;
212 // mouse capture state: the window which has it and if the mouse is currently
214 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
215 static bool g_captureWindowHasMouse
= FALSE
;
217 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
219 // the last window which had the focus - this is normally never NULL (except
220 // if we never had focus at all) as even when g_focusWindow is NULL it still
221 // keeps its previous value
222 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*)NULL
;
224 // the frame that is currently active (i.e. its child has focus). It is
225 // used to generate wxActivateEvents
226 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*)NULL
;
227 static bool g_activeFrameLostFocus
= FALSE
;
229 // if we detect that the app has got/lost the focus, we set this variable to
230 // either TRUE or FALSE and an activate event will be sent during the next
231 // OnIdle() call and it is reset to -1: this value means that we shouldn't
232 // send any activate events at all
233 static int g_sendActivateEvent
= -1;
235 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
236 the last click here */
237 static guint32 gs_timeLastClick
= 0;
239 extern bool g_mainThreadLocked
;
241 //-----------------------------------------------------------------------------
243 //-----------------------------------------------------------------------------
246 #define DISABLE_STYLE_IF_BROKEN_THEME 1
252 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
254 # define DEBUG_MAIN_THREAD
257 static gint
gtk_debug_focus_in_callback( GtkWidget
*WXUNUSED(widget
),
258 GdkEvent
*WXUNUSED(event
),
259 const wxChar
*WXUNUSED(name
) )
262 static bool s_done = FALSE;
265 wxLog::AddTraceMask("focus");
268 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
274 void debug_focus_in( GtkWidget
* widget
, const wxChar
* name
, const wxChar
*window
)
276 // suppress warnings about gtk_debug_focus_in_callback being unused with
281 tmp
+= wxT(" FROM ");
284 wxChar
*s
= new wxChar
[tmp
.Length()+1];
288 gtk_signal_connect( GTK_OBJECT(widget
), "focus_in_event",
289 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback
), (gpointer
)s
);
294 #define DEBUG_MAIN_THREAD
297 //-----------------------------------------------------------------------------
298 // missing gdk functions
299 //-----------------------------------------------------------------------------
302 gdk_window_warp_pointer (GdkWindow
*window
,
307 GdkWindowPrivate
*priv
;
311 window
= GDK_ROOT_PARENT();
314 if (!GDK_WINDOW_DESTROYED(window
))
316 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
317 None
, /* not source window -> move from anywhere */
318 GDK_WINDOW_XID(window
), /* dest window */
319 0, 0, 0, 0, /* not source window -> move from anywhere */
323 priv
= (GdkWindowPrivate
*) window
;
325 if (!priv
->destroyed
)
327 XWarpPointer (priv
->xdisplay
,
328 None
, /* not source window -> move from anywhere */
329 priv
->xwindow
, /* dest window */
330 0, 0, 0, 0, /* not source window -> move from anywhere */
336 //-----------------------------------------------------------------------------
338 //-----------------------------------------------------------------------------
340 extern void wxapp_install_idle_handler();
341 extern bool g_isIdle
;
343 //-----------------------------------------------------------------------------
344 // local code (see below)
345 //-----------------------------------------------------------------------------
347 // returns the child of win which currently has focus or NULL if not found
349 // Note: can't be static, needed by textctrl.cpp.
350 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
352 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
354 return (wxWindow
*)NULL
;
356 if ( winFocus
== win
)
357 return (wxWindow
*)win
;
359 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
361 node
= node
->GetNext() )
363 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
368 return (wxWindow
*)NULL
;
371 // Returns toplevel grandparent of given window:
372 static wxWindowGTK
* wxGetTopLevelParent(wxWindowGTK
*win
)
374 wxWindowGTK
*p
= win
;
375 while (p
&& !p
->IsTopLevel())
381 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
383 // wxUniversal widgets draw the borders and scrollbars themselves
384 #ifndef __WXUNIVERSAL__
391 if (win
->m_hasScrolling
)
393 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
395 GtkRequisition vscroll_req
;
396 vscroll_req
.width
= 2;
397 vscroll_req
.height
= 2;
398 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
399 (scroll_window
->vscrollbar
, &vscroll_req
);
401 GtkRequisition hscroll_req
;
402 hscroll_req
.width
= 2;
403 hscroll_req
.height
= 2;
404 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
405 (scroll_window
->hscrollbar
, &hscroll_req
);
407 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
409 if (scroll_window
->vscrollbar_visible
)
411 dw
+= vscroll_req
.width
;
412 dw
+= scroll_class
->scrollbar_spacing
;
415 if (scroll_window
->hscrollbar_visible
)
417 dh
+= hscroll_req
.height
;
418 dh
+= scroll_class
->scrollbar_spacing
;
424 if (GTK_WIDGET_NO_WINDOW (widget
))
426 dx
+= widget
->allocation
.x
;
427 dy
+= widget
->allocation
.y
;
430 if (win
->HasFlag(wxRAISED_BORDER
))
432 gtk_draw_shadow( widget
->style
,
437 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
441 if (win
->HasFlag(wxSUNKEN_BORDER
))
443 gtk_draw_shadow( widget
->style
,
448 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
452 if (win
->HasFlag(wxSIMPLE_BORDER
))
455 gc
= gdk_gc_new( widget
->window
);
456 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
457 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
459 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
463 #endif // __WXUNIVERSAL__
466 //-----------------------------------------------------------------------------
467 // "expose_event" of m_widget
468 //-----------------------------------------------------------------------------
470 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
472 if (gdk_event
->count
> 0) return FALSE
;
474 draw_frame( widget
, win
);
479 //-----------------------------------------------------------------------------
480 // "draw" of m_widget
481 //-----------------------------------------------------------------------------
483 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
485 draw_frame( widget
, win
);
488 //-----------------------------------------------------------------------------
489 // key code mapping routines
490 //-----------------------------------------------------------------------------
492 static long map_to_unmodified_wx_keysym( GdkEventKey
*event
)
494 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
495 // but only event->keyval which is quite useless to us, so remember
496 // the last character from GDK_KEY_PRESS and resue it as last resort
498 // NB: should be MT-neutral as always called from main thread only
503 } s_lastKeyPress
= { 0, 0 };
505 KeySym keysym
= event
->keyval
;
511 case GDK_Shift_R
: key_code
= WXK_SHIFT
; break;
513 case GDK_Control_R
: key_code
= WXK_CONTROL
; break;
519 case GDK_Super_R
: key_code
= WXK_ALT
; break;
520 case GDK_Menu
: key_code
= WXK_MENU
; break;
521 case GDK_Help
: key_code
= WXK_HELP
; break;
522 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
523 case GDK_ISO_Left_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;
549 case GDK_KP_0
: key_code
= WXK_NUMPAD0
; break;
550 case GDK_KP_1
: key_code
= WXK_NUMPAD1
; break;
551 case GDK_KP_2
: key_code
= WXK_NUMPAD2
; break;
552 case GDK_KP_3
: key_code
= WXK_NUMPAD3
; break;
553 case GDK_KP_4
: key_code
= WXK_NUMPAD4
; break;
554 case GDK_KP_5
: key_code
= WXK_NUMPAD5
; break;
555 case GDK_KP_6
: key_code
= WXK_NUMPAD6
; break;
556 case GDK_KP_7
: key_code
= WXK_NUMPAD7
; break;
557 case GDK_KP_8
: key_code
= WXK_NUMPAD8
; break;
558 case GDK_KP_9
: key_code
= WXK_NUMPAD9
; break;
559 case GDK_KP_Space
: key_code
= WXK_NUMPAD_SPACE
; break;
560 case GDK_KP_Tab
: key_code
= WXK_NUMPAD_TAB
; break;
561 case GDK_KP_Enter
: key_code
= WXK_NUMPAD_ENTER
; break;
562 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
563 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
564 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
565 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
566 case GDK_KP_Home
: key_code
= WXK_NUMPAD_HOME
; break;
567 case GDK_KP_Left
: key_code
= WXK_NUMPAD_LEFT
; break;
568 case GDK_KP_Up
: key_code
= WXK_NUMPAD_UP
; break;
569 case GDK_KP_Right
: key_code
= WXK_NUMPAD_RIGHT
; break;
570 case GDK_KP_Down
: key_code
= WXK_NUMPAD_DOWN
; break;
571 case GDK_KP_Prior
: key_code
= WXK_NUMPAD_PRIOR
; break;
572 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
573 case GDK_KP_Next
: key_code
= WXK_NUMPAD_NEXT
; break;
574 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
575 case GDK_KP_End
: key_code
= WXK_NUMPAD_END
; break;
576 case GDK_KP_Begin
: key_code
= WXK_NUMPAD_BEGIN
; break;
577 case GDK_KP_Insert
: key_code
= WXK_NUMPAD_INSERT
; break;
578 case GDK_KP_Delete
: key_code
= WXK_NUMPAD_DELETE
; break;
579 case GDK_KP_Equal
: key_code
= WXK_NUMPAD_EQUAL
; break;
580 case GDK_KP_Multiply
: key_code
= WXK_NUMPAD_MULTIPLY
; break;
581 case GDK_KP_Add
: key_code
= WXK_NUMPAD_ADD
; break;
582 case GDK_KP_Separator
: key_code
= WXK_NUMPAD_SEPARATOR
; break;
583 case GDK_KP_Subtract
: key_code
= WXK_NUMPAD_SUBTRACT
; break;
584 case GDK_KP_Decimal
: key_code
= WXK_NUMPAD_DECIMAL
; break;
585 case GDK_KP_Divide
: key_code
= WXK_NUMPAD_DIVIDE
; break;
587 case GDK_F1
: key_code
= WXK_F1
; break;
588 case GDK_F2
: key_code
= WXK_F2
; break;
589 case GDK_F3
: key_code
= WXK_F3
; break;
590 case GDK_F4
: key_code
= WXK_F4
; break;
591 case GDK_F5
: key_code
= WXK_F5
; break;
592 case GDK_F6
: key_code
= WXK_F6
; break;
593 case GDK_F7
: key_code
= WXK_F7
; break;
594 case GDK_F8
: key_code
= WXK_F8
; break;
595 case GDK_F9
: key_code
= WXK_F9
; break;
596 case GDK_F10
: key_code
= WXK_F10
; break;
597 case GDK_F11
: key_code
= WXK_F11
; break;
598 case GDK_F12
: key_code
= WXK_F12
; break;
601 // do we have the translation?
602 if ( event
->length
== 1 )
604 keysym
= (KeySym
)event
->string
[0];
606 else if ( (keysym
& 0xFF) != keysym
)
608 // non ASCII key, what to do?
610 if ( event
->type
== GDK_KEY_RELEASE
)
612 // reuse the one from the last keypress if any
613 if ( keysym
== s_lastKeyPress
.keysym
)
615 key_code
= s_lastKeyPress
.keycode
;
622 // ignore this one, we don't know it
625 //else: ASCII key, ok
627 guint upper
= gdk_keyval_to_upper( (guint
)keysym
);
628 key_code
= upper
? upper
: keysym
;
630 if ( event
->type
== GDK_KEY_PRESS
)
632 // remember it to be reused below later
633 s_lastKeyPress
.keysym
= keysym
;
634 s_lastKeyPress
.keycode
= key_code
;
642 static long map_to_wx_keysym( GdkEventKey
*event
)
644 KeySym keysym
= event
->keyval
;
649 case GDK_Menu
: key_code
= WXK_MENU
; break;
650 case GDK_Help
: key_code
= WXK_HELP
; break;
651 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
652 case GDK_ISO_Left_Tab
:
653 case GDK_Tab
: key_code
= WXK_TAB
; break;
654 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
655 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
656 case GDK_Return
: key_code
= WXK_RETURN
; break;
657 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
658 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
659 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
660 case GDK_Delete
: key_code
= WXK_DELETE
; break;
661 case GDK_Home
: key_code
= WXK_HOME
; break;
662 case GDK_Left
: key_code
= WXK_LEFT
; break;
663 case GDK_Up
: key_code
= WXK_UP
; break;
664 case GDK_Right
: key_code
= WXK_RIGHT
; break;
665 case GDK_Down
: key_code
= WXK_DOWN
; break;
666 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
667 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
668 case GDK_Next
: key_code
= WXK_NEXT
; break;
669 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
670 case GDK_End
: key_code
= WXK_END
; break;
671 case GDK_Begin
: key_code
= WXK_HOME
; break;
672 case GDK_Select
: key_code
= WXK_SELECT
; break;
673 case GDK_Print
: key_code
= WXK_PRINT
; break;
674 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
675 case GDK_Insert
: key_code
= WXK_INSERT
; break;
676 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
678 case GDK_KP_0
: key_code
= '0'; break;
679 case GDK_KP_1
: key_code
= '1'; break;
680 case GDK_KP_2
: key_code
= '2'; break;
681 case GDK_KP_3
: key_code
= '3'; break;
682 case GDK_KP_4
: key_code
= '4'; break;
683 case GDK_KP_5
: key_code
= '5'; break;
684 case GDK_KP_6
: key_code
= '6'; break;
685 case GDK_KP_7
: key_code
= '7'; break;
686 case GDK_KP_8
: key_code
= '8'; break;
687 case GDK_KP_9
: key_code
= '9'; break;
688 case GDK_KP_Space
: key_code
= ' '; break;
689 case GDK_KP_Tab
: key_code
= WXK_TAB
; break; /* or '\t' ??? */
690 case GDK_KP_Enter
: key_code
= WXK_RETURN
; break; /* or '\r' ??? */
691 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
692 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
693 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
694 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
695 case GDK_KP_Home
: key_code
= WXK_HOME
; break;
696 case GDK_KP_Left
: key_code
= WXK_LEFT
; break;
697 case GDK_KP_Up
: key_code
= WXK_UP
; break;
698 case GDK_KP_Right
: key_code
= WXK_RIGHT
; break;
699 case GDK_KP_Down
: key_code
= WXK_DOWN
; break;
700 case GDK_KP_Prior
: key_code
= WXK_PRIOR
; break;
701 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
702 case GDK_KP_Next
: key_code
= WXK_NEXT
; break;
703 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
704 case GDK_KP_End
: key_code
= WXK_END
; break;
705 case GDK_KP_Begin
: key_code
= WXK_HOME
; break;
706 case GDK_KP_Insert
: key_code
= WXK_INSERT
; break;
707 case GDK_KP_Delete
: key_code
= WXK_DELETE
; break;
708 case GDK_KP_Equal
: key_code
= '='; break;
709 case GDK_KP_Multiply
: key_code
= '*'; break;
710 case GDK_KP_Add
: key_code
= '+'; break;
711 case GDK_KP_Separator
: key_code
= ','; break;
712 case GDK_KP_Subtract
: key_code
= '-'; break;
713 case GDK_KP_Decimal
: key_code
= '.'; break;
714 case GDK_KP_Divide
: key_code
= '/'; break;
716 case GDK_F1
: key_code
= WXK_F1
; break;
717 case GDK_F2
: key_code
= WXK_F2
; break;
718 case GDK_F3
: key_code
= WXK_F3
; break;
719 case GDK_F4
: key_code
= WXK_F4
; break;
720 case GDK_F5
: key_code
= WXK_F5
; break;
721 case GDK_F6
: key_code
= WXK_F6
; break;
722 case GDK_F7
: key_code
= WXK_F7
; break;
723 case GDK_F8
: key_code
= WXK_F8
; break;
724 case GDK_F9
: key_code
= WXK_F9
; break;
725 case GDK_F10
: key_code
= WXK_F10
; break;
726 case GDK_F11
: key_code
= WXK_F11
; break;
727 case GDK_F12
: key_code
= WXK_F12
; break;
729 if (event
->length
== 1)
731 key_code
= (unsigned char)*event
->string
;
733 else if ((keysym
& 0xFF) == keysym
)
735 key_code
= (guint
)keysym
;
742 //-----------------------------------------------------------------------------
743 // "size_request" of m_widget
744 //-----------------------------------------------------------------------------
746 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
749 win
->GetSize( &w
, &h
);
753 requisition
->height
= h
;
754 requisition
->width
= w
;
757 //-----------------------------------------------------------------------------
758 // "expose_event" of m_wxwindow
759 //-----------------------------------------------------------------------------
761 static int gtk_window_expose_callback( GtkWidget
*widget
,
762 GdkEventExpose
*gdk_event
,
768 wxapp_install_idle_handler();
771 if (win->GetName() == wxT("panel"))
773 wxPrintf( wxT("OnExpose from ") );
774 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
775 wxPrintf( win->GetClassInfo()->GetClassName() );
776 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
777 (int)gdk_event->area.y,
778 (int)gdk_event->area.width,
779 (int)gdk_event->area.height );
783 #ifndef __WXUNIVERSAL__
784 GtkPizza
*pizza
= GTK_PIZZA (widget
);
786 if (win
->GetThemeEnabled())
788 wxWindow
*parent
= win
->GetParent();
789 while (parent
&& !parent
->IsTopLevel())
790 parent
= parent
->GetParent();
794 gtk_paint_flat_box (parent
->m_widget
->style
,
805 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
807 gdk_event
->area
.width
,
808 gdk_event
->area
.height
);
810 // Actual redrawing takes place in idle time.
816 //-----------------------------------------------------------------------------
817 // "event" of m_wxwindow
818 //-----------------------------------------------------------------------------
820 // GTK thinks it is clever and filters out a certain amount of "unneeded"
821 // expose events. We need them, of course, so we override the main event
822 // procedure in GtkWidget by giving our own handler for all system events.
823 // There, we look for expose events ourselves whereas all other events are
826 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
827 GdkEventExpose
*event
,
830 if (event
->type
== GDK_EXPOSE
)
832 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
839 //-----------------------------------------------------------------------------
840 // "draw" of m_wxwindow
841 //-----------------------------------------------------------------------------
843 // This callback is a complete replacement of the gtk_pizza_draw() function,
846 static void gtk_window_draw_callback( GtkWidget
*widget
,
853 wxapp_install_idle_handler();
855 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
856 // there are no child windows.
857 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
858 (win
->GetChildren().GetCount() == 0))
864 if (win->GetName() == wxT("panel"))
866 wxPrintf( wxT("OnDraw from ") );
867 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
868 wxPrintf( win->GetClassInfo()->GetClassName() );
869 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
876 #ifndef __WXUNIVERSAL__
877 GtkPizza
*pizza
= GTK_PIZZA (widget
);
879 if (win
->GetThemeEnabled())
881 wxWindow
*parent
= win
->GetParent();
882 while (parent
&& !parent
->IsTopLevel())
883 parent
= parent
->GetParent();
887 gtk_paint_flat_box (parent
->m_widget
->style
,
898 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
899 (pizza
->clear_on_draw
))
901 gdk_window_clear_area( pizza
->bin_window
,
902 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
906 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
908 // Actual redrawing takes place in idle time.
912 #ifndef __WXUNIVERSAL__
913 // Redraw child widgets
914 GList
*children
= pizza
->children
;
917 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
918 children
= children
->next
;
920 GdkRectangle child_area
;
921 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
923 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
929 //-----------------------------------------------------------------------------
930 // "key_press_event" from any window
931 //-----------------------------------------------------------------------------
933 // turn on to see the key event codes on the console
934 #undef DEBUG_KEY_EVENTS
936 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
937 GdkEventKey
*gdk_event
,
943 wxapp_install_idle_handler();
945 if (!win
->m_hasVMT
) return FALSE
;
946 if (g_blockEventsOnDrag
) return FALSE
;
951 GdkModifierType state
;
952 if (gdk_event
->window
)
953 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
957 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
959 #ifdef DEBUG_KEY_EVENTS
960 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
961 #endif // DEBUG_KEY_EVENTS
963 /* sending unknown key events doesn't really make sense */
967 wxKeyEvent
event( wxEVT_KEY_DOWN
);
968 event
.SetTimestamp( gdk_event
->time
);
969 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
970 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
971 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
972 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
973 event
.m_keyCode
= key_code
;
974 event
.m_scanCode
= gdk_event
->keyval
;
977 event
.SetEventObject( win
);
978 ret
= win
->GetEventHandler()->ProcessEvent( event
);
983 wxWindowGTK
*ancestor
= win
;
986 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
989 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
990 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
993 if (ancestor
->IsTopLevel())
995 ancestor
= ancestor
->GetParent();
998 #endif // wxUSE_ACCEL
1000 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1001 will only be sent if it is not in an accelerator table. */
1004 key_code
= map_to_wx_keysym( gdk_event
);
1008 #ifdef DEBUG_KEY_EVENTS
1009 wxPrintf(_T("Char event: %ld\n"), key_code
);
1010 #endif // DEBUG_KEY_EVENTS
1012 // reuse the ame event object, just change its type and use the
1013 // translated keycode instead of the raw one
1014 event
.SetEventType(wxEVT_CHAR
);
1015 event
.m_keyCode
= key_code
;
1017 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1021 /* win is a control: tab can be propagated up */
1023 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1024 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1025 // have this style, yet choose not to process this particular TAB in which
1026 // case TAB must still work as a navigational character
1028 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1030 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1032 wxNavigationKeyEvent new_event
;
1033 new_event
.SetEventObject( win
->GetParent() );
1034 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1035 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1036 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1037 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1038 new_event
.SetCurrentFocus( win
);
1039 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1042 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1044 (gdk_event
->keyval
== GDK_Escape
) )
1046 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1047 new_event
.SetEventObject( win
);
1048 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1052 #if 0 // (GTK_MINOR_VERSION > 0)
1053 /* Pressing F10 will activate the menu bar of the top frame. */
1055 (gdk_event
->keyval
== GDK_F10
) )
1057 wxWindowGTK
*ancestor
= win
;
1060 if (wxIsKindOf(ancestor
,wxFrame
))
1062 wxFrame
*frame
= (wxFrame
*) ancestor
;
1063 wxMenuBar
*menubar
= frame
->GetMenuBar();
1066 wxNode
*node
= menubar
->GetMenus().First();
1069 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1070 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1076 ancestor
= ancestor
->GetParent();
1083 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1090 //-----------------------------------------------------------------------------
1091 // "key_release_event" from any window
1092 //-----------------------------------------------------------------------------
1094 static gint
gtk_window_key_release_callback( GtkWidget
*widget
, GdkEventKey
*gdk_event
, wxWindowGTK
*win
)
1099 wxapp_install_idle_handler();
1101 if (!win
->m_hasVMT
) return FALSE
;
1102 if (g_blockEventsOnDrag
) return FALSE
;
1104 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
1106 #ifdef DEBUG_KEY_EVENTS
1107 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
1108 #endif // DEBUG_KEY_EVENTS
1110 /* sending unknown key events doesn't really make sense */
1111 if (key_code
== 0) return FALSE
;
1115 GdkModifierType state
;
1116 if (gdk_event
->window
)
1117 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1119 wxKeyEvent
event( wxEVT_KEY_UP
);
1120 event
.SetTimestamp( gdk_event
->time
);
1121 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1122 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1123 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1124 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1125 event
.m_keyCode
= key_code
;
1126 event
.m_scanCode
= gdk_event
->keyval
;
1129 event
.SetEventObject( win
);
1131 if (win
->GetEventHandler()->ProcessEvent( event
))
1133 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1140 // ============================================================================
1142 // ============================================================================
1144 // init wxMouseEvent with the info from gdk_event
1145 #define InitMouseEvent(win, event, gdk_event) \
1147 event.SetTimestamp( gdk_event->time ); \
1148 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1149 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1150 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1151 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1152 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1153 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1154 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1156 wxPoint pt = win->GetClientAreaOrigin(); \
1157 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1158 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1161 // ----------------------------------------------------------------------------
1162 // mouse event processing helper
1163 // ----------------------------------------------------------------------------
1165 static void AdjustEventButtonState(wxMouseEvent
& event
)
1167 // GDK reports the old state of the button for a button press event, but
1168 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1169 // for a LEFT_DOWN event, not FALSE, so we will invert
1170 // left/right/middleDown for the corresponding click events
1172 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1173 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1174 (event
.GetEventType() == wxEVT_LEFT_UP
))
1176 event
.m_leftDown
= !event
.m_leftDown
;
1180 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1181 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1182 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1184 event
.m_middleDown
= !event
.m_middleDown
;
1188 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1189 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1190 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1192 event
.m_rightDown
= !event
.m_rightDown
;
1197 //-----------------------------------------------------------------------------
1198 // "button_press_event"
1199 //-----------------------------------------------------------------------------
1201 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1206 wxapp_install_idle_handler();
1209 wxPrintf( wxT("1) OnButtonPress from ") );
1210 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1211 wxPrintf( win->GetClassInfo()->GetClassName() );
1212 wxPrintf( wxT(".\n") );
1214 if (!win
->m_hasVMT
) return FALSE
;
1215 if (g_blockEventsOnDrag
) return TRUE
;
1216 if (g_blockEventsOnScroll
) return TRUE
;
1218 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1220 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1222 gtk_widget_grab_focus( win
->m_wxwindow
);
1224 wxPrintf( wxT("GrabFocus from ") );
1225 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1226 wxPrintf( win->GetClassInfo()->GetClassName() );
1227 wxPrintf( wxT(".\n") );
1231 wxEventType event_type
= wxEVT_NULL
;
1233 if (gdk_event
->button
== 1)
1235 switch (gdk_event
->type
)
1237 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1238 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1242 else if (gdk_event
->button
== 2)
1244 switch (gdk_event
->type
)
1246 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1247 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1251 else if (gdk_event
->button
== 3)
1253 switch (gdk_event
->type
)
1255 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1256 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1261 if ( event_type
== wxEVT_NULL
)
1263 // unknown mouse button or click type
1267 wxMouseEvent
event( event_type
);
1268 InitMouseEvent( win
, event
, gdk_event
);
1270 AdjustEventButtonState(event
);
1272 // wxListBox actually get mouse events from the item
1274 if (win
->m_isListBox
)
1276 event
.m_x
+= widget
->allocation
.x
;
1277 event
.m_y
+= widget
->allocation
.y
;
1280 // Some control don't have their own X window and thus cannot get
1283 if (!g_captureWindow
)
1285 wxCoord x
= event
.m_x
;
1286 wxCoord y
= event
.m_y
;
1287 if (win
->m_wxwindow
)
1289 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1290 x
+= pizza
->xoffset
;
1291 y
+= pizza
->yoffset
;
1294 wxNode
*node
= win
->GetChildren().First();
1297 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1299 node
= node
->Next();
1300 if (!child
->IsShown())
1303 if (child
->m_isStaticBox
)
1305 // wxStaticBox is transparent in the box itself
1306 int xx1
= child
->m_x
;
1307 int yy1
= child
->m_y
;
1308 int xx2
= child
->m_x
+ child
->m_width
;
1309 int yy2
= child
->m_x
+ child
->m_height
;
1312 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1314 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1316 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1318 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1321 event
.m_x
-= child
->m_x
;
1322 event
.m_y
-= child
->m_y
;
1329 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1330 (child
->m_x
<= x
) &&
1331 (child
->m_y
<= y
) &&
1332 (child
->m_x
+child
->m_width
>= x
) &&
1333 (child
->m_y
+child
->m_height
>= y
))
1336 event
.m_x
-= child
->m_x
;
1337 event
.m_y
-= child
->m_y
;
1344 event
.SetEventObject( win
);
1346 gs_timeLastClick
= gdk_event
->time
;
1349 wxPrintf( wxT("2) OnButtonPress from ") );
1350 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1351 wxPrintf( win->GetClassInfo()->GetClassName() );
1352 wxPrintf( wxT(".\n") );
1355 if (win
->GetEventHandler()->ProcessEvent( event
))
1357 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1364 //-----------------------------------------------------------------------------
1365 // "button_release_event"
1366 //-----------------------------------------------------------------------------
1368 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1373 wxapp_install_idle_handler();
1375 if (!win
->m_hasVMT
) return FALSE
;
1376 if (g_blockEventsOnDrag
) return FALSE
;
1377 if (g_blockEventsOnScroll
) return FALSE
;
1379 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1382 printf( "OnButtonRelease from " );
1383 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1384 printf( win->GetClassInfo()->GetClassName() );
1388 wxEventType event_type
= wxEVT_NULL
;
1390 switch (gdk_event
->button
)
1392 case 1: event_type
= wxEVT_LEFT_UP
; break;
1393 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1394 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1395 default: return FALSE
;
1398 wxMouseEvent
event( event_type
);
1399 InitMouseEvent( win
, event
, gdk_event
);
1401 AdjustEventButtonState(event
);
1403 // wxListBox actually get mouse events from the item
1405 if (win
->m_isListBox
)
1407 event
.m_x
+= widget
->allocation
.x
;
1408 event
.m_y
+= widget
->allocation
.y
;
1411 // Some control don't have their own X window and thus cannot get
1414 if (!g_captureWindow
)
1416 wxCoord x
= event
.m_x
;
1417 wxCoord y
= event
.m_y
;
1418 if (win
->m_wxwindow
)
1420 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1421 x
+= pizza
->xoffset
;
1422 y
+= pizza
->yoffset
;
1425 wxNode
*node
= win
->GetChildren().First();
1428 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1430 node
= node
->Next();
1431 if (!child
->IsShown())
1434 if (child
->m_isStaticBox
)
1436 // wxStaticBox is transparent in the box itself
1437 int xx1
= child
->m_x
;
1438 int yy1
= child
->m_y
;
1439 int xx2
= child
->m_x
+ child
->m_width
;
1440 int yy2
= child
->m_x
+ child
->m_height
;
1443 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1445 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1447 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1449 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1452 event
.m_x
-= child
->m_x
;
1453 event
.m_y
-= child
->m_y
;
1460 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1461 (child
->m_x
<= x
) &&
1462 (child
->m_y
<= y
) &&
1463 (child
->m_x
+child
->m_width
>= x
) &&
1464 (child
->m_y
+child
->m_height
>= y
))
1467 event
.m_x
-= child
->m_x
;
1468 event
.m_y
-= child
->m_y
;
1475 event
.SetEventObject( win
);
1477 if (win
->GetEventHandler()->ProcessEvent( event
))
1479 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1486 //-----------------------------------------------------------------------------
1487 // "motion_notify_event"
1488 //-----------------------------------------------------------------------------
1490 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1491 GdkEventMotion
*gdk_event
,
1497 wxapp_install_idle_handler();
1499 if (!win
->m_hasVMT
) return FALSE
;
1500 if (g_blockEventsOnDrag
) return FALSE
;
1501 if (g_blockEventsOnScroll
) return FALSE
;
1503 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1505 if (gdk_event
->is_hint
)
1509 GdkModifierType state
;
1510 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1516 printf( "OnMotion from " );
1517 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1518 printf( win->GetClassInfo()->GetClassName() );
1522 wxMouseEvent
event( wxEVT_MOTION
);
1523 InitMouseEvent(win
, event
, gdk_event
);
1525 if ( g_captureWindow
)
1527 // synthetize a mouse enter or leave event if needed
1528 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1529 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1530 if ( hasMouse
!= g_captureWindowHasMouse
)
1532 // the mouse changed window
1533 g_captureWindowHasMouse
= hasMouse
;
1535 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1536 : wxEVT_LEAVE_WINDOW
);
1537 InitMouseEvent(win
, event
, gdk_event
);
1538 event
.SetEventObject(win
);
1539 win
->GetEventHandler()->ProcessEvent(event
);
1544 // Some control don't have their own X window and thus cannot get
1547 wxCoord x
= event
.m_x
;
1548 wxCoord y
= event
.m_y
;
1549 if (win
->m_wxwindow
)
1551 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1552 x
+= pizza
->xoffset
;
1553 y
+= pizza
->yoffset
;
1556 wxNode
*node
= win
->GetChildren().First();
1559 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1561 node
= node
->Next();
1562 if (!child
->IsShown())
1565 if (child
->m_isStaticBox
)
1567 // wxStaticBox is transparent in the box itself
1568 int xx1
= child
->m_x
;
1569 int yy1
= child
->m_y
;
1570 int xx2
= child
->m_x
+ child
->m_width
;
1571 int yy2
= child
->m_x
+ child
->m_height
;
1574 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1576 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1578 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1580 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1583 event
.m_x
-= child
->m_x
;
1584 event
.m_y
-= child
->m_y
;
1591 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1592 (child
->m_x
<= x
) &&
1593 (child
->m_y
<= y
) &&
1594 (child
->m_x
+child
->m_width
>= x
) &&
1595 (child
->m_y
+child
->m_height
>= y
))
1598 event
.m_x
-= child
->m_x
;
1599 event
.m_y
-= child
->m_y
;
1606 event
.SetEventObject( win
);
1608 if (win
->GetEventHandler()->ProcessEvent( event
))
1610 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1617 //-----------------------------------------------------------------------------
1619 //-----------------------------------------------------------------------------
1621 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1622 GdkEvent
*WXUNUSED(event
),
1628 wxapp_install_idle_handler();
1630 if (!win
->m_hasVMT
) return FALSE
;
1631 if (g_blockEventsOnDrag
) return FALSE
;
1633 switch ( g_sendActivateEvent
)
1636 // we've got focus from outside, synthetize wxActivateEvent
1637 g_sendActivateEvent
= 1;
1641 // another our window just lost focus, it was already ours before
1642 // - don't send any wxActivateEvent
1643 g_sendActivateEvent
= -1;
1648 g_focusWindow
= win
;
1651 wxLogDebug( wxT("OnSetFocus from %s\n"), win
->GetName().c_str() );
1654 // notify the parent keeping track of focus for the kbd navigation
1655 // purposes that we got it
1656 wxChildFocusEvent
eventFocus(win
);
1657 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1661 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1665 // caret needs to be informed about focus change
1666 wxCaret
*caret
= win
->GetCaret();
1669 caret
->OnSetFocus();
1671 #endif // wxUSE_CARET
1673 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1674 if ( active
!= g_activeFrame
)
1676 if ( g_activeFrame
)
1678 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1679 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1680 event
.SetEventObject(g_activeFrame
);
1681 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1684 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1685 g_activeFrame
= active
;
1686 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1687 event
.SetEventObject(g_activeFrame
);
1688 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1690 g_activeFrameLostFocus
= FALSE
;
1693 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1694 event
.SetEventObject( win
);
1696 if (win
->GetEventHandler()->ProcessEvent( event
))
1698 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1706 //-----------------------------------------------------------------------------
1707 // "focus_out_event"
1708 //-----------------------------------------------------------------------------
1710 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1715 wxapp_install_idle_handler();
1717 if (!win
->m_hasVMT
) return FALSE
;
1718 if (g_blockEventsOnDrag
) return FALSE
;
1721 wxLogDebug( wxT("OnKillFocus from %s"), win
->GetName().c_str() );
1724 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1726 // VZ: commenting this out because it does happen (although not easy
1727 // to reproduce, I only see it when using wxMiniFrame and not
1728 // always) and makes using Mahogany quite annoying
1730 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1731 wxT("unfocusing window that hasn't gained focus properly") )
1734 g_activeFrameLostFocus
= TRUE
;
1737 // if the focus goes out of our app alltogether, OnIdle() will send
1738 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1739 // g_sendActivateEvent to -1
1740 g_sendActivateEvent
= 0;
1742 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1746 g_focusWindow
= (wxWindowGTK
*)NULL
;
1754 // caret needs to be informed about focus change
1755 wxCaret
*caret
= win
->GetCaret();
1758 caret
->OnKillFocus();
1760 #endif // wxUSE_CARET
1762 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1763 event
.SetEventObject( win
);
1765 if (win
->GetEventHandler()->ProcessEvent( event
))
1767 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1774 //-----------------------------------------------------------------------------
1775 // "enter_notify_event"
1776 //-----------------------------------------------------------------------------
1778 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1783 wxapp_install_idle_handler();
1785 if (!win
->m_hasVMT
) return FALSE
;
1786 if (g_blockEventsOnDrag
) return FALSE
;
1788 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1790 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1791 event
.SetTimestamp( gdk_event
->time
);
1792 event
.SetEventObject( win
);
1796 GdkModifierType state
= (GdkModifierType
)0;
1798 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1800 InitMouseEvent(win
, event
, gdk_event
);
1801 wxPoint pt
= win
->GetClientAreaOrigin();
1802 event
.m_x
= x
+ pt
.x
;
1803 event
.m_y
= y
+ pt
.y
;
1805 if (win
->GetEventHandler()->ProcessEvent( event
))
1807 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1814 //-----------------------------------------------------------------------------
1815 // "leave_notify_event"
1816 //-----------------------------------------------------------------------------
1818 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1823 wxapp_install_idle_handler();
1825 if (!win
->m_hasVMT
) return FALSE
;
1826 if (g_blockEventsOnDrag
) return FALSE
;
1828 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1830 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1831 event
.SetTimestamp( gdk_event
->time
);
1832 event
.SetEventObject( win
);
1836 GdkModifierType state
= (GdkModifierType
)0;
1838 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1840 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
);
1841 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
);
1842 event
.m_altDown
= (state
& GDK_MOD1_MASK
);
1843 event
.m_metaDown
= (state
& GDK_MOD2_MASK
);
1844 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
);
1845 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
);
1846 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
);
1848 wxPoint pt
= win
->GetClientAreaOrigin();
1849 event
.m_x
= x
+ pt
.x
;
1850 event
.m_y
= y
+ pt
.y
;
1852 if (win
->GetEventHandler()->ProcessEvent( event
))
1854 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1861 //-----------------------------------------------------------------------------
1862 // "value_changed" from m_vAdjust
1863 //-----------------------------------------------------------------------------
1865 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1872 wxapp_install_idle_handler();
1874 if (g_blockEventsOnDrag
) return;
1876 if (!win
->m_hasVMT
) return;
1878 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1879 if (fabs(diff
) < 0.2) return;
1881 win
->m_oldVerticalPos
= adjust
->value
;
1883 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1885 int value
= (int)(adjust
->value
+0.5);
1887 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1888 event
.SetEventObject( win
);
1889 win
->GetEventHandler()->ProcessEvent( event
);
1892 //-----------------------------------------------------------------------------
1893 // "value_changed" from m_hAdjust
1894 //-----------------------------------------------------------------------------
1896 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1903 wxapp_install_idle_handler();
1905 if (g_blockEventsOnDrag
) return;
1906 if (!win
->m_hasVMT
) return;
1908 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1909 if (fabs(diff
) < 0.2) return;
1911 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1913 win
->m_oldHorizontalPos
= adjust
->value
;
1915 int value
= (int)(adjust
->value
+0.5);
1917 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1918 event
.SetEventObject( win
);
1919 win
->GetEventHandler()->ProcessEvent( event
);
1922 //-----------------------------------------------------------------------------
1923 // "button_press_event" from scrollbar
1924 //-----------------------------------------------------------------------------
1926 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1927 GdkEventButton
*gdk_event
,
1933 wxapp_install_idle_handler();
1936 g_blockEventsOnScroll
= TRUE
;
1938 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1940 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1946 //-----------------------------------------------------------------------------
1947 // "button_release_event" from scrollbar
1948 //-----------------------------------------------------------------------------
1950 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1951 GdkEventButton
*WXUNUSED(gdk_event
),
1956 // don't test here as we can release the mouse while being over
1957 // a different window than the slider
1959 // if (gdk_event->window != widget->slider) return FALSE;
1961 g_blockEventsOnScroll
= FALSE
;
1963 if (win
->m_isScrolling
)
1965 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1969 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1970 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1972 value
= (int)(win
->m_hAdjust
->value
+0.5);
1975 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
1977 value
= (int)(win
->m_vAdjust
->value
+0.5);
1981 wxScrollWinEvent
event( command
, value
, dir
);
1982 event
.SetEventObject( win
);
1983 win
->GetEventHandler()->ProcessEvent( event
);
1986 win
->m_isScrolling
= FALSE
;
1991 // ----------------------------------------------------------------------------
1992 // this wxWindowBase function is implemented here (in platform-specific file)
1993 // because it is static and so couldn't be made virtual
1994 // ----------------------------------------------------------------------------
1996 wxWindow
*wxWindowBase::FindFocus()
1998 // the cast is necessary when we compile in wxUniversal mode
1999 return (wxWindow
*)g_focusWindow
;
2002 //-----------------------------------------------------------------------------
2003 // "realize" from m_widget
2004 //-----------------------------------------------------------------------------
2006 /* We cannot set colours and fonts before the widget has
2007 been realized, so we do this directly after realization. */
2010 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2015 wxapp_install_idle_handler();
2017 if (win
->m_delayedBackgroundColour
)
2018 win
->SetBackgroundColour( win
->GetBackgroundColour() );
2020 if (win
->m_delayedForegroundColour
)
2021 win
->SetForegroundColour( win
->GetForegroundColour() );
2023 wxWindowCreateEvent
event( win
);
2024 event
.SetEventObject( win
);
2025 win
->GetEventHandler()->ProcessEvent( event
);
2030 //-----------------------------------------------------------------------------
2032 //-----------------------------------------------------------------------------
2035 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2036 GtkAllocation
*WXUNUSED(alloc
),
2040 wxapp_install_idle_handler();
2042 if (!win
->m_hasScrolling
) return;
2044 int client_width
= 0;
2045 int client_height
= 0;
2046 win
->GetClientSize( &client_width
, &client_height
);
2047 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2050 win
->m_oldClientWidth
= client_width
;
2051 win
->m_oldClientHeight
= client_height
;
2053 if (!win
->m_nativeSizeEvent
)
2055 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2056 event
.SetEventObject( win
);
2057 win
->GetEventHandler()->ProcessEvent( event
);
2063 #define WXUNUSED_UNLESS_XIM(param) param
2065 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2068 /* Resize XIM window */
2071 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2072 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2073 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2076 wxapp_install_idle_handler();
2082 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2086 gdk_window_get_size (widget
->window
, &width
, &height
);
2087 win
->m_icattr
->preedit_area
.width
= width
;
2088 win
->m_icattr
->preedit_area
.height
= height
;
2089 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2094 //-----------------------------------------------------------------------------
2095 // "realize" from m_wxwindow
2096 //-----------------------------------------------------------------------------
2098 /* Initialize XIM support */
2101 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2102 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2105 wxapp_install_idle_handler();
2108 if (win
->m_ic
) return FALSE
;
2109 if (!widget
) return FALSE
;
2110 if (!gdk_im_ready()) return FALSE
;
2112 win
->m_icattr
= gdk_ic_attr_new();
2113 if (!win
->m_icattr
) return FALSE
;
2117 GdkColormap
*colormap
;
2118 GdkICAttr
*attr
= win
->m_icattr
;
2119 unsigned attrmask
= GDK_IC_ALL_REQ
;
2121 GdkIMStyle supported_style
= (GdkIMStyle
)
2122 (GDK_IM_PREEDIT_NONE
|
2123 GDK_IM_PREEDIT_NOTHING
|
2124 GDK_IM_PREEDIT_POSITION
|
2125 GDK_IM_STATUS_NONE
|
2126 GDK_IM_STATUS_NOTHING
);
2128 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2129 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2131 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2132 attr
->client_window
= widget
->window
;
2134 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2135 gtk_widget_get_default_colormap ())
2137 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2138 attr
->preedit_colormap
= colormap
;
2141 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2142 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2143 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2144 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2146 switch (style
& GDK_IM_PREEDIT_MASK
)
2148 case GDK_IM_PREEDIT_POSITION
:
2149 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2151 g_warning ("over-the-spot style requires fontset");
2155 gdk_window_get_size (widget
->window
, &width
, &height
);
2157 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2158 attr
->spot_location
.x
= 0;
2159 attr
->spot_location
.y
= height
;
2160 attr
->preedit_area
.x
= 0;
2161 attr
->preedit_area
.y
= 0;
2162 attr
->preedit_area
.width
= width
;
2163 attr
->preedit_area
.height
= height
;
2164 attr
->preedit_fontset
= widget
->style
->font
;
2169 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2171 if (win
->m_ic
== NULL
)
2172 g_warning ("Can't create input context.");
2175 mask
= gdk_window_get_events (widget
->window
);
2176 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2177 gdk_window_set_events (widget
->window
, mask
);
2179 if (GTK_WIDGET_HAS_FOCUS(widget
))
2180 gdk_im_begin (win
->m_ic
, widget
->window
);
2187 //-----------------------------------------------------------------------------
2188 // InsertChild for wxWindowGTK.
2189 //-----------------------------------------------------------------------------
2191 /* Callback for wxWindowGTK. This very strange beast has to be used because
2192 * C++ has no virtual methods in a constructor. We have to emulate a
2193 * virtual function here as wxNotebook requires a different way to insert
2194 * a child in it. I had opted for creating a wxNotebookPage window class
2195 * which would have made this superfluous (such in the MDI window system),
2196 * but no-one was listening to me... */
2198 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2200 /* the window might have been scrolled already, do we
2201 have to adapt the position */
2202 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2203 child
->m_x
+= pizza
->xoffset
;
2204 child
->m_y
+= pizza
->yoffset
;
2206 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2207 GTK_WIDGET(child
->m_widget
),
2214 //-----------------------------------------------------------------------------
2216 //-----------------------------------------------------------------------------
2218 wxWindow
*wxGetActiveWindow()
2220 // the cast is necessary when we compile in wxUniversal mode
2221 return (wxWindow
*)g_focusWindow
;
2224 //-----------------------------------------------------------------------------
2226 //-----------------------------------------------------------------------------
2228 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2230 #ifdef __WXUNIVERSAL__
2231 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2233 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2234 #endif // __WXUNIVERSAL__/__WXGTK__
2236 void wxWindowGTK::Init()
2242 m_widget
= (GtkWidget
*) NULL
;
2243 m_wxwindow
= (GtkWidget
*) NULL
;
2244 m_focusWidget
= (GtkWidget
*) NULL
;
2254 m_needParent
= TRUE
;
2255 m_isBeingDeleted
= FALSE
;
2258 m_nativeSizeEvent
= FALSE
;
2260 m_hasScrolling
= FALSE
;
2261 m_isScrolling
= FALSE
;
2263 m_hAdjust
= (GtkAdjustment
*) NULL
;
2264 m_vAdjust
= (GtkAdjustment
*) NULL
;
2265 m_oldHorizontalPos
= 0.0;
2266 m_oldVerticalPos
= 0.0;
2269 m_widgetStyle
= (GtkStyle
*) NULL
;
2271 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2273 m_isStaticBox
= FALSE
;
2274 m_isRadioButton
= FALSE
;
2275 m_isListBox
= FALSE
;
2277 m_acceptsFocus
= FALSE
;
2279 m_clipPaintRegion
= FALSE
;
2281 m_cursor
= *wxSTANDARD_CURSOR
;
2283 m_delayedForegroundColour
= FALSE
;
2284 m_delayedBackgroundColour
= FALSE
;
2287 m_ic
= (GdkIC
*) NULL
;
2288 m_icattr
= (GdkICAttr
*) NULL
;
2292 wxWindowGTK::wxWindowGTK()
2297 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2302 const wxString
&name
)
2306 Create( parent
, id
, pos
, size
, style
, name
);
2309 bool wxWindowGTK::Create( wxWindow
*parent
,
2314 const wxString
&name
)
2316 if (!PreCreation( parent
, pos
, size
) ||
2317 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2319 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2323 m_insertCallback
= wxInsertChildInWindow
;
2325 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2326 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2328 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2330 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2331 scroll_class
->scrollbar_spacing
= 0;
2333 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2335 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2336 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2338 m_wxwindow
= gtk_pizza_new();
2340 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2342 #ifndef __WXUNIVERSAL__
2344 #if GTK_CHECK_VERSION(1, 2, 0)
2345 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2347 if (HasFlag(wxRAISED_BORDER
))
2349 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2351 else if (HasFlag(wxSUNKEN_BORDER
))
2353 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2355 else if (HasFlag(wxSIMPLE_BORDER
))
2357 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2361 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2364 GtkViewport
*viewport
= GTK_VIEWPORT(scrolledWindow
->viewport
);
2366 if (HasFlag(wxRAISED_BORDER
))
2368 gtk_viewport_set_shadow_type( viewport
, GTK_SHADOW_OUT
);
2370 else if (HasFlag(wxSUNKEN_BORDER
))
2372 gtk_viewport_set_shadow_type( viewport
, GTK_SHADOW_IN
);
2376 gtk_viewport_set_shadow_type( viewport
, GTK_SHADOW_NONE
);
2378 #endif // GTK+ > 1.0/<= 1.0
2380 #endif // __WXUNIVERSAL__
2382 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2383 m_acceptsFocus
= TRUE
;
2385 #if !GTK_CHECK_VERSION(1, 2, 0)
2386 // shut the viewport up
2387 gtk_viewport_set_hadjustment( viewport
, (GtkAdjustment
*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2388 gtk_viewport_set_vadjustment( viewport
, (GtkAdjustment
*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2391 // I _really_ don't want scrollbars in the beginning
2392 m_vAdjust
->lower
= 0.0;
2393 m_vAdjust
->upper
= 1.0;
2394 m_vAdjust
->value
= 0.0;
2395 m_vAdjust
->step_increment
= 1.0;
2396 m_vAdjust
->page_increment
= 1.0;
2397 m_vAdjust
->page_size
= 5.0;
2398 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2399 m_hAdjust
->lower
= 0.0;
2400 m_hAdjust
->upper
= 1.0;
2401 m_hAdjust
->value
= 0.0;
2402 m_hAdjust
->step_increment
= 1.0;
2403 m_hAdjust
->page_increment
= 1.0;
2404 m_hAdjust
->page_size
= 5.0;
2405 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2407 // these handlers block mouse events to any window during scrolling such as
2408 // motion events and prevent GTK and wxWindows from fighting over where the
2411 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2412 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2414 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2415 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2417 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2418 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2420 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2421 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2423 // these handlers get notified when screen updates are required either when
2424 // scrolling or when the window size (and therefore scrollbar configuration)
2427 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2428 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2429 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2430 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2432 gtk_widget_show( m_wxwindow
);
2435 m_parent
->DoAddChild( this );
2437 m_focusWidget
= m_wxwindow
;
2446 wxWindowGTK::~wxWindowGTK()
2448 if (g_focusWindow
== this)
2449 g_focusWindow
= NULL
;
2451 if (g_activeFrame
== this)
2452 g_activeFrame
= NULL
;
2454 m_isBeingDeleted
= TRUE
;
2463 m_parent
->RemoveChild( this );
2467 gdk_ic_destroy (m_ic
);
2469 gdk_ic_attr_destroy (m_icattr
);
2474 #if DISABLE_STYLE_IF_BROKEN_THEME
2475 // don't delete if it's a pixmap theme style
2476 if (!m_widgetStyle
->engine_data
)
2477 gtk_style_unref( m_widgetStyle
);
2479 m_widgetStyle
= (GtkStyle
*) NULL
;
2484 gtk_widget_destroy( m_wxwindow
);
2485 m_wxwindow
= (GtkWidget
*) NULL
;
2490 gtk_widget_destroy( m_widget
);
2491 m_widget
= (GtkWidget
*) NULL
;
2495 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2497 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2499 /* this turns -1 into 20 so that a minimal window is
2500 visible even although -1,-1 has been given as the
2501 size of the window. the same trick is used in other
2502 ports and should make debugging easier */
2503 m_width
= WidthDefault(size
.x
);
2504 m_height
= HeightDefault(size
.y
);
2509 /* some reasonable defaults */
2514 m_x
= (gdk_screen_width () - m_width
) / 2;
2515 if (m_x
< 10) m_x
= 10;
2519 m_y
= (gdk_screen_height () - m_height
) / 2;
2520 if (m_y
< 10) m_y
= 10;
2527 void wxWindowGTK::PostCreation()
2529 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2535 // these get reported to wxWindows -> wxPaintEvent
2537 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2539 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2540 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2542 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2543 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2545 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2547 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2548 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2552 // these are called when the "sunken" or "raised" borders are drawn */
2553 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2554 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2556 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2557 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2562 if (m_focusWidget
== NULL
)
2563 m_focusWidget
= m_widget
;
2566 if (GetClassInfo() && GetClassInfo()->GetClassName())
2567 wxPrintf( GetClassInfo()->GetClassName() );
2571 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2572 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2574 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2575 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2577 // connect to the various key and mouse handlers
2579 GtkWidget
*connect_widget
= GetConnectWidget();
2581 ConnectWidget( connect_widget
);
2583 /* We cannot set colours, fonts and cursors before the widget has
2584 been realized, so we do this directly after realization */
2585 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2586 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2590 // Catch native resize events
2591 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2592 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2594 // Initialize XIM support
2595 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2596 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2598 // And resize XIM window
2599 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2600 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2603 if (!GTK_IS_COMBO(m_widget
))
2605 // This is needed if we want to add our windows into native
2606 // GTK control, such as the toolbar. With this callback, the
2607 // toolbar gets to know the correct size (the one set by the
2608 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2609 // when moving to GTK 2.0.
2610 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2611 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2617 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2619 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2620 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2622 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2623 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2625 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2626 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2628 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2629 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2631 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2632 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2634 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2635 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2637 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2638 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2641 bool wxWindowGTK::Destroy()
2643 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2647 return wxWindowBase::Destroy();
2650 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2652 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2655 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2657 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2658 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2661 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2664 if (m_resizing
) return; /* I don't like recursions */
2667 int currentX
, currentY
;
2668 GetPosition(¤tX
, ¤tY
);
2673 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2675 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2677 /* don't set the size for children of wxNotebook, just take the values. */
2685 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2687 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2689 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2690 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2691 if (width
!= -1) m_width
= width
;
2692 if (height
!= -1) m_height
= height
;
2696 m_x
= x
+ pizza
->xoffset
;
2697 m_y
= y
+ pizza
->yoffset
;
2702 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2704 if (width
== -1) m_width
= 80;
2707 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2709 if (height
== -1) m_height
= 26;
2712 int minWidth
= GetMinWidth(),
2713 minHeight
= GetMinHeight(),
2714 maxWidth
= GetMaxWidth(),
2715 maxHeight
= GetMaxHeight();
2717 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2718 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2719 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2720 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2723 int bottom_border
= 0;
2725 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2727 /* the default button has a border around it */
2732 DoMoveWindow( m_x
-border
,
2735 m_height
+border
+bottom_border
);
2740 /* Sometimes the client area changes size without the
2741 whole windows's size changing, but if the whole
2742 windows's size doesn't change, no wxSizeEvent will
2743 normally be sent. Here we add an extra test if
2744 the client test has been changed and this will
2746 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2750 wxPrintf( "OnSize sent from " );
2751 if (GetClassInfo() && GetClassInfo()->GetClassName())
2752 wxPrintf( GetClassInfo()->GetClassName() );
2753 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2756 if (!m_nativeSizeEvent
)
2758 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2759 event
.SetEventObject( this );
2760 GetEventHandler()->ProcessEvent( event
);
2766 void wxWindowGTK::OnInternalIdle()
2768 // Update invalidated regions.
2771 // Synthetize activate events.
2772 if ( g_sendActivateEvent
!= -1 )
2774 bool activate
= g_sendActivateEvent
!= 0;
2777 g_sendActivateEvent
= -1;
2779 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2782 if ( g_activeFrameLostFocus
)
2784 if ( g_activeFrame
)
2786 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2787 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2788 event
.SetEventObject(g_activeFrame
);
2789 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2790 g_activeFrame
= NULL
;
2792 g_activeFrameLostFocus
= FALSE
;
2795 wxCursor cursor
= m_cursor
;
2796 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2800 /* I now set the cursor anew in every OnInternalIdle call
2801 as setting the cursor in a parent window also effects the
2802 windows above so that checking for the current cursor is
2807 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2809 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2811 if (!g_globalCursor
.Ok())
2812 cursor
= *wxSTANDARD_CURSOR
;
2814 window
= m_widget
->window
;
2815 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2816 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2822 GdkWindow
*window
= m_widget
->window
;
2823 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2824 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2832 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2834 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2836 if (width
) (*width
) = m_width
;
2837 if (height
) (*height
) = m_height
;
2840 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2842 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2846 SetSize( width
, height
);
2853 #ifndef __WXUNIVERSAL__
2854 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2856 /* when using GTK 1.2 we set the shadow border size to 2 */
2860 if (HasFlag(wxSIMPLE_BORDER
))
2862 /* when using GTK 1.2 we set the simple border size to 1 */
2866 #endif // __WXUNIVERSAL__
2870 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2872 GtkRequisition vscroll_req
;
2873 vscroll_req
.width
= 2;
2874 vscroll_req
.height
= 2;
2875 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2876 (scroll_window
->vscrollbar
, &vscroll_req
);
2878 GtkRequisition hscroll_req
;
2879 hscroll_req
.width
= 2;
2880 hscroll_req
.height
= 2;
2881 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2882 (scroll_window
->hscrollbar
, &hscroll_req
);
2884 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2886 if (scroll_window
->vscrollbar_visible
)
2888 dw
+= vscroll_req
.width
;
2889 dw
+= scroll_class
->scrollbar_spacing
;
2892 if (scroll_window
->hscrollbar_visible
)
2894 dh
+= hscroll_req
.height
;
2895 dh
+= scroll_class
->scrollbar_spacing
;
2899 SetSize( width
+dw
, height
+dh
);
2903 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2905 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2909 if (width
) (*width
) = m_width
;
2910 if (height
) (*height
) = m_height
;
2917 #ifndef __WXUNIVERSAL__
2918 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2920 /* when using GTK 1.2 we set the shadow border size to 2 */
2924 if (HasFlag(wxSIMPLE_BORDER
))
2926 /* when using GTK 1.2 we set the simple border size to 1 */
2930 #endif // __WXUNIVERSAL__
2934 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2936 GtkRequisition vscroll_req
;
2937 vscroll_req
.width
= 2;
2938 vscroll_req
.height
= 2;
2939 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2940 (scroll_window
->vscrollbar
, &vscroll_req
);
2942 GtkRequisition hscroll_req
;
2943 hscroll_req
.width
= 2;
2944 hscroll_req
.height
= 2;
2945 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2946 (scroll_window
->hscrollbar
, &hscroll_req
);
2948 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2950 if (scroll_window
->vscrollbar_visible
)
2952 dw
+= vscroll_req
.width
;
2953 dw
+= scroll_class
->scrollbar_spacing
;
2956 if (scroll_window
->hscrollbar_visible
)
2958 dh
+= hscroll_req
.height
;
2959 dh
+= scroll_class
->scrollbar_spacing
;
2963 if (width
) (*width
) = m_width
- dw
;
2964 if (height
) (*height
) = m_height
- dh
;
2968 printf( "GetClientSize, name %s ", GetName().c_str() );
2969 if (width) printf( " width = %d", (*width) );
2970 if (height) printf( " height = %d", (*height) );
2975 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2977 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2981 if (m_parent
&& m_parent
->m_wxwindow
)
2983 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2984 dx
= pizza
->xoffset
;
2985 dy
= pizza
->yoffset
;
2988 if (x
) (*x
) = m_x
- dx
;
2989 if (y
) (*y
) = m_y
- dy
;
2992 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2994 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2996 if (!m_widget
->window
) return;
2998 GdkWindow
*source
= (GdkWindow
*) NULL
;
3000 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3002 source
= m_widget
->window
;
3006 gdk_window_get_origin( source
, &org_x
, &org_y
);
3010 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3012 org_x
+= m_widget
->allocation
.x
;
3013 org_y
+= m_widget
->allocation
.y
;
3021 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3023 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3025 if (!m_widget
->window
) return;
3027 GdkWindow
*source
= (GdkWindow
*) NULL
;
3029 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3031 source
= m_widget
->window
;
3035 gdk_window_get_origin( source
, &org_x
, &org_y
);
3039 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3041 org_x
+= m_widget
->allocation
.x
;
3042 org_y
+= m_widget
->allocation
.y
;
3050 bool wxWindowGTK::Show( bool show
)
3052 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3054 if (!wxWindowBase::Show(show
))
3061 gtk_widget_show( m_widget
);
3063 gtk_widget_hide( m_widget
);
3068 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3070 win
->OnParentEnable(enable
);
3072 // Recurse, so that children have the opportunity to Do The Right Thing
3073 // and reset colours that have been messed up by a parent's (really ancestor's)
3075 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3077 node
= node
->GetNext() )
3079 wxWindow
*child
= node
->GetData();
3080 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3081 wxWindowNotifyEnable(child
, enable
);
3085 bool wxWindowGTK::Enable( bool enable
)
3087 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3089 if (!wxWindowBase::Enable(enable
))
3095 gtk_widget_set_sensitive( m_widget
, enable
);
3097 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3099 wxWindowNotifyEnable(this, enable
);
3104 int wxWindowGTK::GetCharHeight() const
3106 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3108 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3110 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3112 return font
->ascent
+ font
->descent
;
3115 int wxWindowGTK::GetCharWidth() const
3117 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3119 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3121 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3123 return gdk_string_width( font
, "H" );
3126 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3130 int *externalLeading
,
3131 const wxFont
*theFont
) const
3133 wxFont fontToUse
= m_font
;
3134 if (theFont
) fontToUse
= *theFont
;
3136 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3138 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3139 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3140 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3141 if (descent
) (*descent
) = font
->descent
;
3142 if (externalLeading
) (*externalLeading
) = 0; // ??
3145 void wxWindowGTK::SetFocus()
3147 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3150 wxPrintf( "SetFocus from " );
3151 if (GetClassInfo() && GetClassInfo()->GetClassName())
3152 wxPrintf( GetClassInfo()->GetClassName() );
3158 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3160 gtk_widget_grab_focus (m_wxwindow
);
3165 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3167 gtk_widget_grab_focus (m_widget
);
3169 else if (GTK_IS_CONTAINER(m_widget
))
3171 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3180 bool wxWindowGTK::AcceptsFocus() const
3182 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3185 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3187 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3189 wxWindowGTK
*oldParent
= m_parent
,
3190 *newParent
= (wxWindowGTK
*)newParentBase
;
3192 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3194 if ( !wxWindowBase::Reparent(newParent
) )
3197 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3199 /* prevent GTK from deleting the widget arbitrarily */
3200 gtk_widget_ref( m_widget
);
3204 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3207 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3211 /* insert GTK representation */
3212 (*(newParent
->m_insertCallback
))(newParent
, this);
3215 /* reverse: prevent GTK from deleting the widget arbitrarily */
3216 gtk_widget_unref( m_widget
);
3221 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3223 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3225 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3227 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3232 /* insert GTK representation */
3233 (*m_insertCallback
)(this, child
);
3236 void wxWindowGTK::Raise()
3238 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3240 if (!m_widget
->window
) return;
3242 gdk_window_raise( m_widget
->window
);
3245 void wxWindowGTK::Lower()
3247 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3249 if (!m_widget
->window
) return;
3251 gdk_window_lower( m_widget
->window
);
3254 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3256 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3258 if (cursor
== m_cursor
)
3262 wxapp_install_idle_handler();
3264 if (cursor
== wxNullCursor
)
3265 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3267 return wxWindowBase::SetCursor( cursor
);
3270 void wxWindowGTK::WarpPointer( int x
, int y
)
3272 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3274 // We provide this function ourselves as it is
3275 // missing in GDK (top of this file).
3277 GdkWindow
*window
= (GdkWindow
*) NULL
;
3279 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3281 window
= GetConnectWidget()->window
;
3284 gdk_window_warp_pointer( window
, x
, y
);
3287 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3289 if (!m_widget
) return;
3290 if (!m_widget
->window
) return;
3292 // temporarily hide the caret to avoid nasty interactions between caret
3293 // drawing and the window contents redraw
3294 #if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3295 wxCaretSuspend
cs((wxWindow
*)this);
3296 #endif // wxUSE_CARET
3298 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3302 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3303 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3307 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3308 m_clearRegion
.Clear();
3309 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3317 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3318 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3322 GdkRectangle gdk_rect
;
3323 gdk_rect
.x
= rect
->x
;
3324 gdk_rect
.y
= rect
->y
;
3325 gdk_rect
.width
= rect
->width
;
3326 gdk_rect
.height
= rect
->height
;
3327 gtk_widget_draw( m_widget
, &gdk_rect
);
3334 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3335 m_updateRegion
.Clear();
3336 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3340 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3345 void wxWindowGTK::Update()
3347 if (!m_updateRegion
.IsEmpty())
3349 GtkSendPaintEvents();
3353 void wxWindowGTK::GtkSendPaintEvents()
3357 m_clearRegion
.Clear();
3358 m_updateRegion
.Clear();
3362 m_clipPaintRegion
= TRUE
;
3364 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3366 wxWindowDC
dc( (wxWindow
*)this );
3367 dc
.SetClippingRegion( m_clearRegion
);
3369 wxEraseEvent
erase_event( GetId(), &dc
);
3370 erase_event
.SetEventObject( this );
3372 if (!GetEventHandler()->ProcessEvent(erase_event
))
3374 wxRegionIterator
upd( m_clearRegion
);
3377 gdk_window_clear_area( GTK_PIZZA(m_wxwindow
)->bin_window
,
3378 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3382 m_clearRegion
.Clear();
3385 wxNcPaintEvent
nc_paint_event( GetId() );
3386 nc_paint_event
.SetEventObject( this );
3387 GetEventHandler()->ProcessEvent( nc_paint_event
);
3389 wxPaintEvent
paint_event( GetId() );
3390 paint_event
.SetEventObject( this );
3391 GetEventHandler()->ProcessEvent( paint_event
);
3393 m_clipPaintRegion
= FALSE
;
3395 #ifndef __WXUNIVERSAL__
3396 // The following code will result in all window-less widgets
3397 // being redrawn because the wxWindows class is allowed to
3398 // paint over the window-less widgets.
3400 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3402 GList
*children
= pizza
->children
;
3405 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3406 children
= children
->next
;
3408 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3409 GTK_WIDGET_DRAWABLE (child
->widget
))
3411 // Get intersection of widget area and update region
3412 wxRegion
region( m_updateRegion
);
3414 GdkEventExpose gdk_event
;
3415 gdk_event
.type
= GDK_EXPOSE
;
3416 gdk_event
.window
= pizza
->bin_window
;
3417 gdk_event
.count
= 0;
3419 wxRegionIterator
upd( m_updateRegion
);
3423 rect
.x
= upd
.GetX();
3424 rect
.y
= upd
.GetY();
3425 rect
.width
= upd
.GetWidth();
3426 rect
.height
= upd
.GetHeight();
3428 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3430 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3439 m_updateRegion
.Clear();
3442 void wxWindowGTK::Clear()
3444 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3446 if (!m_widget
->window
) return;
3448 if (m_wxwindow
&& m_wxwindow
->window
)
3450 // gdk_window_clear( m_wxwindow->window );
3455 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3457 wxWindowBase::DoSetToolTip(tip
);
3460 m_tooltip
->Apply( (wxWindow
*)this );
3463 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3465 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3467 #endif // wxUSE_TOOLTIPS
3469 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3471 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3473 if (!wxWindowBase::SetBackgroundColour(colour
))
3475 // don't leave if the GTK widget has just
3477 if (!m_delayedBackgroundColour
) return FALSE
;
3480 GdkWindow
*window
= (GdkWindow
*) NULL
;
3482 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3484 window
= GetConnectWidget()->window
;
3488 // indicate that a new style has been set
3489 // but it couldn't get applied as the
3490 // widget hasn't been realized yet.
3491 m_delayedBackgroundColour
= TRUE
;
3495 (m_wxwindow
->window
) &&
3496 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3498 /* wxMSW doesn't clear the window here. I don't do that either to
3499 provide compatibility. call Clear() to do the job. */
3501 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3502 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3510 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3512 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3514 if (!wxWindowBase::SetForegroundColour(colour
))
3516 // don't leave if the GTK widget has just
3518 if (!m_delayedForegroundColour
) return FALSE
;
3521 GdkWindow
*window
= (GdkWindow
*) NULL
;
3523 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3525 window
= GetConnectWidget()->window
;
3529 // indicate that a new style has been set
3530 // but it couldn't get applied as the
3531 // widget hasn't been realized yet.
3532 m_delayedForegroundColour
= TRUE
;
3540 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3544 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3546 // FIXME: no more klass in 2.0
3548 remake
->klass
= m_widgetStyle
->klass
;
3551 gtk_style_unref( m_widgetStyle
);
3552 m_widgetStyle
= remake
;
3556 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3559 def
= gtk_widget_get_default_style();
3561 m_widgetStyle
= gtk_style_copy( def
);
3563 // FIXME: no more klass in 2.0
3565 m_widgetStyle
->klass
= def
->klass
;
3569 return m_widgetStyle
;
3572 void wxWindowGTK::SetWidgetStyle()
3574 #if DISABLE_STYLE_IF_BROKEN_THEME
3575 if (m_widget
->style
->engine_data
)
3577 static bool s_warningPrinted
= FALSE
;
3578 if (!s_warningPrinted
)
3580 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3581 s_warningPrinted
= TRUE
;
3583 m_widgetStyle
= m_widget
->style
;
3588 GtkStyle
*style
= GetWidgetStyle();
3590 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3592 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3595 if (m_foregroundColour
.Ok())
3597 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3598 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3600 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3601 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3602 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3606 // Try to restore the gtk default style. This is still a little
3607 // oversimplified for what is probably really needed here for controls
3608 // other than buttons, but is better than not being able to (re)set a
3609 // control's foreground colour to *wxBLACK -- RL
3610 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3613 def
= gtk_widget_get_default_style();
3615 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3616 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3617 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3621 if (m_backgroundColour
.Ok())
3623 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3624 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3626 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3627 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3628 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3629 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3630 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3631 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3632 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3633 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3637 // Try to restore the gtk default style. This is still a little
3638 // oversimplified for what is probably really needed here for controls
3639 // other than buttons, but is better than not being able to (re)set a
3640 // control's background colour to default grey and means resetting a
3641 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3643 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3646 def
= gtk_widget_get_default_style();
3648 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3649 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3650 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3651 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3652 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3653 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3654 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3655 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3660 void wxWindowGTK::ApplyWidgetStyle()
3664 //-----------------------------------------------------------------------------
3665 // Pop-up menu stuff
3666 //-----------------------------------------------------------------------------
3668 #if wxUSE_MENUS_NATIVE
3671 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3673 *is_waiting
= FALSE
;
3676 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3678 menu
->SetInvokingWindow( win
);
3679 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3682 wxMenuItem
*menuitem
= node
->GetData();
3683 if (menuitem
->IsSubMenu())
3685 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3688 node
= node
->GetNext();
3692 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3693 // wxPopupMenuPositionCallback()
3695 // should be safe even in the MT case as the user can hardly popup 2 menus
3696 // simultaneously, can he?
3697 static gint gs_pop_x
= 0;
3698 static gint gs_pop_y
= 0;
3700 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3703 gboolean
* WXUNUSED(whatever
),
3705 gpointer
WXUNUSED(user_data
) )
3707 // ensure that the menu appears entirely on screen
3709 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3711 wxSize sizeScreen
= wxGetDisplaySize();
3713 gint xmax
= sizeScreen
.x
- req
.width
,
3714 ymax
= sizeScreen
.y
- req
.height
;
3716 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3717 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3720 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3722 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3724 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3726 SetInvokingWindow( menu
, this );
3732 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3734 bool is_waiting
= TRUE
;
3736 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3738 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3739 (gpointer
)&is_waiting
);
3742 GTK_MENU(menu
->m_menu
),
3743 (GtkWidget
*) NULL
, // parent menu shell
3744 (GtkWidget
*) NULL
, // parent menu item
3745 wxPopupMenuPositionCallback
, // function to position it
3746 NULL
, // client data
3747 0, // button used to activate it
3748 gs_timeLastClick
// the time of activation
3753 while (gtk_events_pending())
3754 gtk_main_iteration();
3760 #endif // wxUSE_MENUS_NATIVE
3762 #if wxUSE_DRAG_AND_DROP
3764 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3766 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3768 GtkWidget
*dnd_widget
= GetConnectWidget();
3770 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3772 if (m_dropTarget
) delete m_dropTarget
;
3773 m_dropTarget
= dropTarget
;
3775 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3778 #endif // wxUSE_DRAG_AND_DROP
3780 GtkWidget
* wxWindowGTK::GetConnectWidget()
3782 GtkWidget
*connect_widget
= m_widget
;
3783 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3785 return connect_widget
;
3788 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3791 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3793 return (window
== m_widget
->window
);
3796 bool wxWindowGTK::SetFont( const wxFont
&font
)
3798 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3800 if (!wxWindowBase::SetFont(font
))
3805 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3806 if ( sysbg
== m_backgroundColour
)
3808 m_backgroundColour
= wxNullColour
;
3810 m_backgroundColour
= sysbg
;
3820 void wxWindowGTK::DoCaptureMouse()
3822 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3824 GdkWindow
*window
= (GdkWindow
*) NULL
;
3826 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3828 window
= GetConnectWidget()->window
;
3830 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3832 wxCursor
* cursor
= & m_cursor
;
3834 cursor
= wxSTANDARD_CURSOR
;
3836 gdk_pointer_grab( window
, FALSE
,
3838 (GDK_BUTTON_PRESS_MASK
|
3839 GDK_BUTTON_RELEASE_MASK
|
3840 GDK_POINTER_MOTION_HINT_MASK
|
3841 GDK_POINTER_MOTION_MASK
),
3843 cursor
->GetCursor(),
3844 (guint32
)GDK_CURRENT_TIME
);
3845 g_captureWindow
= this;
3846 g_captureWindowHasMouse
= TRUE
;
3849 void wxWindowGTK::DoReleaseMouse()
3851 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3853 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3855 g_captureWindow
= (wxWindowGTK
*) NULL
;
3857 GdkWindow
*window
= (GdkWindow
*) NULL
;
3859 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3861 window
= GetConnectWidget()->window
;
3866 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3870 wxWindow
*wxWindowBase::GetCapture()
3872 return (wxWindow
*)g_captureWindow
;
3875 bool wxWindowGTK::IsRetained() const
3880 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3881 int range
, bool refresh
)
3883 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3885 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3887 m_hasScrolling
= TRUE
;
3889 if (orient
== wxHORIZONTAL
)
3891 float fpos
= (float)pos
;
3892 float frange
= (float)range
;
3893 float fthumb
= (float)thumbVisible
;
3894 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3895 if (fpos
< 0.0) fpos
= 0.0;
3897 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
3898 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
3900 SetScrollPos( orient
, pos
, refresh
);
3904 m_oldHorizontalPos
= fpos
;
3906 m_hAdjust
->lower
= 0.0;
3907 m_hAdjust
->upper
= frange
;
3908 m_hAdjust
->value
= fpos
;
3909 m_hAdjust
->step_increment
= 1.0;
3910 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3911 m_hAdjust
->page_size
= fthumb
;
3915 float fpos
= (float)pos
;
3916 float frange
= (float)range
;
3917 float fthumb
= (float)thumbVisible
;
3918 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3919 if (fpos
< 0.0) fpos
= 0.0;
3921 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
3922 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
3924 SetScrollPos( orient
, pos
, refresh
);
3928 m_oldVerticalPos
= fpos
;
3930 m_vAdjust
->lower
= 0.0;
3931 m_vAdjust
->upper
= frange
;
3932 m_vAdjust
->value
= fpos
;
3933 m_vAdjust
->step_increment
= 1.0;
3934 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3935 m_vAdjust
->page_size
= fthumb
;
3938 if (orient
== wxHORIZONTAL
)
3939 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
3941 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
3944 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
3946 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3948 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3950 if (orient
== wxHORIZONTAL
)
3952 float fpos
= (float)pos
;
3953 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
3954 if (fpos
< 0.0) fpos
= 0.0;
3955 m_oldHorizontalPos
= fpos
;
3957 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
3958 m_hAdjust
->value
= fpos
;
3962 float fpos
= (float)pos
;
3963 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
3964 if (fpos
< 0.0) fpos
= 0.0;
3965 m_oldVerticalPos
= fpos
;
3967 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
3968 m_vAdjust
->value
= fpos
;
3971 if (m_wxwindow
->window
)
3973 if (orient
== wxHORIZONTAL
)
3975 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
3976 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
3978 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
3980 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
3981 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
3985 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
3986 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
3988 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
3990 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
3991 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
3996 int wxWindowGTK::GetScrollThumb( int orient
) const
3998 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4000 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4002 if (orient
== wxHORIZONTAL
)
4003 return (int)(m_hAdjust
->page_size
+0.5);
4005 return (int)(m_vAdjust
->page_size
+0.5);
4008 int wxWindowGTK::GetScrollPos( int orient
) const
4010 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4012 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4014 if (orient
== wxHORIZONTAL
)
4015 return (int)(m_hAdjust
->value
+0.5);
4017 return (int)(m_vAdjust
->value
+0.5);
4020 int wxWindowGTK::GetScrollRange( int orient
) const
4022 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4024 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4026 if (orient
== wxHORIZONTAL
)
4027 return (int)(m_hAdjust
->upper
+0.5);
4029 return (int)(m_vAdjust
->upper
+0.5);
4032 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4034 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4036 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4038 // No scrolling requested.
4039 if ((dx
== 0) && (dy
== 0)) return;
4041 if (!m_updateRegion
.IsEmpty())
4043 m_updateRegion
.Offset( dx
, dy
);
4047 GetClientSize( &cw
, &ch
);
4048 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4051 if (!m_clearRegion
.IsEmpty())
4053 m_clearRegion
.Offset( dx
, dy
);
4057 GetClientSize( &cw
, &ch
);
4058 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4063 m_clipPaintRegion
= TRUE
;
4065 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4067 m_clipPaintRegion
= FALSE
;
4071 if (m_children
.GetCount() > 0)
4073 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4077 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
4079 pizza
->xoffset
-= dx
;
4080 pizza
->yoffset
-= dy
;
4082 GdkGC
*m_scrollGC
= gdk_gc_new( pizza
->bin_window
);
4083 gdk_gc_set_exposures( m_scrollGC
, TRUE
);
4087 GetClientSize( &cw
, &ch
);
4088 int w
= cw
- abs(dx
);
4089 int h
= ch
- abs(dy
);
4091 if ((h
< 0) || (w
< 0))
4099 if (dx
< 0) s_x
= -dx
;
4100 if (dy
< 0) s_y
= -dy
;
4103 if (dx
> 0) d_x
= dx
;
4104 if (dy
> 0) d_y
= dy
;
4106 gdk_window_copy_area( pizza
->bin_window
, m_scrollGC
, d_x
, d_y
,
4107 pizza
->bin_window
, s_x
, s_y
, w
, h
);
4110 if (dx
< 0) rect
.x
= cw
+dx
; else rect
.x
= 0;
4111 if (dy
< 0) rect
.y
= ch
+dy
; else rect
.y
= 0;
4112 if (dy
!= 0) rect
.width
= cw
; else rect
.width
= abs(dx
);
4113 if (dx
!= 0) rect
.height
= ch
; else rect
.height
= abs(dy
);
4115 Refresh( TRUE
, &rect
);
4118 gdk_gc_unref( m_scrollGC
);
4123 // Find the wxWindow at the current mouse position, also returning the mouse
4125 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4127 pt
= wxGetMousePosition();
4128 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4132 // Get the current mouse position.
4133 wxPoint
wxGetMousePosition()
4135 /* This crashes when used within wxHelpContext,
4136 so we have to use the X-specific implementation below.
4138 GdkModifierType *mask;
4139 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4141 return wxPoint(x, y);
4145 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4147 return wxPoint(-999, -999);
4149 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4150 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4151 Window rootReturn
, childReturn
;
4152 int rootX
, rootY
, winX
, winY
;
4153 unsigned int maskReturn
;
4155 XQueryPointer (display
,
4159 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4160 return wxPoint(rootX
, rootY
);