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))
79 //-----------------------------------------------------------------------------
80 // documentation on internals
81 //-----------------------------------------------------------------------------
84 I have been asked several times about writing some documentation about
85 the GTK port of wxWindows, especially its internal structures. Obviously,
86 you cannot understand wxGTK without knowing a little about the GTK, but
87 some more information about what the wxWindow, which is the base class
88 for all other window classes, does seems required as well.
92 What does wxWindow do? It contains the common interface for the following
93 jobs of its descendants:
95 1) Define the rudimentary behaviour common to all window classes, such as
96 resizing, intercepting user input (so as to make it possible to use these
97 events for special purposes in a derived class), window names etc.
99 2) Provide the possibility to contain and manage children, if the derived
100 class is allowed to contain children, which holds true for those window
101 classes which do not display a native GTK widget. To name them, these
102 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
103 work classes are a special case and are handled a bit differently from
104 the rest. The same holds true for the wxNotebook class.
106 3) Provide the possibility to draw into a client area of a window. This,
107 too, only holds true for classes that do not display a native GTK widget
110 4) Provide the entire mechanism for scrolling widgets. This actual inter-
111 face for this is usually in wxScrolledWindow, but the GTK implementation
114 5) A multitude of helper or extra methods for special purposes, such as
115 Drag'n'Drop, managing validators etc.
117 6) Display a border (sunken, raised, simple or none).
119 Normally one might expect, that one wxWindows window would always correspond
120 to one GTK widget. Under GTK, there is no such allround widget that has all
121 the functionality. Moreover, the GTK defines a client area as a different
122 widget from the actual widget you are handling. Last but not least some
123 special classes (e.g. wxFrame) handle different categories of widgets and
124 still have the possibility to draw something in the client area.
125 It was therefore required to write a special purpose GTK widget, that would
126 represent a client area in the sense of wxWindows capable to do the jobs
127 2), 3) and 4). I have written this class and it resides in win_gtk.c of
130 All windows must have a widget, with which they interact with other under-
131 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
132 thw wxWindow class has a member variable called m_widget which holds a
133 pointer to this widget. When the window class represents a GTK native widget,
134 this is (in most cases) the only GTK widget the class manages. E.g. the
135 wxStatitText class handles only a GtkLabel widget a pointer to which you
136 can find in m_widget (defined in wxWindow)
138 When the class has a client area for drawing into and for containing children
139 it has to handle the client area widget (of the type GtkPizza, defined in
140 win_gtk.c), but there could be any number of widgets, handled by a class
141 The common rule for all windows is only, that the widget that interacts with
142 the rest of GTK must be referenced in m_widget and all other widgets must be
143 children of this widget on the GTK level. The top-most widget, which also
144 represents the client area, must be in the m_wxwindow field and must be of
147 As I said, the window classes that display a GTK native widget only have
148 one widget, so in the case of e.g. the wxButton class m_widget holds a
149 pointer to a GtkButton widget. But windows with client areas (for drawing
150 and children) have a m_widget field that is a pointer to a GtkScrolled-
151 Window and a m_wxwindow field that is pointer to a GtkPizza and this
152 one is (in the GTK sense) a child of the GtkScrolledWindow.
154 If the m_wxwindow field is set, then all input to this widget is inter-
155 cepted and sent to the wxWindows class. If not, all input to the widget
156 that gets pointed to by m_widget gets intercepted and sent to the class.
160 The design of scrolling in wxWindows is markedly different from that offered
161 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
162 clicking on a scrollbar belonging to scrolled window will inevitably move
163 the window. In wxWindows, the scrollbar will only emit an event, send this
164 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
165 which actually moves the window and its subchildren. Note that GtkPizza
166 memorizes how much it has been scrolled but that wxWindows forgets this
167 so that the two coordinates systems have to be kept in synch. This is done
168 in various places using the pizza->xoffset and pizza->yoffset values.
172 Singularily the most broken code in GTK is the code that is supposes to
173 inform subwindows (child windows) about new positions. Very often, duplicate
174 events are sent without changes in size or position, equally often no
175 events are sent at all (All this is due to a bug in the GtkContainer code
176 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
177 GTK's own system and it simply waits for size events for toplevel windows
178 and then iterates down the respective size events to all window. This has
179 the disadvantage, that windows might get size events before the GTK widget
180 actually has the reported size. This doesn't normally pose any problem, but
181 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
182 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
183 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
184 window that is used for OpenGl output really has that size (as reported by
189 If someone at some point of time feels the immense desire to have a look at,
190 change or attempt to optimse the Refresh() logic, this person will need an
191 intimate understanding of what a "draw" and what an "expose" events are and
192 what there are used for, in particular when used in connection with GTK's
193 own windowless widgets. Beware.
197 Cursors, too, have been a constant source of pleasure. The main difficulty
198 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
199 for the parent. To prevent this from doing too much harm, I use idle time
200 to set the cursor over and over again, starting from the toplevel windows
201 and ending with the youngest generation (speaking of parent and child windows).
202 Also don't forget that cursors (like much else) are connected to GdkWindows,
203 not GtkWidgets and that the "window" field of a GtkWidget might very well
204 point to the GdkWindow of the parent widget (-> "window less widget") and
205 that the two obviously have very different meanings.
209 //-----------------------------------------------------------------------------
211 //-----------------------------------------------------------------------------
213 extern wxList wxPendingDelete
;
214 extern bool g_blockEventsOnDrag
;
215 extern bool g_blockEventsOnScroll
;
216 extern wxCursor g_globalCursor
;
218 static GdkGC
*g_eraseGC
= NULL
;
220 // mouse capture state: the window which has it and if the mouse is currently
222 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
223 static bool g_captureWindowHasMouse
= FALSE
;
225 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
227 // the last window which had the focus - this is normally never NULL (except
228 // if we never had focus at all) as even when g_focusWindow is NULL it still
229 // keeps its previous value
230 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*)NULL
;
232 // the frame that is currently active (i.e. its child has focus). It is
233 // used to generate wxActivateEvents
234 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*)NULL
;
235 static bool g_activeFrameLostFocus
= FALSE
;
237 // if we detect that the app has got/lost the focus, we set this variable to
238 // either TRUE or FALSE and an activate event will be sent during the next
239 // OnIdle() call and it is reset to -1: this value means that we shouldn't
240 // send any activate events at all
241 static int g_sendActivateEvent
= -1;
243 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
244 the last click here */
245 static guint32 gs_timeLastClick
= 0;
247 extern bool g_mainThreadLocked
;
249 //-----------------------------------------------------------------------------
251 //-----------------------------------------------------------------------------
254 #define DISABLE_STYLE_IF_BROKEN_THEME 1
260 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
262 # define DEBUG_MAIN_THREAD
265 static gint
gtk_debug_focus_in_callback( GtkWidget
*WXUNUSED(widget
),
266 GdkEvent
*WXUNUSED(event
),
267 const wxChar
*WXUNUSED(name
) )
270 static bool s_done = FALSE;
273 wxLog::AddTraceMask("focus");
276 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
282 void debug_focus_in( GtkWidget
* widget
, const wxChar
* name
, const wxChar
*window
)
284 // suppress warnings about gtk_debug_focus_in_callback being unused with
289 tmp
+= wxT(" FROM ");
292 wxChar
*s
= new wxChar
[tmp
.Length()+1];
296 gtk_signal_connect( GTK_OBJECT(widget
), "focus_in_event",
297 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback
), (gpointer
)s
);
302 #define DEBUG_MAIN_THREAD
305 //-----------------------------------------------------------------------------
306 // missing gdk functions
307 //-----------------------------------------------------------------------------
310 gdk_window_warp_pointer (GdkWindow
*window
,
315 GdkWindowPrivate
*priv
;
319 window
= GDK_ROOT_PARENT();
322 if (!GDK_WINDOW_DESTROYED(window
))
324 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
325 None
, /* not source window -> move from anywhere */
326 GDK_WINDOW_XID(window
), /* dest window */
327 0, 0, 0, 0, /* not source window -> move from anywhere */
331 priv
= (GdkWindowPrivate
*) window
;
333 if (!priv
->destroyed
)
335 XWarpPointer (priv
->xdisplay
,
336 None
, /* not source window -> move from anywhere */
337 priv
->xwindow
, /* dest window */
338 0, 0, 0, 0, /* not source window -> move from anywhere */
344 //-----------------------------------------------------------------------------
346 //-----------------------------------------------------------------------------
348 extern void wxapp_install_idle_handler();
349 extern bool g_isIdle
;
351 //-----------------------------------------------------------------------------
352 // local code (see below)
353 //-----------------------------------------------------------------------------
355 // returns the child of win which currently has focus or NULL if not found
357 // Note: can't be static, needed by textctrl.cpp.
358 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
360 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
362 return (wxWindow
*)NULL
;
364 if ( winFocus
== win
)
365 return (wxWindow
*)win
;
367 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
369 node
= node
->GetNext() )
371 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
376 return (wxWindow
*)NULL
;
379 // Returns toplevel grandparent of given window:
380 static wxWindowGTK
* wxGetTopLevelParent(wxWindowGTK
*win
)
382 wxWindowGTK
*p
= win
;
383 while (p
&& !p
->IsTopLevel())
388 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
390 // wxUniversal widgets draw the borders and scrollbars themselves
391 #ifndef __WXUNIVERSAL__
398 if (win
->m_hasScrolling
)
400 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
402 GtkRequisition vscroll_req
;
403 vscroll_req
.width
= 2;
404 vscroll_req
.height
= 2;
405 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
406 (scroll_window
->vscrollbar
, &vscroll_req
);
408 GtkRequisition hscroll_req
;
409 hscroll_req
.width
= 2;
410 hscroll_req
.height
= 2;
411 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
412 (scroll_window
->hscrollbar
, &hscroll_req
);
414 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
416 if (scroll_window
->vscrollbar_visible
)
418 dw
+= vscroll_req
.width
;
419 dw
+= scroll_class
->scrollbar_spacing
;
422 if (scroll_window
->hscrollbar_visible
)
424 dh
+= hscroll_req
.height
;
425 dh
+= scroll_class
->scrollbar_spacing
;
431 if (GTK_WIDGET_NO_WINDOW (widget
))
433 dx
+= widget
->allocation
.x
;
434 dy
+= widget
->allocation
.y
;
437 if (win
->HasFlag(wxRAISED_BORDER
))
439 gtk_draw_shadow( widget
->style
,
444 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
448 if (win
->HasFlag(wxSUNKEN_BORDER
))
450 gtk_draw_shadow( widget
->style
,
455 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
459 if (win
->HasFlag(wxSIMPLE_BORDER
))
462 gc
= gdk_gc_new( widget
->window
);
463 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
464 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
466 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
470 #endif // __WXUNIVERSAL__
473 //-----------------------------------------------------------------------------
474 // "expose_event" of m_widget
475 //-----------------------------------------------------------------------------
477 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
479 if (gdk_event
->count
> 0) return FALSE
;
481 draw_frame( widget
, win
);
486 //-----------------------------------------------------------------------------
487 // "draw" of m_widget
488 //-----------------------------------------------------------------------------
492 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
494 draw_frame( widget
, win
);
499 //-----------------------------------------------------------------------------
500 // key code mapping routines
501 //-----------------------------------------------------------------------------
503 static long map_to_unmodified_wx_keysym( GdkEventKey
*event
)
505 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
506 // but only event->keyval which is quite useless to us, so remember
507 // the last character from GDK_KEY_PRESS and resue it as last resort
509 // NB: should be MT-neutral as always called from main thread only
514 } s_lastKeyPress
= { 0, 0 };
516 KeySym keysym
= event
->keyval
;
522 case GDK_Shift_R
: key_code
= WXK_SHIFT
; break;
524 case GDK_Control_R
: key_code
= WXK_CONTROL
; break;
530 case GDK_Super_R
: key_code
= WXK_ALT
; break;
531 case GDK_Menu
: key_code
= WXK_MENU
; break;
532 case GDK_Help
: key_code
= WXK_HELP
; break;
533 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
534 case GDK_ISO_Left_Tab
:
535 case GDK_Tab
: key_code
= WXK_TAB
; break;
536 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
537 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
538 case GDK_Return
: key_code
= WXK_RETURN
; break;
539 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
540 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
541 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
542 case GDK_Delete
: key_code
= WXK_DELETE
; break;
543 case GDK_Home
: key_code
= WXK_HOME
; break;
544 case GDK_Left
: key_code
= WXK_LEFT
; break;
545 case GDK_Up
: key_code
= WXK_UP
; break;
546 case GDK_Right
: key_code
= WXK_RIGHT
; break;
547 case GDK_Down
: key_code
= WXK_DOWN
; break;
548 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
549 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
550 case GDK_Next
: key_code
= WXK_NEXT
; break;
551 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
552 case GDK_End
: key_code
= WXK_END
; break;
553 case GDK_Begin
: key_code
= WXK_HOME
; break;
554 case GDK_Select
: key_code
= WXK_SELECT
; break;
555 case GDK_Print
: key_code
= WXK_PRINT
; break;
556 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
557 case GDK_Insert
: key_code
= WXK_INSERT
; break;
558 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
560 case GDK_KP_0
: key_code
= WXK_NUMPAD0
; break;
561 case GDK_KP_1
: key_code
= WXK_NUMPAD1
; break;
562 case GDK_KP_2
: key_code
= WXK_NUMPAD2
; break;
563 case GDK_KP_3
: key_code
= WXK_NUMPAD3
; break;
564 case GDK_KP_4
: key_code
= WXK_NUMPAD4
; break;
565 case GDK_KP_5
: key_code
= WXK_NUMPAD5
; break;
566 case GDK_KP_6
: key_code
= WXK_NUMPAD6
; break;
567 case GDK_KP_7
: key_code
= WXK_NUMPAD7
; break;
568 case GDK_KP_8
: key_code
= WXK_NUMPAD8
; break;
569 case GDK_KP_9
: key_code
= WXK_NUMPAD9
; break;
570 case GDK_KP_Space
: key_code
= WXK_NUMPAD_SPACE
; break;
571 case GDK_KP_Tab
: key_code
= WXK_NUMPAD_TAB
; break;
572 case GDK_KP_Enter
: key_code
= WXK_NUMPAD_ENTER
; break;
573 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
574 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
575 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
576 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
577 case GDK_KP_Home
: key_code
= WXK_NUMPAD_HOME
; break;
578 case GDK_KP_Left
: key_code
= WXK_NUMPAD_LEFT
; break;
579 case GDK_KP_Up
: key_code
= WXK_NUMPAD_UP
; break;
580 case GDK_KP_Right
: key_code
= WXK_NUMPAD_RIGHT
; break;
581 case GDK_KP_Down
: key_code
= WXK_NUMPAD_DOWN
; break;
582 case GDK_KP_Prior
: key_code
= WXK_NUMPAD_PRIOR
; break;
583 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
584 case GDK_KP_Next
: key_code
= WXK_NUMPAD_NEXT
; break;
585 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
586 case GDK_KP_End
: key_code
= WXK_NUMPAD_END
; break;
587 case GDK_KP_Begin
: key_code
= WXK_NUMPAD_BEGIN
; break;
588 case GDK_KP_Insert
: key_code
= WXK_NUMPAD_INSERT
; break;
589 case GDK_KP_Delete
: key_code
= WXK_NUMPAD_DELETE
; break;
590 case GDK_KP_Equal
: key_code
= WXK_NUMPAD_EQUAL
; break;
591 case GDK_KP_Multiply
: key_code
= WXK_NUMPAD_MULTIPLY
; break;
592 case GDK_KP_Add
: key_code
= WXK_NUMPAD_ADD
; break;
593 case GDK_KP_Separator
: key_code
= WXK_NUMPAD_SEPARATOR
; break;
594 case GDK_KP_Subtract
: key_code
= WXK_NUMPAD_SUBTRACT
; break;
595 case GDK_KP_Decimal
: key_code
= WXK_NUMPAD_DECIMAL
; break;
596 case GDK_KP_Divide
: key_code
= WXK_NUMPAD_DIVIDE
; break;
598 case GDK_F1
: key_code
= WXK_F1
; break;
599 case GDK_F2
: key_code
= WXK_F2
; break;
600 case GDK_F3
: key_code
= WXK_F3
; break;
601 case GDK_F4
: key_code
= WXK_F4
; break;
602 case GDK_F5
: key_code
= WXK_F5
; break;
603 case GDK_F6
: key_code
= WXK_F6
; break;
604 case GDK_F7
: key_code
= WXK_F7
; break;
605 case GDK_F8
: key_code
= WXK_F8
; break;
606 case GDK_F9
: key_code
= WXK_F9
; break;
607 case GDK_F10
: key_code
= WXK_F10
; break;
608 case GDK_F11
: key_code
= WXK_F11
; break;
609 case GDK_F12
: key_code
= WXK_F12
; break;
612 // do we have the translation?
613 if ( event
->length
== 1 )
615 keysym
= (KeySym
)event
->string
[0];
617 else if ( (keysym
& 0xFF) != keysym
)
619 // non ASCII key, what to do?
621 if ( event
->type
== GDK_KEY_RELEASE
)
623 // reuse the one from the last keypress if any
624 if ( keysym
== s_lastKeyPress
.keysym
)
626 key_code
= s_lastKeyPress
.keycode
;
633 // ignore this one, we don't know it
636 //else: ASCII key, ok
638 guint upper
= gdk_keyval_to_upper( (guint
)keysym
);
639 key_code
= upper
? upper
: keysym
;
641 if ( event
->type
== GDK_KEY_PRESS
)
643 // remember it to be reused below later
644 s_lastKeyPress
.keysym
= keysym
;
645 s_lastKeyPress
.keycode
= key_code
;
653 static long map_to_wx_keysym( GdkEventKey
*event
)
655 KeySym keysym
= event
->keyval
;
660 case GDK_Menu
: key_code
= WXK_MENU
; break;
661 case GDK_Help
: key_code
= WXK_HELP
; break;
662 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
663 case GDK_ISO_Left_Tab
:
664 case GDK_Tab
: key_code
= WXK_TAB
; break;
665 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
666 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
667 case GDK_Return
: key_code
= WXK_RETURN
; break;
668 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
669 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
670 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
671 case GDK_Delete
: key_code
= WXK_DELETE
; break;
672 case GDK_Home
: key_code
= WXK_HOME
; break;
673 case GDK_Left
: key_code
= WXK_LEFT
; break;
674 case GDK_Up
: key_code
= WXK_UP
; break;
675 case GDK_Right
: key_code
= WXK_RIGHT
; break;
676 case GDK_Down
: key_code
= WXK_DOWN
; break;
677 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
678 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
679 case GDK_Next
: key_code
= WXK_NEXT
; break;
680 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
681 case GDK_End
: key_code
= WXK_END
; break;
682 case GDK_Begin
: key_code
= WXK_HOME
; break;
683 case GDK_Select
: key_code
= WXK_SELECT
; break;
684 case GDK_Print
: key_code
= WXK_PRINT
; break;
685 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
686 case GDK_Insert
: key_code
= WXK_INSERT
; break;
687 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
689 case GDK_KP_0
: key_code
= '0'; break;
690 case GDK_KP_1
: key_code
= '1'; break;
691 case GDK_KP_2
: key_code
= '2'; break;
692 case GDK_KP_3
: key_code
= '3'; break;
693 case GDK_KP_4
: key_code
= '4'; break;
694 case GDK_KP_5
: key_code
= '5'; break;
695 case GDK_KP_6
: key_code
= '6'; break;
696 case GDK_KP_7
: key_code
= '7'; break;
697 case GDK_KP_8
: key_code
= '8'; break;
698 case GDK_KP_9
: key_code
= '9'; break;
699 case GDK_KP_Space
: key_code
= ' '; break;
700 case GDK_KP_Tab
: key_code
= WXK_TAB
; break; /* or '\t' ??? */
701 case GDK_KP_Enter
: key_code
= WXK_RETURN
; break; /* or '\r' ??? */
702 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
703 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
704 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
705 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
706 case GDK_KP_Home
: key_code
= WXK_HOME
; break;
707 case GDK_KP_Left
: key_code
= WXK_LEFT
; break;
708 case GDK_KP_Up
: key_code
= WXK_UP
; break;
709 case GDK_KP_Right
: key_code
= WXK_RIGHT
; break;
710 case GDK_KP_Down
: key_code
= WXK_DOWN
; break;
711 case GDK_KP_Prior
: key_code
= WXK_PRIOR
; break;
712 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
713 case GDK_KP_Next
: key_code
= WXK_NEXT
; break;
714 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
715 case GDK_KP_End
: key_code
= WXK_END
; break;
716 case GDK_KP_Begin
: key_code
= WXK_HOME
; break;
717 case GDK_KP_Insert
: key_code
= WXK_INSERT
; break;
718 case GDK_KP_Delete
: key_code
= WXK_DELETE
; break;
719 case GDK_KP_Equal
: key_code
= '='; break;
720 case GDK_KP_Multiply
: key_code
= '*'; break;
721 case GDK_KP_Add
: key_code
= '+'; break;
722 case GDK_KP_Separator
: key_code
= ','; break;
723 case GDK_KP_Subtract
: key_code
= '-'; break;
724 case GDK_KP_Decimal
: key_code
= '.'; break;
725 case GDK_KP_Divide
: key_code
= '/'; break;
727 case GDK_F1
: key_code
= WXK_F1
; break;
728 case GDK_F2
: key_code
= WXK_F2
; break;
729 case GDK_F3
: key_code
= WXK_F3
; break;
730 case GDK_F4
: key_code
= WXK_F4
; break;
731 case GDK_F5
: key_code
= WXK_F5
; break;
732 case GDK_F6
: key_code
= WXK_F6
; break;
733 case GDK_F7
: key_code
= WXK_F7
; break;
734 case GDK_F8
: key_code
= WXK_F8
; break;
735 case GDK_F9
: key_code
= WXK_F9
; break;
736 case GDK_F10
: key_code
= WXK_F10
; break;
737 case GDK_F11
: key_code
= WXK_F11
; break;
738 case GDK_F12
: key_code
= WXK_F12
; break;
740 if (event
->length
== 1)
742 key_code
= (unsigned char)*event
->string
;
744 else if ((keysym
& 0xFF) == keysym
)
746 key_code
= (guint
)keysym
;
753 //-----------------------------------------------------------------------------
754 // "size_request" of m_widget
755 //-----------------------------------------------------------------------------
757 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
760 win
->GetSize( &w
, &h
);
764 requisition
->height
= h
;
765 requisition
->width
= w
;
768 //-----------------------------------------------------------------------------
769 // "expose_event" of m_wxwindow
770 //-----------------------------------------------------------------------------
773 extern GtkContainerClass
*pizza_parent_class
;
776 static int gtk_window_expose_callback( GtkWidget
*widget
,
777 GdkEventExpose
*gdk_event
,
783 wxapp_install_idle_handler();
786 if (win->GetName() == wxT("panel"))
788 wxPrintf( wxT("OnExpose from ") );
789 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
790 wxPrintf( win->GetClassInfo()->GetClassName() );
791 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
792 (int)gdk_event->area.y,
793 (int)gdk_event->area.width,
794 (int)gdk_event->area.height );
798 #ifndef __WXUNIVERSAL__
799 GtkPizza
*pizza
= GTK_PIZZA (widget
);
801 if (win
->GetThemeEnabled())
803 wxWindow
*parent
= win
->GetParent();
804 while (parent
&& !parent
->IsTopLevel())
805 parent
= parent
->GetParent();
809 gtk_paint_flat_box (parent
->m_widget
->style
,
820 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
822 gdk_event
->area
.width
,
823 gdk_event
->area
.height
);
825 // Actual redrawing takes place in idle time.
830 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
837 //-----------------------------------------------------------------------------
838 // "event" of m_wxwindow
839 //-----------------------------------------------------------------------------
841 // GTK thinks it is clever and filters out a certain amount of "unneeded"
842 // expose events. We need them, of course, so we override the main event
843 // procedure in GtkWidget by giving our own handler for all system events.
844 // There, we look for expose events ourselves whereas all other events are
847 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
848 GdkEventExpose
*event
,
851 if (event
->type
== GDK_EXPOSE
)
853 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
860 //-----------------------------------------------------------------------------
861 // "draw" of m_wxwindow
862 //-----------------------------------------------------------------------------
866 // This callback is a complete replacement of the gtk_pizza_draw() function,
867 // which is disabled.
869 static void gtk_window_draw_callback( GtkWidget
*widget
,
876 wxapp_install_idle_handler();
878 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
879 // there are no child windows.
880 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
881 (win
->GetChildren().GetCount() == 0))
887 if (win->GetName() == wxT("panel"))
889 wxPrintf( wxT("OnDraw from ") );
890 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
891 wxPrintf( win->GetClassInfo()->GetClassName() );
892 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
899 #ifndef __WXUNIVERSAL__
900 GtkPizza
*pizza
= GTK_PIZZA (widget
);
902 if (win
->GetThemeEnabled())
904 wxWindow
*parent
= win
->GetParent();
905 while (parent
&& !parent
->IsTopLevel())
906 parent
= parent
->GetParent();
910 gtk_paint_flat_box (parent
->m_widget
->style
,
921 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
922 (pizza
->clear_on_draw
))
924 gdk_window_clear_area( pizza
->bin_window
,
925 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
929 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
931 // Actual redrawing takes place in idle time.
935 #ifndef __WXUNIVERSAL__
936 // Redraw child widgets
937 GList
*children
= pizza
->children
;
940 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
941 children
= children
->next
;
943 GdkRectangle child_area
;
944 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
946 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
954 //-----------------------------------------------------------------------------
955 // "key_press_event" from any window
956 //-----------------------------------------------------------------------------
958 // turn on to see the key event codes on the console
959 #undef DEBUG_KEY_EVENTS
961 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
962 GdkEventKey
*gdk_event
,
968 wxapp_install_idle_handler();
970 if (!win
->m_hasVMT
) return FALSE
;
971 if (g_blockEventsOnDrag
) return FALSE
;
976 GdkModifierType state
;
977 if (gdk_event
->window
)
978 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
982 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
984 #ifdef DEBUG_KEY_EVENTS
985 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
986 #endif // DEBUG_KEY_EVENTS
988 /* sending unknown key events doesn't really make sense */
992 wxKeyEvent
event( wxEVT_KEY_DOWN
);
993 event
.SetTimestamp( gdk_event
->time
);
994 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
995 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
996 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
997 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
998 event
.m_keyCode
= key_code
;
999 event
.m_scanCode
= gdk_event
->keyval
;
1002 event
.SetEventObject( win
);
1003 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1008 wxWindowGTK
*ancestor
= win
;
1011 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1014 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1015 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1018 if (ancestor
->IsTopLevel())
1020 ancestor
= ancestor
->GetParent();
1023 #endif // wxUSE_ACCEL
1025 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1026 will only be sent if it is not in an accelerator table. */
1029 key_code
= map_to_wx_keysym( gdk_event
);
1033 #ifdef DEBUG_KEY_EVENTS
1034 wxPrintf(_T("Char event: %ld\n"), key_code
);
1035 #endif // DEBUG_KEY_EVENTS
1037 // reuse the ame event object, just change its type and use the
1038 // translated keycode instead of the raw one
1039 event
.SetEventType(wxEVT_CHAR
);
1040 event
.m_keyCode
= key_code
;
1042 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1046 /* win is a control: tab can be propagated up */
1048 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1049 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1050 // have this style, yet choose not to process this particular TAB in which
1051 // case TAB must still work as a navigational character
1053 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1055 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1057 wxNavigationKeyEvent new_event
;
1058 new_event
.SetEventObject( win
->GetParent() );
1059 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1060 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1061 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1062 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1063 new_event
.SetCurrentFocus( win
);
1064 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1067 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1069 (gdk_event
->keyval
== GDK_Escape
) )
1071 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1072 new_event
.SetEventObject( win
);
1073 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1077 #if 0 // (GTK_MINOR_VERSION > 0)
1078 /* Pressing F10 will activate the menu bar of the top frame. */
1080 (gdk_event
->keyval
== GDK_F10
) )
1082 wxWindowGTK
*ancestor
= win
;
1085 if (wxIsKindOf(ancestor
,wxFrame
))
1087 wxFrame
*frame
= (wxFrame
*) ancestor
;
1088 wxMenuBar
*menubar
= frame
->GetMenuBar();
1091 wxNode
*node
= menubar
->GetMenus().First();
1094 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1095 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1101 ancestor
= ancestor
->GetParent();
1108 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1115 //-----------------------------------------------------------------------------
1116 // "key_release_event" from any window
1117 //-----------------------------------------------------------------------------
1119 static gint
gtk_window_key_release_callback( GtkWidget
*widget
, GdkEventKey
*gdk_event
, wxWindowGTK
*win
)
1124 wxapp_install_idle_handler();
1126 if (!win
->m_hasVMT
) return FALSE
;
1127 if (g_blockEventsOnDrag
) return FALSE
;
1129 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
1131 #ifdef DEBUG_KEY_EVENTS
1132 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
1133 #endif // DEBUG_KEY_EVENTS
1135 /* sending unknown key events doesn't really make sense */
1136 if (key_code
== 0) return FALSE
;
1140 GdkModifierType state
;
1141 if (gdk_event
->window
)
1142 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1144 wxKeyEvent
event( wxEVT_KEY_UP
);
1145 event
.SetTimestamp( gdk_event
->time
);
1146 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1147 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1148 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1149 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1150 event
.m_keyCode
= key_code
;
1151 event
.m_scanCode
= gdk_event
->keyval
;
1154 event
.SetEventObject( win
);
1156 if (win
->GetEventHandler()->ProcessEvent( event
))
1158 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1165 // ============================================================================
1167 // ============================================================================
1169 // init wxMouseEvent with the info from gdk_event
1170 #define InitMouseEvent(win, event, gdk_event) \
1172 event.SetTimestamp( gdk_event->time ); \
1173 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1174 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1175 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1176 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1177 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1178 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1179 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1181 wxPoint pt = win->GetClientAreaOrigin(); \
1182 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1183 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1186 // ----------------------------------------------------------------------------
1187 // mouse event processing helper
1188 // ----------------------------------------------------------------------------
1190 static void AdjustEventButtonState(wxMouseEvent
& event
)
1192 // GDK reports the old state of the button for a button press event, but
1193 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1194 // for a LEFT_DOWN event, not FALSE, so we will invert
1195 // left/right/middleDown for the corresponding click events
1197 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1198 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1199 (event
.GetEventType() == wxEVT_LEFT_UP
))
1201 event
.m_leftDown
= !event
.m_leftDown
;
1205 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1206 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1207 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1209 event
.m_middleDown
= !event
.m_middleDown
;
1213 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1214 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1215 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1217 event
.m_rightDown
= !event
.m_rightDown
;
1222 //-----------------------------------------------------------------------------
1223 // "button_press_event"
1224 //-----------------------------------------------------------------------------
1226 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1231 wxapp_install_idle_handler();
1234 wxPrintf( wxT("1) OnButtonPress from ") );
1235 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1236 wxPrintf( win->GetClassInfo()->GetClassName() );
1237 wxPrintf( wxT(".\n") );
1239 if (!win
->m_hasVMT
) return FALSE
;
1240 if (g_blockEventsOnDrag
) return TRUE
;
1241 if (g_blockEventsOnScroll
) return TRUE
;
1243 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1245 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1247 gtk_widget_grab_focus( win
->m_wxwindow
);
1249 wxPrintf( wxT("GrabFocus from ") );
1250 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1251 wxPrintf( win->GetClassInfo()->GetClassName() );
1252 wxPrintf( wxT(".\n") );
1256 wxEventType event_type
= wxEVT_NULL
;
1258 if (gdk_event
->button
== 1)
1260 switch (gdk_event
->type
)
1262 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1263 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1267 else if (gdk_event
->button
== 2)
1269 switch (gdk_event
->type
)
1271 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1272 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1276 else if (gdk_event
->button
== 3)
1278 switch (gdk_event
->type
)
1280 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1281 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1286 if ( event_type
== wxEVT_NULL
)
1288 // unknown mouse button or click type
1292 wxMouseEvent
event( event_type
);
1293 InitMouseEvent( win
, event
, gdk_event
);
1295 AdjustEventButtonState(event
);
1297 // wxListBox actually get mouse events from the item
1299 if (win
->m_isListBox
)
1301 event
.m_x
+= widget
->allocation
.x
;
1302 event
.m_y
+= widget
->allocation
.y
;
1305 // Some control don't have their own X window and thus cannot get
1308 if (!g_captureWindow
)
1310 wxCoord x
= event
.m_x
;
1311 wxCoord y
= event
.m_y
;
1312 if (win
->m_wxwindow
)
1314 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1315 x
+= pizza
->xoffset
;
1316 y
+= pizza
->yoffset
;
1319 wxNode
*node
= win
->GetChildren().First();
1322 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1324 node
= node
->Next();
1325 if (!child
->IsShown())
1328 if (child
->m_isStaticBox
)
1330 // wxStaticBox is transparent in the box itself
1331 int xx1
= child
->m_x
;
1332 int yy1
= child
->m_y
;
1333 int xx2
= child
->m_x
+ child
->m_width
;
1334 int yy2
= child
->m_x
+ child
->m_height
;
1337 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1339 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1341 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1343 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1346 event
.m_x
-= child
->m_x
;
1347 event
.m_y
-= child
->m_y
;
1354 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1355 (child
->m_x
<= x
) &&
1356 (child
->m_y
<= y
) &&
1357 (child
->m_x
+child
->m_width
>= x
) &&
1358 (child
->m_y
+child
->m_height
>= y
))
1361 event
.m_x
-= child
->m_x
;
1362 event
.m_y
-= child
->m_y
;
1369 event
.SetEventObject( win
);
1371 gs_timeLastClick
= gdk_event
->time
;
1374 wxPrintf( wxT("2) OnButtonPress from ") );
1375 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1376 wxPrintf( win->GetClassInfo()->GetClassName() );
1377 wxPrintf( wxT(".\n") );
1380 if (win
->GetEventHandler()->ProcessEvent( event
))
1382 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1389 //-----------------------------------------------------------------------------
1390 // "button_release_event"
1391 //-----------------------------------------------------------------------------
1393 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1398 wxapp_install_idle_handler();
1400 if (!win
->m_hasVMT
) return FALSE
;
1401 if (g_blockEventsOnDrag
) return FALSE
;
1402 if (g_blockEventsOnScroll
) return FALSE
;
1404 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1407 printf( "OnButtonRelease from " );
1408 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1409 printf( win->GetClassInfo()->GetClassName() );
1413 wxEventType event_type
= wxEVT_NULL
;
1415 switch (gdk_event
->button
)
1417 case 1: event_type
= wxEVT_LEFT_UP
; break;
1418 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1419 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1420 default: return FALSE
;
1423 wxMouseEvent
event( event_type
);
1424 InitMouseEvent( win
, event
, gdk_event
);
1426 AdjustEventButtonState(event
);
1428 // wxListBox actually get mouse events from the item
1430 if (win
->m_isListBox
)
1432 event
.m_x
+= widget
->allocation
.x
;
1433 event
.m_y
+= widget
->allocation
.y
;
1436 // Some control don't have their own X window and thus cannot get
1439 if (!g_captureWindow
)
1441 wxCoord x
= event
.m_x
;
1442 wxCoord y
= event
.m_y
;
1443 if (win
->m_wxwindow
)
1445 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1446 x
+= pizza
->xoffset
;
1447 y
+= pizza
->yoffset
;
1450 wxNode
*node
= win
->GetChildren().First();
1453 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1455 node
= node
->Next();
1456 if (!child
->IsShown())
1459 if (child
->m_isStaticBox
)
1461 // wxStaticBox is transparent in the box itself
1462 int xx1
= child
->m_x
;
1463 int yy1
= child
->m_y
;
1464 int xx2
= child
->m_x
+ child
->m_width
;
1465 int yy2
= child
->m_x
+ child
->m_height
;
1468 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1470 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1472 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1474 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1477 event
.m_x
-= child
->m_x
;
1478 event
.m_y
-= child
->m_y
;
1485 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1486 (child
->m_x
<= x
) &&
1487 (child
->m_y
<= y
) &&
1488 (child
->m_x
+child
->m_width
>= x
) &&
1489 (child
->m_y
+child
->m_height
>= y
))
1492 event
.m_x
-= child
->m_x
;
1493 event
.m_y
-= child
->m_y
;
1500 event
.SetEventObject( win
);
1502 if (win
->GetEventHandler()->ProcessEvent( event
))
1504 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1511 //-----------------------------------------------------------------------------
1512 // "motion_notify_event"
1513 //-----------------------------------------------------------------------------
1515 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1516 GdkEventMotion
*gdk_event
,
1522 wxapp_install_idle_handler();
1524 if (!win
->m_hasVMT
) return FALSE
;
1525 if (g_blockEventsOnDrag
) return FALSE
;
1526 if (g_blockEventsOnScroll
) return FALSE
;
1528 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1530 if (gdk_event
->is_hint
)
1534 GdkModifierType state
;
1535 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1541 printf( "OnMotion from " );
1542 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1543 printf( win->GetClassInfo()->GetClassName() );
1547 wxMouseEvent
event( wxEVT_MOTION
);
1548 InitMouseEvent(win
, event
, gdk_event
);
1550 if ( g_captureWindow
)
1552 // synthetize a mouse enter or leave event if needed
1553 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1554 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1555 if ( hasMouse
!= g_captureWindowHasMouse
)
1557 // the mouse changed window
1558 g_captureWindowHasMouse
= hasMouse
;
1560 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1561 : wxEVT_LEAVE_WINDOW
);
1562 InitMouseEvent(win
, event
, gdk_event
);
1563 event
.SetEventObject(win
);
1564 win
->GetEventHandler()->ProcessEvent(event
);
1569 // Some control don't have their own X window and thus cannot get
1572 wxCoord x
= event
.m_x
;
1573 wxCoord y
= event
.m_y
;
1574 if (win
->m_wxwindow
)
1576 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1577 x
+= pizza
->xoffset
;
1578 y
+= pizza
->yoffset
;
1581 wxNode
*node
= win
->GetChildren().First();
1584 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1586 node
= node
->Next();
1587 if (!child
->IsShown())
1590 if (child
->m_isStaticBox
)
1592 // wxStaticBox is transparent in the box itself
1593 int xx1
= child
->m_x
;
1594 int yy1
= child
->m_y
;
1595 int xx2
= child
->m_x
+ child
->m_width
;
1596 int yy2
= child
->m_x
+ child
->m_height
;
1599 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1601 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1603 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1605 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1608 event
.m_x
-= child
->m_x
;
1609 event
.m_y
-= child
->m_y
;
1616 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1617 (child
->m_x
<= x
) &&
1618 (child
->m_y
<= y
) &&
1619 (child
->m_x
+child
->m_width
>= x
) &&
1620 (child
->m_y
+child
->m_height
>= y
))
1623 event
.m_x
-= child
->m_x
;
1624 event
.m_y
-= child
->m_y
;
1631 event
.SetEventObject( win
);
1633 if (win
->GetEventHandler()->ProcessEvent( event
))
1635 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1642 //-----------------------------------------------------------------------------
1644 //-----------------------------------------------------------------------------
1646 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1647 GdkEvent
*WXUNUSED(event
),
1653 wxapp_install_idle_handler();
1655 if (!win
->m_hasVMT
) return FALSE
;
1656 if (g_blockEventsOnDrag
) return FALSE
;
1658 switch ( g_sendActivateEvent
)
1661 // we've got focus from outside, synthetize wxActivateEvent
1662 g_sendActivateEvent
= 1;
1666 // another our window just lost focus, it was already ours before
1667 // - don't send any wxActivateEvent
1668 g_sendActivateEvent
= -1;
1673 g_focusWindow
= win
;
1676 wxLogDebug( wxT("OnSetFocus from %s\n"), win
->GetName().c_str() );
1679 // notify the parent keeping track of focus for the kbd navigation
1680 // purposes that we got it
1681 wxChildFocusEvent
eventFocus(win
);
1682 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1686 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1690 // caret needs to be informed about focus change
1691 wxCaret
*caret
= win
->GetCaret();
1694 caret
->OnSetFocus();
1696 #endif // wxUSE_CARET
1698 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1699 if ( active
!= g_activeFrame
)
1701 if ( g_activeFrame
)
1703 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1704 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1705 event
.SetEventObject(g_activeFrame
);
1706 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1709 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1710 g_activeFrame
= active
;
1711 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1712 event
.SetEventObject(g_activeFrame
);
1713 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1715 g_activeFrameLostFocus
= FALSE
;
1718 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1719 event
.SetEventObject( win
);
1721 if (win
->GetEventHandler()->ProcessEvent( event
))
1723 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1731 //-----------------------------------------------------------------------------
1732 // "focus_out_event"
1733 //-----------------------------------------------------------------------------
1735 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1740 wxapp_install_idle_handler();
1742 if (!win
->m_hasVMT
) return FALSE
;
1743 if (g_blockEventsOnDrag
) return FALSE
;
1746 wxLogDebug( wxT("OnKillFocus from %s"), win
->GetName().c_str() );
1749 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1751 // VZ: commenting this out because it does happen (although not easy
1752 // to reproduce, I only see it when using wxMiniFrame and not
1753 // always) and makes using Mahogany quite annoying
1755 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1756 wxT("unfocusing window that hasn't gained focus properly") )
1759 g_activeFrameLostFocus
= TRUE
;
1762 // if the focus goes out of our app alltogether, OnIdle() will send
1763 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1764 // g_sendActivateEvent to -1
1765 g_sendActivateEvent
= 0;
1767 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1771 g_focusWindow
= (wxWindowGTK
*)NULL
;
1779 // caret needs to be informed about focus change
1780 wxCaret
*caret
= win
->GetCaret();
1783 caret
->OnKillFocus();
1785 #endif // wxUSE_CARET
1787 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1788 event
.SetEventObject( win
);
1790 if (win
->GetEventHandler()->ProcessEvent( event
))
1792 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1799 //-----------------------------------------------------------------------------
1800 // "enter_notify_event"
1801 //-----------------------------------------------------------------------------
1803 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1808 wxapp_install_idle_handler();
1810 if (!win
->m_hasVMT
) return FALSE
;
1811 if (g_blockEventsOnDrag
) return FALSE
;
1813 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1815 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1816 event
.SetTimestamp( gdk_event
->time
);
1817 event
.SetEventObject( win
);
1821 GdkModifierType state
= (GdkModifierType
)0;
1823 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1825 InitMouseEvent(win
, event
, gdk_event
);
1826 wxPoint pt
= win
->GetClientAreaOrigin();
1827 event
.m_x
= x
+ pt
.x
;
1828 event
.m_y
= y
+ pt
.y
;
1830 if (win
->GetEventHandler()->ProcessEvent( event
))
1832 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1839 //-----------------------------------------------------------------------------
1840 // "leave_notify_event"
1841 //-----------------------------------------------------------------------------
1843 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1848 wxapp_install_idle_handler();
1850 if (!win
->m_hasVMT
) return FALSE
;
1851 if (g_blockEventsOnDrag
) return FALSE
;
1853 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1855 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1856 event
.SetTimestamp( gdk_event
->time
);
1857 event
.SetEventObject( win
);
1861 GdkModifierType state
= (GdkModifierType
)0;
1863 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1865 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
);
1866 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
);
1867 event
.m_altDown
= (state
& GDK_MOD1_MASK
);
1868 event
.m_metaDown
= (state
& GDK_MOD2_MASK
);
1869 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
);
1870 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
);
1871 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
);
1873 wxPoint pt
= win
->GetClientAreaOrigin();
1874 event
.m_x
= x
+ pt
.x
;
1875 event
.m_y
= y
+ pt
.y
;
1877 if (win
->GetEventHandler()->ProcessEvent( event
))
1879 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1886 //-----------------------------------------------------------------------------
1887 // "value_changed" from m_vAdjust
1888 //-----------------------------------------------------------------------------
1890 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1897 wxapp_install_idle_handler();
1899 if (g_blockEventsOnDrag
) return;
1901 if (!win
->m_hasVMT
) return;
1903 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1904 if (fabs(diff
) < 0.2) return;
1906 win
->m_oldVerticalPos
= adjust
->value
;
1908 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1910 int value
= (int)(adjust
->value
+0.5);
1912 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1913 event
.SetEventObject( win
);
1914 win
->GetEventHandler()->ProcessEvent( event
);
1917 //-----------------------------------------------------------------------------
1918 // "value_changed" from m_hAdjust
1919 //-----------------------------------------------------------------------------
1921 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1928 wxapp_install_idle_handler();
1930 if (g_blockEventsOnDrag
) return;
1931 if (!win
->m_hasVMT
) return;
1933 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1934 if (fabs(diff
) < 0.2) return;
1936 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1938 win
->m_oldHorizontalPos
= adjust
->value
;
1940 int value
= (int)(adjust
->value
+0.5);
1942 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1943 event
.SetEventObject( win
);
1944 win
->GetEventHandler()->ProcessEvent( event
);
1947 //-----------------------------------------------------------------------------
1948 // "button_press_event" from scrollbar
1949 //-----------------------------------------------------------------------------
1951 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1952 GdkEventButton
*gdk_event
,
1958 wxapp_install_idle_handler();
1961 g_blockEventsOnScroll
= TRUE
;
1963 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1965 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1971 //-----------------------------------------------------------------------------
1972 // "button_release_event" from scrollbar
1973 //-----------------------------------------------------------------------------
1975 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1976 GdkEventButton
*WXUNUSED(gdk_event
),
1981 // don't test here as we can release the mouse while being over
1982 // a different window than the slider
1984 // if (gdk_event->window != widget->slider) return FALSE;
1986 g_blockEventsOnScroll
= FALSE
;
1988 if (win
->m_isScrolling
)
1990 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1994 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
1995 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
1997 value
= (int)(win
->m_hAdjust
->value
+0.5);
2000 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2002 value
= (int)(win
->m_vAdjust
->value
+0.5);
2006 wxScrollWinEvent
event( command
, value
, dir
);
2007 event
.SetEventObject( win
);
2008 win
->GetEventHandler()->ProcessEvent( event
);
2011 win
->m_isScrolling
= FALSE
;
2016 // ----------------------------------------------------------------------------
2017 // this wxWindowBase function is implemented here (in platform-specific file)
2018 // because it is static and so couldn't be made virtual
2019 // ----------------------------------------------------------------------------
2021 wxWindow
*wxWindowBase::FindFocus()
2023 // the cast is necessary when we compile in wxUniversal mode
2024 return (wxWindow
*)g_focusWindow
;
2027 //-----------------------------------------------------------------------------
2028 // "realize" from m_widget
2029 //-----------------------------------------------------------------------------
2031 /* We cannot set colours and fonts before the widget has
2032 been realized, so we do this directly after realization. */
2035 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2040 wxapp_install_idle_handler();
2042 if (win
->m_delayedBackgroundColour
)
2043 win
->SetBackgroundColour( win
->GetBackgroundColour() );
2045 if (win
->m_delayedForegroundColour
)
2046 win
->SetForegroundColour( win
->GetForegroundColour() );
2048 wxWindowCreateEvent
event( win
);
2049 event
.SetEventObject( win
);
2050 win
->GetEventHandler()->ProcessEvent( event
);
2055 //-----------------------------------------------------------------------------
2057 //-----------------------------------------------------------------------------
2060 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2061 GtkAllocation
*WXUNUSED(alloc
),
2065 wxapp_install_idle_handler();
2067 if (!win
->m_hasScrolling
) return;
2069 int client_width
= 0;
2070 int client_height
= 0;
2071 win
->GetClientSize( &client_width
, &client_height
);
2072 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2075 win
->m_oldClientWidth
= client_width
;
2076 win
->m_oldClientHeight
= client_height
;
2078 if (!win
->m_nativeSizeEvent
)
2080 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2081 event
.SetEventObject( win
);
2082 win
->GetEventHandler()->ProcessEvent( event
);
2088 #define WXUNUSED_UNLESS_XIM(param) param
2090 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2093 /* Resize XIM window */
2096 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2097 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2098 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2101 wxapp_install_idle_handler();
2107 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2111 gdk_window_get_size (widget
->window
, &width
, &height
);
2112 win
->m_icattr
->preedit_area
.width
= width
;
2113 win
->m_icattr
->preedit_area
.height
= height
;
2114 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2119 //-----------------------------------------------------------------------------
2120 // "realize" from m_wxwindow
2121 //-----------------------------------------------------------------------------
2123 /* Initialize XIM support */
2126 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2127 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2130 wxapp_install_idle_handler();
2133 if (win
->m_ic
) return FALSE
;
2134 if (!widget
) return FALSE
;
2135 if (!gdk_im_ready()) return FALSE
;
2137 win
->m_icattr
= gdk_ic_attr_new();
2138 if (!win
->m_icattr
) return FALSE
;
2142 GdkColormap
*colormap
;
2143 GdkICAttr
*attr
= win
->m_icattr
;
2144 unsigned attrmask
= GDK_IC_ALL_REQ
;
2146 GdkIMStyle supported_style
= (GdkIMStyle
)
2147 (GDK_IM_PREEDIT_NONE
|
2148 GDK_IM_PREEDIT_NOTHING
|
2149 GDK_IM_PREEDIT_POSITION
|
2150 GDK_IM_STATUS_NONE
|
2151 GDK_IM_STATUS_NOTHING
);
2153 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2154 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2156 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2157 attr
->client_window
= widget
->window
;
2159 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2160 gtk_widget_get_default_colormap ())
2162 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2163 attr
->preedit_colormap
= colormap
;
2166 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2167 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2168 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2169 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2171 switch (style
& GDK_IM_PREEDIT_MASK
)
2173 case GDK_IM_PREEDIT_POSITION
:
2174 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2176 g_warning ("over-the-spot style requires fontset");
2180 gdk_window_get_size (widget
->window
, &width
, &height
);
2182 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2183 attr
->spot_location
.x
= 0;
2184 attr
->spot_location
.y
= height
;
2185 attr
->preedit_area
.x
= 0;
2186 attr
->preedit_area
.y
= 0;
2187 attr
->preedit_area
.width
= width
;
2188 attr
->preedit_area
.height
= height
;
2189 attr
->preedit_fontset
= widget
->style
->font
;
2194 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2196 if (win
->m_ic
== NULL
)
2197 g_warning ("Can't create input context.");
2200 mask
= gdk_window_get_events (widget
->window
);
2201 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2202 gdk_window_set_events (widget
->window
, mask
);
2204 if (GTK_WIDGET_HAS_FOCUS(widget
))
2205 gdk_im_begin (win
->m_ic
, widget
->window
);
2212 //-----------------------------------------------------------------------------
2213 // InsertChild for wxWindowGTK.
2214 //-----------------------------------------------------------------------------
2216 /* Callback for wxWindowGTK. This very strange beast has to be used because
2217 * C++ has no virtual methods in a constructor. We have to emulate a
2218 * virtual function here as wxNotebook requires a different way to insert
2219 * a child in it. I had opted for creating a wxNotebookPage window class
2220 * which would have made this superfluous (such in the MDI window system),
2221 * but no-one was listening to me... */
2223 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2225 /* the window might have been scrolled already, do we
2226 have to adapt the position */
2227 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2228 child
->m_x
+= pizza
->xoffset
;
2229 child
->m_y
+= pizza
->yoffset
;
2231 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2232 GTK_WIDGET(child
->m_widget
),
2239 //-----------------------------------------------------------------------------
2241 //-----------------------------------------------------------------------------
2243 wxWindow
*wxGetActiveWindow()
2245 // the cast is necessary when we compile in wxUniversal mode
2246 return (wxWindow
*)g_focusWindow
;
2249 //-----------------------------------------------------------------------------
2251 //-----------------------------------------------------------------------------
2253 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2255 #ifdef __WXUNIVERSAL__
2256 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2258 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2259 #endif // __WXUNIVERSAL__/__WXGTK__
2261 void wxWindowGTK::Init()
2267 m_widget
= (GtkWidget
*) NULL
;
2268 m_wxwindow
= (GtkWidget
*) NULL
;
2269 m_focusWidget
= (GtkWidget
*) NULL
;
2279 m_needParent
= TRUE
;
2280 m_isBeingDeleted
= FALSE
;
2283 m_nativeSizeEvent
= FALSE
;
2285 m_hasScrolling
= FALSE
;
2286 m_isScrolling
= FALSE
;
2288 m_hAdjust
= (GtkAdjustment
*) NULL
;
2289 m_vAdjust
= (GtkAdjustment
*) NULL
;
2290 m_oldHorizontalPos
= 0.0;
2291 m_oldVerticalPos
= 0.0;
2294 m_widgetStyle
= (GtkStyle
*) NULL
;
2296 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2298 m_isStaticBox
= FALSE
;
2299 m_isRadioButton
= FALSE
;
2300 m_isListBox
= FALSE
;
2302 m_acceptsFocus
= FALSE
;
2304 m_clipPaintRegion
= FALSE
;
2306 m_cursor
= *wxSTANDARD_CURSOR
;
2308 m_delayedForegroundColour
= FALSE
;
2309 m_delayedBackgroundColour
= FALSE
;
2312 m_ic
= (GdkIC
*) NULL
;
2313 m_icattr
= (GdkICAttr
*) NULL
;
2317 wxWindowGTK::wxWindowGTK()
2322 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2327 const wxString
&name
)
2331 Create( parent
, id
, pos
, size
, style
, name
);
2334 bool wxWindowGTK::Create( wxWindow
*parent
,
2339 const wxString
&name
)
2341 if (!PreCreation( parent
, pos
, size
) ||
2342 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2344 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2348 m_insertCallback
= wxInsertChildInWindow
;
2350 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2351 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2353 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2355 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2356 scroll_class
->scrollbar_spacing
= 0;
2358 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2360 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2361 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2363 m_wxwindow
= gtk_pizza_new();
2365 #ifndef __WXUNIVERSAL__
2366 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2368 if (HasFlag(wxRAISED_BORDER
))
2370 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2372 else if (HasFlag(wxSUNKEN_BORDER
))
2374 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2376 else if (HasFlag(wxSIMPLE_BORDER
))
2378 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2382 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2384 #endif // __WXUNIVERSAL__
2386 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2388 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2389 m_acceptsFocus
= TRUE
;
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 );
2543 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2544 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2546 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2548 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2549 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2552 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2556 // these are called when the "sunken" or "raised" borders are drawn
2557 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2558 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2561 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2562 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2568 if (m_focusWidget
== NULL
)
2569 m_focusWidget
= m_widget
;
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
);
2686 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2688 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2689 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2690 if (width
!= -1) m_width
= width
;
2691 if (height
!= -1) m_height
= height
;
2695 m_x
= x
+ pizza
->xoffset
;
2696 m_y
= y
+ pizza
->yoffset
;
2701 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2703 if (width
== -1) m_width
= 80;
2706 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2708 if (height
== -1) m_height
= 26;
2711 int minWidth
= GetMinWidth(),
2712 minHeight
= GetMinHeight(),
2713 maxWidth
= GetMaxWidth(),
2714 maxHeight
= GetMaxHeight();
2716 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2717 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2718 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2719 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2722 int bottom_border
= 0;
2725 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2727 /* the default button has a border around it */
2733 DoMoveWindow( m_x
-border
,
2736 m_height
+border
+bottom_border
);
2741 /* Sometimes the client area changes size without the
2742 whole windows's size changing, but if the whole
2743 windows's size doesn't change, no wxSizeEvent will
2744 normally be sent. Here we add an extra test if
2745 the client test has been changed and this will
2747 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2751 wxPrintf( "OnSize sent from " );
2752 if (GetClassInfo() && GetClassInfo()->GetClassName())
2753 wxPrintf( GetClassInfo()->GetClassName() );
2754 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2757 if (!m_nativeSizeEvent
)
2759 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2760 event
.SetEventObject( this );
2761 GetEventHandler()->ProcessEvent( event
);
2767 void wxWindowGTK::OnInternalIdle()
2769 // Update invalidated regions.
2772 // Synthetize activate events.
2773 if ( g_sendActivateEvent
!= -1 )
2775 bool activate
= g_sendActivateEvent
!= 0;
2778 g_sendActivateEvent
= -1;
2780 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2783 if ( g_activeFrameLostFocus
)
2785 if ( g_activeFrame
)
2787 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2788 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2789 event
.SetEventObject(g_activeFrame
);
2790 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2791 g_activeFrame
= NULL
;
2793 g_activeFrameLostFocus
= FALSE
;
2796 wxCursor cursor
= m_cursor
;
2797 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2801 /* I now set the cursor anew in every OnInternalIdle call
2802 as setting the cursor in a parent window also effects the
2803 windows above so that checking for the current cursor is
2808 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2810 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2812 if (!g_globalCursor
.Ok())
2813 cursor
= *wxSTANDARD_CURSOR
;
2815 window
= m_widget
->window
;
2816 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2817 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2823 GdkWindow
*window
= m_widget
->window
;
2824 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2825 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2833 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2835 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2837 if (width
) (*width
) = m_width
;
2838 if (height
) (*height
) = m_height
;
2841 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2843 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2847 SetSize( width
, height
);
2854 #ifndef __WXUNIVERSAL__
2855 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2857 /* when using GTK 1.2 we set the shadow border size to 2 */
2861 if (HasFlag(wxSIMPLE_BORDER
))
2863 /* when using GTK 1.2 we set the simple border size to 1 */
2867 #endif // __WXUNIVERSAL__
2871 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2873 GtkRequisition vscroll_req
;
2874 vscroll_req
.width
= 2;
2875 vscroll_req
.height
= 2;
2876 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2877 (scroll_window
->vscrollbar
, &vscroll_req
);
2879 GtkRequisition hscroll_req
;
2880 hscroll_req
.width
= 2;
2881 hscroll_req
.height
= 2;
2882 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2883 (scroll_window
->hscrollbar
, &hscroll_req
);
2885 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2887 if (scroll_window
->vscrollbar_visible
)
2889 dw
+= vscroll_req
.width
;
2890 dw
+= scroll_class
->scrollbar_spacing
;
2893 if (scroll_window
->hscrollbar_visible
)
2895 dh
+= hscroll_req
.height
;
2896 dh
+= scroll_class
->scrollbar_spacing
;
2900 SetSize( width
+dw
, height
+dh
);
2904 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2906 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2910 if (width
) (*width
) = m_width
;
2911 if (height
) (*height
) = m_height
;
2918 #ifndef __WXUNIVERSAL__
2919 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2921 /* when using GTK 1.2 we set the shadow border size to 2 */
2925 if (HasFlag(wxSIMPLE_BORDER
))
2927 /* when using GTK 1.2 we set the simple border size to 1 */
2931 #endif // __WXUNIVERSAL__
2935 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2937 GtkRequisition vscroll_req
;
2938 vscroll_req
.width
= 2;
2939 vscroll_req
.height
= 2;
2940 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2941 (scroll_window
->vscrollbar
, &vscroll_req
);
2943 GtkRequisition hscroll_req
;
2944 hscroll_req
.width
= 2;
2945 hscroll_req
.height
= 2;
2946 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2947 (scroll_window
->hscrollbar
, &hscroll_req
);
2949 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2951 if (scroll_window
->vscrollbar_visible
)
2953 dw
+= vscroll_req
.width
;
2954 dw
+= scroll_class
->scrollbar_spacing
;
2957 if (scroll_window
->hscrollbar_visible
)
2959 dh
+= hscroll_req
.height
;
2960 dh
+= scroll_class
->scrollbar_spacing
;
2964 if (width
) (*width
) = m_width
- dw
;
2965 if (height
) (*height
) = m_height
- dh
;
2969 printf( "GetClientSize, name %s ", GetName().c_str() );
2970 if (width) printf( " width = %d", (*width) );
2971 if (height) printf( " height = %d", (*height) );
2976 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2978 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2982 if (m_parent
&& m_parent
->m_wxwindow
)
2984 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2985 dx
= pizza
->xoffset
;
2986 dy
= pizza
->yoffset
;
2989 if (x
) (*x
) = m_x
- dx
;
2990 if (y
) (*y
) = m_y
- dy
;
2993 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
2995 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2997 if (!m_widget
->window
) return;
2999 GdkWindow
*source
= (GdkWindow
*) NULL
;
3001 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3003 source
= m_widget
->window
;
3007 gdk_window_get_origin( source
, &org_x
, &org_y
);
3011 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3013 org_x
+= m_widget
->allocation
.x
;
3014 org_y
+= m_widget
->allocation
.y
;
3022 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3024 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3026 if (!m_widget
->window
) return;
3028 GdkWindow
*source
= (GdkWindow
*) NULL
;
3030 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3032 source
= m_widget
->window
;
3036 gdk_window_get_origin( source
, &org_x
, &org_y
);
3040 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3042 org_x
+= m_widget
->allocation
.x
;
3043 org_y
+= m_widget
->allocation
.y
;
3051 bool wxWindowGTK::Show( bool show
)
3053 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3055 if (!wxWindowBase::Show(show
))
3062 gtk_widget_show( m_widget
);
3064 gtk_widget_hide( m_widget
);
3069 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3071 win
->OnParentEnable(enable
);
3073 // Recurse, so that children have the opportunity to Do The Right Thing
3074 // and reset colours that have been messed up by a parent's (really ancestor's)
3076 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3078 node
= node
->GetNext() )
3080 wxWindow
*child
= node
->GetData();
3081 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3082 wxWindowNotifyEnable(child
, enable
);
3086 bool wxWindowGTK::Enable( bool enable
)
3088 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3090 if (!wxWindowBase::Enable(enable
))
3096 gtk_widget_set_sensitive( m_widget
, enable
);
3098 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3100 wxWindowNotifyEnable(this, enable
);
3105 int wxWindowGTK::GetCharHeight() const
3107 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3109 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3111 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3113 return font
->ascent
+ font
->descent
;
3116 int wxWindowGTK::GetCharWidth() const
3118 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3120 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3122 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3124 return gdk_string_width( font
, "H" );
3127 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3131 int *externalLeading
,
3132 const wxFont
*theFont
) const
3134 wxFont fontToUse
= m_font
;
3135 if (theFont
) fontToUse
= *theFont
;
3137 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3139 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3140 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3141 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3142 if (descent
) (*descent
) = font
->descent
;
3143 if (externalLeading
) (*externalLeading
) = 0; // ??
3146 void wxWindowGTK::SetFocus()
3148 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3151 wxPrintf( "SetFocus from " );
3152 if (GetClassInfo() && GetClassInfo()->GetClassName())
3153 wxPrintf( GetClassInfo()->GetClassName() );
3159 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3161 gtk_widget_grab_focus (m_wxwindow
);
3166 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3168 gtk_widget_grab_focus (m_widget
);
3170 else if (GTK_IS_CONTAINER(m_widget
))
3172 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3181 bool wxWindowGTK::AcceptsFocus() const
3183 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3186 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3188 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3190 wxWindowGTK
*oldParent
= m_parent
,
3191 *newParent
= (wxWindowGTK
*)newParentBase
;
3193 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3195 if ( !wxWindowBase::Reparent(newParent
) )
3198 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3200 /* prevent GTK from deleting the widget arbitrarily */
3201 gtk_widget_ref( m_widget
);
3205 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3208 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3212 /* insert GTK representation */
3213 (*(newParent
->m_insertCallback
))(newParent
, this);
3216 /* reverse: prevent GTK from deleting the widget arbitrarily */
3217 gtk_widget_unref( m_widget
);
3222 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3224 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3226 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3228 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3233 /* insert GTK representation */
3234 (*m_insertCallback
)(this, child
);
3237 void wxWindowGTK::Raise()
3239 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3241 if (!m_widget
->window
) return;
3243 gdk_window_raise( m_widget
->window
);
3246 void wxWindowGTK::Lower()
3248 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3250 if (!m_widget
->window
) return;
3252 gdk_window_lower( m_widget
->window
);
3255 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3257 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3259 if (cursor
== m_cursor
)
3263 wxapp_install_idle_handler();
3265 if (cursor
== wxNullCursor
)
3266 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3268 return wxWindowBase::SetCursor( cursor
);
3271 void wxWindowGTK::WarpPointer( int x
, int y
)
3273 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3275 // We provide this function ourselves as it is
3276 // missing in GDK (top of this file).
3278 GdkWindow
*window
= (GdkWindow
*) NULL
;
3280 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3282 window
= GetConnectWidget()->window
;
3285 gdk_window_warp_pointer( window
, x
, y
);
3288 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3290 if (!m_widget
) return;
3291 if (!m_widget
->window
) return;
3294 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3298 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3299 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3303 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3304 m_clearRegion
.Clear();
3305 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3313 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3314 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3318 GdkRectangle gdk_rect
;
3319 gdk_rect
.x
= rect
->x
;
3320 gdk_rect
.y
= rect
->y
;
3321 gdk_rect
.width
= rect
->width
;
3322 gdk_rect
.height
= rect
->height
;
3323 gtk_widget_draw( m_widget
, &gdk_rect
);
3330 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3331 m_updateRegion
.Clear();
3332 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3336 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3344 GdkRectangle gdk_rect
;
3345 gdk_rect
.x
= rect
->x
;
3346 gdk_rect
.y
= rect
->y
;
3347 gdk_rect
.width
= rect
->width
;
3348 gdk_rect
.height
= rect
->height
;
3349 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3353 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3359 void wxWindowGTK::Update()
3362 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3363 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3366 if (!m_updateRegion
.IsEmpty())
3367 GtkSendPaintEvents();
3370 void wxWindowGTK::GtkSendPaintEvents()
3374 m_clearRegion
.Clear();
3375 m_updateRegion
.Clear();
3379 m_clipPaintRegion
= TRUE
;
3381 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3383 wxWindowDC
dc( (wxWindow
*)this );
3384 dc
.SetClippingRegion( m_clearRegion
);
3386 wxEraseEvent
erase_event( GetId(), &dc
);
3387 erase_event
.SetEventObject( this );
3389 if (!GetEventHandler()->ProcessEvent(erase_event
))
3391 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3393 wxRegionIterator
upd( m_clearRegion
);
3396 gdk_draw_rectangle( GTK_PIZZA(m_wxwindow
)->bin_window
, g_eraseGC
, 0,
3397 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3401 m_clearRegion
.Clear();
3404 wxNcPaintEvent
nc_paint_event( GetId() );
3405 nc_paint_event
.SetEventObject( this );
3406 GetEventHandler()->ProcessEvent( nc_paint_event
);
3408 wxPaintEvent
paint_event( GetId() );
3409 paint_event
.SetEventObject( this );
3410 GetEventHandler()->ProcessEvent( paint_event
);
3412 m_clipPaintRegion
= FALSE
;
3414 #ifndef __WXUNIVERSAL__
3416 // The following code will result in all window-less widgets
3417 // being redrawn because the wxWindows class is allowed to
3418 // paint over the window-less widgets.
3420 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3422 GList
*children
= pizza
->children
;
3425 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3426 children
= children
->next
;
3428 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3429 GTK_WIDGET_DRAWABLE (child
->widget
))
3431 // Get intersection of widget area and update region
3432 wxRegion
region( m_updateRegion
);
3434 GdkEventExpose gdk_event
;
3435 gdk_event
.type
= GDK_EXPOSE
;
3436 gdk_event
.window
= pizza
->bin_window
;
3437 gdk_event
.count
= 0;
3439 wxRegionIterator
upd( m_updateRegion
);
3443 rect
.x
= upd
.GetX();
3444 rect
.y
= upd
.GetY();
3445 rect
.width
= upd
.GetWidth();
3446 rect
.height
= upd
.GetHeight();
3448 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3450 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3460 m_updateRegion
.Clear();
3463 void wxWindowGTK::Clear()
3465 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3467 if (!m_widget
->window
) return;
3469 if (m_wxwindow
&& m_wxwindow
->window
)
3471 // gdk_window_clear( m_wxwindow->window );
3476 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3478 wxWindowBase::DoSetToolTip(tip
);
3481 m_tooltip
->Apply( (wxWindow
*)this );
3484 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3486 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3488 #endif // wxUSE_TOOLTIPS
3490 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3492 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3494 if (!wxWindowBase::SetBackgroundColour(colour
))
3496 // don't leave if the GTK widget has just
3498 if (!m_delayedBackgroundColour
) return FALSE
;
3501 GdkWindow
*window
= (GdkWindow
*) NULL
;
3503 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3505 window
= GetConnectWidget()->window
;
3509 // indicate that a new style has been set
3510 // but it couldn't get applied as the
3511 // widget hasn't been realized yet.
3512 m_delayedBackgroundColour
= TRUE
;
3516 (m_wxwindow
->window
) &&
3517 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3519 /* wxMSW doesn't clear the window here. I don't do that either to
3520 provide compatibility. call Clear() to do the job. */
3522 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3523 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3531 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3533 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3535 if (!wxWindowBase::SetForegroundColour(colour
))
3537 // don't leave if the GTK widget has just
3539 if (!m_delayedForegroundColour
) return FALSE
;
3542 GdkWindow
*window
= (GdkWindow
*) NULL
;
3544 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3546 window
= GetConnectWidget()->window
;
3550 // indicate that a new style has been set
3551 // but it couldn't get applied as the
3552 // widget hasn't been realized yet.
3553 m_delayedForegroundColour
= TRUE
;
3561 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3565 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3567 // FIXME: no more klass in 2.0
3569 remake
->klass
= m_widgetStyle
->klass
;
3572 gtk_style_unref( m_widgetStyle
);
3573 m_widgetStyle
= remake
;
3577 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3580 def
= gtk_widget_get_default_style();
3582 m_widgetStyle
= gtk_style_copy( def
);
3584 // FIXME: no more klass in 2.0
3586 m_widgetStyle
->klass
= def
->klass
;
3590 return m_widgetStyle
;
3593 void wxWindowGTK::SetWidgetStyle()
3595 #if DISABLE_STYLE_IF_BROKEN_THEME
3596 if (m_widget
->style
->engine_data
)
3598 static bool s_warningPrinted
= FALSE
;
3599 if (!s_warningPrinted
)
3601 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3602 s_warningPrinted
= TRUE
;
3604 m_widgetStyle
= m_widget
->style
;
3609 GtkStyle
*style
= GetWidgetStyle();
3611 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3613 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3616 if (m_foregroundColour
.Ok())
3618 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3619 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3621 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3622 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3623 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3627 // Try to restore the gtk default style. This is still a little
3628 // oversimplified for what is probably really needed here for controls
3629 // other than buttons, but is better than not being able to (re)set a
3630 // control's foreground colour to *wxBLACK -- RL
3631 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3634 def
= gtk_widget_get_default_style();
3636 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3637 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3638 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3642 if (m_backgroundColour
.Ok())
3644 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3645 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3647 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3648 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3649 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3650 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3651 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3652 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3653 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3654 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3658 // Try to restore the gtk default style. This is still a little
3659 // oversimplified for what is probably really needed here for controls
3660 // other than buttons, but is better than not being able to (re)set a
3661 // control's background colour to default grey and means resetting a
3662 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3664 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3667 def
= gtk_widget_get_default_style();
3669 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3670 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3671 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3672 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3673 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3674 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3675 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3676 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3681 void wxWindowGTK::ApplyWidgetStyle()
3685 //-----------------------------------------------------------------------------
3686 // Pop-up menu stuff
3687 //-----------------------------------------------------------------------------
3689 #if wxUSE_MENUS_NATIVE
3692 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3694 *is_waiting
= FALSE
;
3697 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3699 menu
->SetInvokingWindow( win
);
3700 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3703 wxMenuItem
*menuitem
= node
->GetData();
3704 if (menuitem
->IsSubMenu())
3706 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3709 node
= node
->GetNext();
3713 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3714 // wxPopupMenuPositionCallback()
3716 // should be safe even in the MT case as the user can hardly popup 2 menus
3717 // simultaneously, can he?
3718 static gint gs_pop_x
= 0;
3719 static gint gs_pop_y
= 0;
3721 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3724 gboolean
* WXUNUSED(whatever
),
3726 gpointer
WXUNUSED(user_data
) )
3728 // ensure that the menu appears entirely on screen
3730 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3732 wxSize sizeScreen
= wxGetDisplaySize();
3734 gint xmax
= sizeScreen
.x
- req
.width
,
3735 ymax
= sizeScreen
.y
- req
.height
;
3737 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3738 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3741 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3743 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3745 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3747 SetInvokingWindow( menu
, this );
3753 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3755 bool is_waiting
= TRUE
;
3757 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3759 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3760 (gpointer
)&is_waiting
);
3763 GTK_MENU(menu
->m_menu
),
3764 (GtkWidget
*) NULL
, // parent menu shell
3765 (GtkWidget
*) NULL
, // parent menu item
3766 wxPopupMenuPositionCallback
, // function to position it
3767 NULL
, // client data
3768 0, // button used to activate it
3769 gs_timeLastClick
// the time of activation
3774 while (gtk_events_pending())
3775 gtk_main_iteration();
3781 #endif // wxUSE_MENUS_NATIVE
3783 #if wxUSE_DRAG_AND_DROP
3785 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3787 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3789 GtkWidget
*dnd_widget
= GetConnectWidget();
3791 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3793 if (m_dropTarget
) delete m_dropTarget
;
3794 m_dropTarget
= dropTarget
;
3796 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3799 #endif // wxUSE_DRAG_AND_DROP
3801 GtkWidget
* wxWindowGTK::GetConnectWidget()
3803 GtkWidget
*connect_widget
= m_widget
;
3804 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3806 return connect_widget
;
3809 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3812 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3814 return (window
== m_widget
->window
);
3817 bool wxWindowGTK::SetFont( const wxFont
&font
)
3819 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3821 if (!wxWindowBase::SetFont(font
))
3826 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3827 if ( sysbg
== m_backgroundColour
)
3829 m_backgroundColour
= wxNullColour
;
3831 m_backgroundColour
= sysbg
;
3841 void wxWindowGTK::DoCaptureMouse()
3843 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3845 GdkWindow
*window
= (GdkWindow
*) NULL
;
3847 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3849 window
= GetConnectWidget()->window
;
3851 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3853 wxCursor
* cursor
= & m_cursor
;
3855 cursor
= wxSTANDARD_CURSOR
;
3857 gdk_pointer_grab( window
, FALSE
,
3859 (GDK_BUTTON_PRESS_MASK
|
3860 GDK_BUTTON_RELEASE_MASK
|
3861 GDK_POINTER_MOTION_HINT_MASK
|
3862 GDK_POINTER_MOTION_MASK
),
3864 cursor
->GetCursor(),
3865 (guint32
)GDK_CURRENT_TIME
);
3866 g_captureWindow
= this;
3867 g_captureWindowHasMouse
= TRUE
;
3870 void wxWindowGTK::DoReleaseMouse()
3872 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3874 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3876 g_captureWindow
= (wxWindowGTK
*) NULL
;
3878 GdkWindow
*window
= (GdkWindow
*) NULL
;
3880 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3882 window
= GetConnectWidget()->window
;
3887 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3891 wxWindow
*wxWindowBase::GetCapture()
3893 return (wxWindow
*)g_captureWindow
;
3896 bool wxWindowGTK::IsRetained() const
3901 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3902 int range
, bool refresh
)
3904 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3906 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3908 m_hasScrolling
= TRUE
;
3910 if (orient
== wxHORIZONTAL
)
3912 float fpos
= (float)pos
;
3913 float frange
= (float)range
;
3914 float fthumb
= (float)thumbVisible
;
3915 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3916 if (fpos
< 0.0) fpos
= 0.0;
3918 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
3919 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
3921 SetScrollPos( orient
, pos
, refresh
);
3925 m_oldHorizontalPos
= fpos
;
3927 m_hAdjust
->lower
= 0.0;
3928 m_hAdjust
->upper
= frange
;
3929 m_hAdjust
->value
= fpos
;
3930 m_hAdjust
->step_increment
= 1.0;
3931 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3932 m_hAdjust
->page_size
= fthumb
;
3936 float fpos
= (float)pos
;
3937 float frange
= (float)range
;
3938 float fthumb
= (float)thumbVisible
;
3939 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3940 if (fpos
< 0.0) fpos
= 0.0;
3942 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
3943 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
3945 SetScrollPos( orient
, pos
, refresh
);
3949 m_oldVerticalPos
= fpos
;
3951 m_vAdjust
->lower
= 0.0;
3952 m_vAdjust
->upper
= frange
;
3953 m_vAdjust
->value
= fpos
;
3954 m_vAdjust
->step_increment
= 1.0;
3955 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3956 m_vAdjust
->page_size
= fthumb
;
3959 if (orient
== wxHORIZONTAL
)
3960 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
3962 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
3965 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
3967 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3969 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3971 if (orient
== wxHORIZONTAL
)
3973 float fpos
= (float)pos
;
3974 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
3975 if (fpos
< 0.0) fpos
= 0.0;
3976 m_oldHorizontalPos
= fpos
;
3978 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
3979 m_hAdjust
->value
= fpos
;
3983 float fpos
= (float)pos
;
3984 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
3985 if (fpos
< 0.0) fpos
= 0.0;
3986 m_oldVerticalPos
= fpos
;
3988 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
3989 m_vAdjust
->value
= fpos
;
3992 if (m_wxwindow
->window
)
3994 if (orient
== wxHORIZONTAL
)
3996 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
3997 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
3999 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4001 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4002 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4006 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4007 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4009 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4011 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4012 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4017 int wxWindowGTK::GetScrollThumb( int orient
) const
4019 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4021 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4023 if (orient
== wxHORIZONTAL
)
4024 return (int)(m_hAdjust
->page_size
+0.5);
4026 return (int)(m_vAdjust
->page_size
+0.5);
4029 int wxWindowGTK::GetScrollPos( int orient
) const
4031 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4033 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4035 if (orient
== wxHORIZONTAL
)
4036 return (int)(m_hAdjust
->value
+0.5);
4038 return (int)(m_vAdjust
->value
+0.5);
4041 int wxWindowGTK::GetScrollRange( int orient
) const
4043 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4045 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4047 if (orient
== wxHORIZONTAL
)
4048 return (int)(m_hAdjust
->upper
+0.5);
4050 return (int)(m_vAdjust
->upper
+0.5);
4053 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4055 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4057 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4059 // No scrolling requested.
4060 if ((dx
== 0) && (dy
== 0)) return;
4063 if (!m_updateRegion
.IsEmpty())
4065 m_updateRegion
.Offset( dx
, dy
);
4069 GetClientSize( &cw
, &ch
);
4070 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4073 if (!m_clearRegion
.IsEmpty())
4075 m_clearRegion
.Offset( dx
, dy
);
4079 GetClientSize( &cw
, &ch
);
4080 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4083 m_clipPaintRegion
= TRUE
;
4085 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4087 m_clipPaintRegion
= FALSE
;
4090 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, -dx
, -dy
);
4092 GTK_PIZZA(m_wxwindow
)->xoffset
-= dx
;
4093 GTK_PIZZA(m_wxwindow
)->yoffset
-= dy
;
4100 // Find the wxWindow at the current mouse position, also returning the mouse
4102 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4104 pt
= wxGetMousePosition();
4105 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4109 // Get the current mouse position.
4110 wxPoint
wxGetMousePosition()
4112 /* This crashes when used within wxHelpContext,
4113 so we have to use the X-specific implementation below.
4115 GdkModifierType *mask;
4116 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4118 return wxPoint(x, y);
4122 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4124 return wxPoint(-999, -999);
4126 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4127 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4128 Window rootReturn
, childReturn
;
4129 int rootX
, rootY
, winX
, winY
;
4130 unsigned int maskReturn
;
4132 XQueryPointer (display
,
4136 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4137 return wxPoint(rootX
, rootY
);
4141 // ----------------------------------------------------------------------------
4143 // ----------------------------------------------------------------------------
4145 class wxWinModule
: public wxModule
4152 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4155 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4157 bool wxWinModule::OnInit()
4159 g_eraseGC
= gdk_gc_new( GDK_ROOT_PARENT() );
4160 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4165 void wxWinModule::OnExit()
4167 gdk_gc_unref( g_eraseGC
);