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))
80 extern GtkContainerClass
*pizza_parent_class
;
83 //-----------------------------------------------------------------------------
84 // documentation on internals
85 //-----------------------------------------------------------------------------
88 I have been asked several times about writing some documentation about
89 the GTK port of wxWindows, especially its internal structures. Obviously,
90 you cannot understand wxGTK without knowing a little about the GTK, but
91 some more information about what the wxWindow, which is the base class
92 for all other window classes, does seems required as well.
96 What does wxWindow do? It contains the common interface for the following
97 jobs of its descendants:
99 1) Define the rudimentary behaviour common to all window classes, such as
100 resizing, intercepting user input (so as to make it possible to use these
101 events for special purposes in a derived class), window names etc.
103 2) Provide the possibility to contain and manage children, if the derived
104 class is allowed to contain children, which holds true for those window
105 classes which do not display a native GTK widget. To name them, these
106 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
107 work classes are a special case and are handled a bit differently from
108 the rest. The same holds true for the wxNotebook class.
110 3) Provide the possibility to draw into a client area of a window. This,
111 too, only holds true for classes that do not display a native GTK widget
114 4) Provide the entire mechanism for scrolling widgets. This actual inter-
115 face for this is usually in wxScrolledWindow, but the GTK implementation
118 5) A multitude of helper or extra methods for special purposes, such as
119 Drag'n'Drop, managing validators etc.
121 6) Display a border (sunken, raised, simple or none).
123 Normally one might expect, that one wxWindows window would always correspond
124 to one GTK widget. Under GTK, there is no such allround widget that has all
125 the functionality. Moreover, the GTK defines a client area as a different
126 widget from the actual widget you are handling. Last but not least some
127 special classes (e.g. wxFrame) handle different categories of widgets and
128 still have the possibility to draw something in the client area.
129 It was therefore required to write a special purpose GTK widget, that would
130 represent a client area in the sense of wxWindows capable to do the jobs
131 2), 3) and 4). I have written this class and it resides in win_gtk.c of
134 All windows must have a widget, with which they interact with other under-
135 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
136 thw wxWindow class has a member variable called m_widget which holds a
137 pointer to this widget. When the window class represents a GTK native widget,
138 this is (in most cases) the only GTK widget the class manages. E.g. the
139 wxStatitText class handles only a GtkLabel widget a pointer to which you
140 can find in m_widget (defined in wxWindow)
142 When the class has a client area for drawing into and for containing children
143 it has to handle the client area widget (of the type GtkPizza, defined in
144 win_gtk.c), but there could be any number of widgets, handled by a class
145 The common rule for all windows is only, that the widget that interacts with
146 the rest of GTK must be referenced in m_widget and all other widgets must be
147 children of this widget on the GTK level. The top-most widget, which also
148 represents the client area, must be in the m_wxwindow field and must be of
151 As I said, the window classes that display a GTK native widget only have
152 one widget, so in the case of e.g. the wxButton class m_widget holds a
153 pointer to a GtkButton widget. But windows with client areas (for drawing
154 and children) have a m_widget field that is a pointer to a GtkScrolled-
155 Window and a m_wxwindow field that is pointer to a GtkPizza and this
156 one is (in the GTK sense) a child of the GtkScrolledWindow.
158 If the m_wxwindow field is set, then all input to this widget is inter-
159 cepted and sent to the wxWindows class. If not, all input to the widget
160 that gets pointed to by m_widget gets intercepted and sent to the class.
164 The design of scrolling in wxWindows is markedly different from that offered
165 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
166 clicking on a scrollbar belonging to scrolled window will inevitably move
167 the window. In wxWindows, the scrollbar will only emit an event, send this
168 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
169 which actually moves the window and its subchildren. Note that GtkPizza
170 memorizes how much it has been scrolled but that wxWindows forgets this
171 so that the two coordinates systems have to be kept in synch. This is done
172 in various places using the pizza->xoffset and pizza->yoffset values.
176 Singularily the most broken code in GTK is the code that is supposes to
177 inform subwindows (child windows) about new positions. Very often, duplicate
178 events are sent without changes in size or position, equally often no
179 events are sent at all (All this is due to a bug in the GtkContainer code
180 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
181 GTK's own system and it simply waits for size events for toplevel windows
182 and then iterates down the respective size events to all window. This has
183 the disadvantage, that windows might get size events before the GTK widget
184 actually has the reported size. This doesn't normally pose any problem, but
185 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
186 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
187 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
188 window that is used for OpenGl output really has that size (as reported by
193 If someone at some point of time feels the immense desire to have a look at,
194 change or attempt to optimse the Refresh() logic, this person will need an
195 intimate understanding of what a "draw" and what an "expose" events are and
196 what there are used for, in particular when used in connection with GTK's
197 own windowless widgets. Beware.
201 Cursors, too, have been a constant source of pleasure. The main difficulty
202 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
203 for the parent. To prevent this from doing too much harm, I use idle time
204 to set the cursor over and over again, starting from the toplevel windows
205 and ending with the youngest generation (speaking of parent and child windows).
206 Also don't forget that cursors (like much else) are connected to GdkWindows,
207 not GtkWidgets and that the "window" field of a GtkWidget might very well
208 point to the GdkWindow of the parent widget (-> "window less widget") and
209 that the two obviously have very different meanings.
213 //-----------------------------------------------------------------------------
215 //-----------------------------------------------------------------------------
217 extern wxList wxPendingDelete
;
218 extern bool g_blockEventsOnDrag
;
219 extern bool g_blockEventsOnScroll
;
220 extern wxCursor g_globalCursor
;
222 static GdkGC
*g_eraseGC
= NULL
;
224 // mouse capture state: the window which has it and if the mouse is currently
226 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
227 static bool g_captureWindowHasMouse
= FALSE
;
229 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
231 // the last window which had the focus - this is normally never NULL (except
232 // if we never had focus at all) as even when g_focusWindow is NULL it still
233 // keeps its previous value
234 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*)NULL
;
236 // the frame that is currently active (i.e. its child has focus). It is
237 // used to generate wxActivateEvents
238 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*)NULL
;
239 static bool g_activeFrameLostFocus
= FALSE
;
241 // if we detect that the app has got/lost the focus, we set this variable to
242 // either TRUE or FALSE and an activate event will be sent during the next
243 // OnIdle() call and it is reset to -1: this value means that we shouldn't
244 // send any activate events at all
245 static int g_sendActivateEvent
= -1;
247 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
248 the last click here */
249 static guint32 gs_timeLastClick
= 0;
251 extern bool g_mainThreadLocked
;
253 //-----------------------------------------------------------------------------
255 //-----------------------------------------------------------------------------
258 #define DISABLE_STYLE_IF_BROKEN_THEME 1
264 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
266 # define DEBUG_MAIN_THREAD
269 static gint
gtk_debug_focus_in_callback( GtkWidget
*WXUNUSED(widget
),
270 GdkEvent
*WXUNUSED(event
),
271 const wxChar
*WXUNUSED(name
) )
274 static bool s_done = FALSE;
277 wxLog::AddTraceMask("focus");
280 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
286 void debug_focus_in( GtkWidget
* widget
, const wxChar
* name
, const wxChar
*window
)
288 // suppress warnings about gtk_debug_focus_in_callback being unused with
293 tmp
+= wxT(" FROM ");
296 wxChar
*s
= new wxChar
[tmp
.Length()+1];
300 gtk_signal_connect( GTK_OBJECT(widget
), "focus_in_event",
301 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback
), (gpointer
)s
);
306 #define DEBUG_MAIN_THREAD
309 //-----------------------------------------------------------------------------
310 // missing gdk functions
311 //-----------------------------------------------------------------------------
314 gdk_window_warp_pointer (GdkWindow
*window
,
319 GdkWindowPrivate
*priv
;
323 window
= GDK_ROOT_PARENT();
326 if (!GDK_WINDOW_DESTROYED(window
))
328 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
329 None
, /* not source window -> move from anywhere */
330 GDK_WINDOW_XID(window
), /* dest window */
331 0, 0, 0, 0, /* not source window -> move from anywhere */
335 priv
= (GdkWindowPrivate
*) window
;
337 if (!priv
->destroyed
)
339 XWarpPointer (priv
->xdisplay
,
340 None
, /* not source window -> move from anywhere */
341 priv
->xwindow
, /* dest window */
342 0, 0, 0, 0, /* not source window -> move from anywhere */
348 //-----------------------------------------------------------------------------
350 //-----------------------------------------------------------------------------
352 extern void wxapp_install_idle_handler();
353 extern bool g_isIdle
;
355 //-----------------------------------------------------------------------------
356 // local code (see below)
357 //-----------------------------------------------------------------------------
359 // returns the child of win which currently has focus or NULL if not found
361 // Note: can't be static, needed by textctrl.cpp.
362 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
364 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
366 return (wxWindow
*)NULL
;
368 if ( winFocus
== win
)
369 return (wxWindow
*)win
;
371 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
373 node
= node
->GetNext() )
375 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
380 return (wxWindow
*)NULL
;
383 // Returns toplevel grandparent of given window:
384 static wxWindowGTK
* wxGetTopLevelParent(wxWindowGTK
*win
)
386 wxWindowGTK
*p
= win
;
387 while (p
&& !p
->IsTopLevel())
392 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
394 // wxUniversal widgets draw the borders and scrollbars themselves
395 #ifndef __WXUNIVERSAL__
402 if (win
->m_hasScrolling
)
404 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
406 GtkRequisition vscroll_req
;
407 vscroll_req
.width
= 2;
408 vscroll_req
.height
= 2;
409 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
410 (scroll_window
->vscrollbar
, &vscroll_req
);
412 GtkRequisition hscroll_req
;
413 hscroll_req
.width
= 2;
414 hscroll_req
.height
= 2;
415 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
416 (scroll_window
->hscrollbar
, &hscroll_req
);
418 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
420 if (scroll_window
->vscrollbar_visible
)
422 dw
+= vscroll_req
.width
;
423 dw
+= scroll_class
->scrollbar_spacing
;
426 if (scroll_window
->hscrollbar_visible
)
428 dh
+= hscroll_req
.height
;
429 dh
+= scroll_class
->scrollbar_spacing
;
435 if (GTK_WIDGET_NO_WINDOW (widget
))
437 dx
+= widget
->allocation
.x
;
438 dy
+= widget
->allocation
.y
;
441 if (win
->HasFlag(wxRAISED_BORDER
))
443 gtk_draw_shadow( widget
->style
,
448 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
452 if (win
->HasFlag(wxSUNKEN_BORDER
))
454 gtk_draw_shadow( widget
->style
,
459 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
463 if (win
->HasFlag(wxSIMPLE_BORDER
))
466 gc
= gdk_gc_new( widget
->window
);
467 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
468 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
470 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
474 #endif // __WXUNIVERSAL__
477 //-----------------------------------------------------------------------------
478 // "expose_event" of m_widget
479 //-----------------------------------------------------------------------------
481 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
483 if (gdk_event
->count
> 0) return FALSE
;
485 draw_frame( widget
, win
);
489 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
495 //-----------------------------------------------------------------------------
496 // "draw" of m_widget
497 //-----------------------------------------------------------------------------
501 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
503 draw_frame( widget
, win
);
508 //-----------------------------------------------------------------------------
509 // key code mapping routines
510 //-----------------------------------------------------------------------------
512 static long map_to_unmodified_wx_keysym( GdkEventKey
*event
)
514 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
515 // but only event->keyval which is quite useless to us, so remember
516 // the last character from GDK_KEY_PRESS and resue it as last resort
518 // NB: should be MT-neutral as always called from main thread only
523 } s_lastKeyPress
= { 0, 0 };
525 KeySym keysym
= event
->keyval
;
531 case GDK_Shift_R
: key_code
= WXK_SHIFT
; break;
533 case GDK_Control_R
: key_code
= WXK_CONTROL
; break;
539 case GDK_Super_R
: key_code
= WXK_ALT
; break;
540 case GDK_Menu
: key_code
= WXK_MENU
; break;
541 case GDK_Help
: key_code
= WXK_HELP
; break;
542 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
543 case GDK_ISO_Left_Tab
:
544 case GDK_Tab
: key_code
= WXK_TAB
; break;
545 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
546 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
547 case GDK_Return
: key_code
= WXK_RETURN
; break;
548 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
549 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
550 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
551 case GDK_Delete
: key_code
= WXK_DELETE
; break;
552 case GDK_Home
: key_code
= WXK_HOME
; break;
553 case GDK_Left
: key_code
= WXK_LEFT
; break;
554 case GDK_Up
: key_code
= WXK_UP
; break;
555 case GDK_Right
: key_code
= WXK_RIGHT
; break;
556 case GDK_Down
: key_code
= WXK_DOWN
; break;
557 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
558 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
559 case GDK_Next
: key_code
= WXK_NEXT
; break;
560 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
561 case GDK_End
: key_code
= WXK_END
; break;
562 case GDK_Begin
: key_code
= WXK_HOME
; break;
563 case GDK_Select
: key_code
= WXK_SELECT
; break;
564 case GDK_Print
: key_code
= WXK_PRINT
; break;
565 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
566 case GDK_Insert
: key_code
= WXK_INSERT
; break;
567 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
569 case GDK_KP_0
: key_code
= WXK_NUMPAD0
; break;
570 case GDK_KP_1
: key_code
= WXK_NUMPAD1
; break;
571 case GDK_KP_2
: key_code
= WXK_NUMPAD2
; break;
572 case GDK_KP_3
: key_code
= WXK_NUMPAD3
; break;
573 case GDK_KP_4
: key_code
= WXK_NUMPAD4
; break;
574 case GDK_KP_5
: key_code
= WXK_NUMPAD5
; break;
575 case GDK_KP_6
: key_code
= WXK_NUMPAD6
; break;
576 case GDK_KP_7
: key_code
= WXK_NUMPAD7
; break;
577 case GDK_KP_8
: key_code
= WXK_NUMPAD8
; break;
578 case GDK_KP_9
: key_code
= WXK_NUMPAD9
; break;
579 case GDK_KP_Space
: key_code
= WXK_NUMPAD_SPACE
; break;
580 case GDK_KP_Tab
: key_code
= WXK_NUMPAD_TAB
; break;
581 case GDK_KP_Enter
: key_code
= WXK_NUMPAD_ENTER
; break;
582 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
583 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
584 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
585 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
586 case GDK_KP_Home
: key_code
= WXK_NUMPAD_HOME
; break;
587 case GDK_KP_Left
: key_code
= WXK_NUMPAD_LEFT
; break;
588 case GDK_KP_Up
: key_code
= WXK_NUMPAD_UP
; break;
589 case GDK_KP_Right
: key_code
= WXK_NUMPAD_RIGHT
; break;
590 case GDK_KP_Down
: key_code
= WXK_NUMPAD_DOWN
; break;
591 case GDK_KP_Prior
: key_code
= WXK_NUMPAD_PRIOR
; break;
592 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
593 case GDK_KP_Next
: key_code
= WXK_NUMPAD_NEXT
; break;
594 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
595 case GDK_KP_End
: key_code
= WXK_NUMPAD_END
; break;
596 case GDK_KP_Begin
: key_code
= WXK_NUMPAD_BEGIN
; break;
597 case GDK_KP_Insert
: key_code
= WXK_NUMPAD_INSERT
; break;
598 case GDK_KP_Delete
: key_code
= WXK_NUMPAD_DELETE
; break;
599 case GDK_KP_Equal
: key_code
= WXK_NUMPAD_EQUAL
; break;
600 case GDK_KP_Multiply
: key_code
= WXK_NUMPAD_MULTIPLY
; break;
601 case GDK_KP_Add
: key_code
= WXK_NUMPAD_ADD
; break;
602 case GDK_KP_Separator
: key_code
= WXK_NUMPAD_SEPARATOR
; break;
603 case GDK_KP_Subtract
: key_code
= WXK_NUMPAD_SUBTRACT
; break;
604 case GDK_KP_Decimal
: key_code
= WXK_NUMPAD_DECIMAL
; break;
605 case GDK_KP_Divide
: key_code
= WXK_NUMPAD_DIVIDE
; break;
607 case GDK_F1
: key_code
= WXK_F1
; break;
608 case GDK_F2
: key_code
= WXK_F2
; break;
609 case GDK_F3
: key_code
= WXK_F3
; break;
610 case GDK_F4
: key_code
= WXK_F4
; break;
611 case GDK_F5
: key_code
= WXK_F5
; break;
612 case GDK_F6
: key_code
= WXK_F6
; break;
613 case GDK_F7
: key_code
= WXK_F7
; break;
614 case GDK_F8
: key_code
= WXK_F8
; break;
615 case GDK_F9
: key_code
= WXK_F9
; break;
616 case GDK_F10
: key_code
= WXK_F10
; break;
617 case GDK_F11
: key_code
= WXK_F11
; break;
618 case GDK_F12
: key_code
= WXK_F12
; break;
621 // do we have the translation?
622 if ( event
->length
== 1 )
624 keysym
= (KeySym
)event
->string
[0];
626 else if ( (keysym
& 0xFF) != keysym
)
628 // non ASCII key, what to do?
630 if ( event
->type
== GDK_KEY_RELEASE
)
632 // reuse the one from the last keypress if any
633 if ( keysym
== s_lastKeyPress
.keysym
)
635 key_code
= s_lastKeyPress
.keycode
;
642 // ignore this one, we don't know it
645 //else: ASCII key, ok
647 guint upper
= gdk_keyval_to_upper( (guint
)keysym
);
648 key_code
= upper
? upper
: keysym
;
650 if ( event
->type
== GDK_KEY_PRESS
)
652 // remember it to be reused below later
653 s_lastKeyPress
.keysym
= keysym
;
654 s_lastKeyPress
.keycode
= key_code
;
662 static long map_to_wx_keysym( GdkEventKey
*event
)
664 KeySym keysym
= event
->keyval
;
669 case GDK_Menu
: key_code
= WXK_MENU
; break;
670 case GDK_Help
: key_code
= WXK_HELP
; break;
671 case GDK_BackSpace
: key_code
= WXK_BACK
; break;
672 case GDK_ISO_Left_Tab
:
673 case GDK_Tab
: key_code
= WXK_TAB
; break;
674 case GDK_Linefeed
: key_code
= WXK_RETURN
; break;
675 case GDK_Clear
: key_code
= WXK_CLEAR
; break;
676 case GDK_Return
: key_code
= WXK_RETURN
; break;
677 case GDK_Pause
: key_code
= WXK_PAUSE
; break;
678 case GDK_Scroll_Lock
: key_code
= WXK_SCROLL
; break;
679 case GDK_Escape
: key_code
= WXK_ESCAPE
; break;
680 case GDK_Delete
: key_code
= WXK_DELETE
; break;
681 case GDK_Home
: key_code
= WXK_HOME
; break;
682 case GDK_Left
: key_code
= WXK_LEFT
; break;
683 case GDK_Up
: key_code
= WXK_UP
; break;
684 case GDK_Right
: key_code
= WXK_RIGHT
; break;
685 case GDK_Down
: key_code
= WXK_DOWN
; break;
686 case GDK_Prior
: key_code
= WXK_PRIOR
; break;
687 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
688 case GDK_Next
: key_code
= WXK_NEXT
; break;
689 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
690 case GDK_End
: key_code
= WXK_END
; break;
691 case GDK_Begin
: key_code
= WXK_HOME
; break;
692 case GDK_Select
: key_code
= WXK_SELECT
; break;
693 case GDK_Print
: key_code
= WXK_PRINT
; break;
694 case GDK_Execute
: key_code
= WXK_EXECUTE
; break;
695 case GDK_Insert
: key_code
= WXK_INSERT
; break;
696 case GDK_Num_Lock
: key_code
= WXK_NUMLOCK
; break;
698 case GDK_KP_0
: key_code
= '0'; break;
699 case GDK_KP_1
: key_code
= '1'; break;
700 case GDK_KP_2
: key_code
= '2'; break;
701 case GDK_KP_3
: key_code
= '3'; break;
702 case GDK_KP_4
: key_code
= '4'; break;
703 case GDK_KP_5
: key_code
= '5'; break;
704 case GDK_KP_6
: key_code
= '6'; break;
705 case GDK_KP_7
: key_code
= '7'; break;
706 case GDK_KP_8
: key_code
= '8'; break;
707 case GDK_KP_9
: key_code
= '9'; break;
708 case GDK_KP_Space
: key_code
= ' '; break;
709 case GDK_KP_Tab
: key_code
= WXK_TAB
; break; /* or '\t' ??? */
710 case GDK_KP_Enter
: key_code
= WXK_RETURN
; break; /* or '\r' ??? */
711 case GDK_KP_F1
: key_code
= WXK_NUMPAD_F1
; break;
712 case GDK_KP_F2
: key_code
= WXK_NUMPAD_F2
; break;
713 case GDK_KP_F3
: key_code
= WXK_NUMPAD_F3
; break;
714 case GDK_KP_F4
: key_code
= WXK_NUMPAD_F4
; break;
715 case GDK_KP_Home
: key_code
= WXK_HOME
; break;
716 case GDK_KP_Left
: key_code
= WXK_LEFT
; break;
717 case GDK_KP_Up
: key_code
= WXK_UP
; break;
718 case GDK_KP_Right
: key_code
= WXK_RIGHT
; break;
719 case GDK_KP_Down
: key_code
= WXK_DOWN
; break;
720 case GDK_KP_Prior
: key_code
= WXK_PRIOR
; break;
721 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
722 case GDK_KP_Next
: key_code
= WXK_NEXT
; break;
723 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
724 case GDK_KP_End
: key_code
= WXK_END
; break;
725 case GDK_KP_Begin
: key_code
= WXK_HOME
; break;
726 case GDK_KP_Insert
: key_code
= WXK_INSERT
; break;
727 case GDK_KP_Delete
: key_code
= WXK_DELETE
; break;
728 case GDK_KP_Equal
: key_code
= '='; break;
729 case GDK_KP_Multiply
: key_code
= '*'; break;
730 case GDK_KP_Add
: key_code
= '+'; break;
731 case GDK_KP_Separator
: key_code
= ','; break;
732 case GDK_KP_Subtract
: key_code
= '-'; break;
733 case GDK_KP_Decimal
: key_code
= '.'; break;
734 case GDK_KP_Divide
: key_code
= '/'; break;
736 case GDK_F1
: key_code
= WXK_F1
; break;
737 case GDK_F2
: key_code
= WXK_F2
; break;
738 case GDK_F3
: key_code
= WXK_F3
; break;
739 case GDK_F4
: key_code
= WXK_F4
; break;
740 case GDK_F5
: key_code
= WXK_F5
; break;
741 case GDK_F6
: key_code
= WXK_F6
; break;
742 case GDK_F7
: key_code
= WXK_F7
; break;
743 case GDK_F8
: key_code
= WXK_F8
; break;
744 case GDK_F9
: key_code
= WXK_F9
; break;
745 case GDK_F10
: key_code
= WXK_F10
; break;
746 case GDK_F11
: key_code
= WXK_F11
; break;
747 case GDK_F12
: key_code
= WXK_F12
; break;
749 if (event
->length
== 1)
751 key_code
= (unsigned char)*event
->string
;
753 else if ((keysym
& 0xFF) == keysym
)
755 key_code
= (guint
)keysym
;
762 //-----------------------------------------------------------------------------
763 // "size_request" of m_widget
764 //-----------------------------------------------------------------------------
766 static void gtk_window_size_request_callback( GtkWidget
*widget
, GtkRequisition
*requisition
, wxWindow
*win
)
769 win
->GetSize( &w
, &h
);
773 requisition
->height
= h
;
774 requisition
->width
= w
;
777 //-----------------------------------------------------------------------------
778 // "expose_event" of m_wxwindow
779 //-----------------------------------------------------------------------------
781 static int gtk_window_expose_callback( GtkWidget
*widget
,
782 GdkEventExpose
*gdk_event
,
788 wxapp_install_idle_handler();
791 if (win->GetName() == wxT("panel"))
793 wxPrintf( wxT("OnExpose from ") );
794 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
795 wxPrintf( win->GetClassInfo()->GetClassName() );
796 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
797 (int)gdk_event->area.y,
798 (int)gdk_event->area.width,
799 (int)gdk_event->area.height );
803 #ifndef __WXUNIVERSAL__
804 GtkPizza
*pizza
= GTK_PIZZA (widget
);
806 if (win
->GetThemeEnabled())
808 wxWindow
*parent
= win
->GetParent();
809 while (parent
&& !parent
->IsTopLevel())
810 parent
= parent
->GetParent();
814 gtk_paint_flat_box (parent
->m_widget
->style
,
825 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
827 gdk_event
->area
.width
,
828 gdk_event
->area
.height
);
830 // Actual redrawing takes place in idle time.
835 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
842 //-----------------------------------------------------------------------------
843 // "event" of m_wxwindow
844 //-----------------------------------------------------------------------------
846 // GTK thinks it is clever and filters out a certain amount of "unneeded"
847 // expose events. We need them, of course, so we override the main event
848 // procedure in GtkWidget by giving our own handler for all system events.
849 // There, we look for expose events ourselves whereas all other events are
852 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
853 GdkEventExpose
*event
,
856 if (event
->type
== GDK_EXPOSE
)
858 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
865 //-----------------------------------------------------------------------------
866 // "draw" of m_wxwindow
867 //-----------------------------------------------------------------------------
871 // This callback is a complete replacement of the gtk_pizza_draw() function,
872 // which is disabled.
874 static void gtk_window_draw_callback( GtkWidget
*widget
,
881 wxapp_install_idle_handler();
883 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
884 // there are no child windows.
885 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
886 (win
->GetChildren().GetCount() == 0))
892 if (win->GetName() == wxT("panel"))
894 wxPrintf( wxT("OnDraw from ") );
895 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
896 wxPrintf( win->GetClassInfo()->GetClassName() );
897 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
904 #ifndef __WXUNIVERSAL__
905 GtkPizza
*pizza
= GTK_PIZZA (widget
);
907 if (win
->GetThemeEnabled())
909 wxWindow
*parent
= win
->GetParent();
910 while (parent
&& !parent
->IsTopLevel())
911 parent
= parent
->GetParent();
915 gtk_paint_flat_box (parent
->m_widget
->style
,
926 if (!(GTK_WIDGET_APP_PAINTABLE (widget
)) &&
927 (pizza
->clear_on_draw
))
929 gdk_window_clear_area( pizza
->bin_window
,
930 rect
->x
, rect
->y
, rect
->width
, rect
->height
);
934 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
936 // Actual redrawing takes place in idle time.
940 #ifndef __WXUNIVERSAL__
941 // Redraw child widgets
942 GList
*children
= pizza
->children
;
945 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
946 children
= children
->next
;
948 GdkRectangle child_area
;
949 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
951 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
959 //-----------------------------------------------------------------------------
960 // "key_press_event" from any window
961 //-----------------------------------------------------------------------------
963 // turn on to see the key event codes on the console
964 #undef DEBUG_KEY_EVENTS
966 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
967 GdkEventKey
*gdk_event
,
973 wxapp_install_idle_handler();
975 if (!win
->m_hasVMT
) return FALSE
;
976 if (g_blockEventsOnDrag
) return FALSE
;
981 GdkModifierType state
;
982 if (gdk_event
->window
)
983 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
987 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
989 #ifdef DEBUG_KEY_EVENTS
990 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
991 #endif // DEBUG_KEY_EVENTS
993 /* sending unknown key events doesn't really make sense */
997 wxKeyEvent
event( wxEVT_KEY_DOWN
);
998 event
.SetTimestamp( gdk_event
->time
);
999 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1000 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1001 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1002 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1003 event
.m_keyCode
= key_code
;
1004 event
.m_scanCode
= gdk_event
->keyval
;
1007 event
.SetEventObject( win
);
1008 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1013 wxWindowGTK
*ancestor
= win
;
1016 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1019 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1020 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1023 if (ancestor
->IsTopLevel())
1025 ancestor
= ancestor
->GetParent();
1028 #endif // wxUSE_ACCEL
1030 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1031 will only be sent if it is not in an accelerator table. */
1034 key_code
= map_to_wx_keysym( gdk_event
);
1038 #ifdef DEBUG_KEY_EVENTS
1039 wxPrintf(_T("Char event: %ld\n"), key_code
);
1040 #endif // DEBUG_KEY_EVENTS
1042 // reuse the ame event object, just change its type and use the
1043 // translated keycode instead of the raw one
1044 event
.SetEventType(wxEVT_CHAR
);
1045 event
.m_keyCode
= key_code
;
1047 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1051 /* win is a control: tab can be propagated up */
1053 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1054 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1055 // have this style, yet choose not to process this particular TAB in which
1056 // case TAB must still work as a navigational character
1058 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1060 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1062 wxNavigationKeyEvent new_event
;
1063 new_event
.SetEventObject( win
->GetParent() );
1064 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
1065 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1066 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
1067 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1068 new_event
.SetCurrentFocus( win
);
1069 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1072 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
1074 (gdk_event
->keyval
== GDK_Escape
) )
1076 wxCommandEvent
new_event(wxEVT_COMMAND_BUTTON_CLICKED
,wxID_CANCEL
);
1077 new_event
.SetEventObject( win
);
1078 ret
= win
->GetEventHandler()->ProcessEvent( new_event
);
1082 #if 0 // (GTK_MINOR_VERSION > 0)
1083 /* Pressing F10 will activate the menu bar of the top frame. */
1085 (gdk_event
->keyval
== GDK_F10
) )
1087 wxWindowGTK
*ancestor
= win
;
1090 if (wxIsKindOf(ancestor
,wxFrame
))
1092 wxFrame
*frame
= (wxFrame
*) ancestor
;
1093 wxMenuBar
*menubar
= frame
->GetMenuBar();
1096 wxNode
*node
= menubar
->GetMenus().First();
1099 wxMenu
*firstMenu
= (wxMenu
*) node
->Data();
1100 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu
->m_owner
) );
1106 ancestor
= ancestor
->GetParent();
1113 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1120 //-----------------------------------------------------------------------------
1121 // "key_release_event" from any window
1122 //-----------------------------------------------------------------------------
1124 static gint
gtk_window_key_release_callback( GtkWidget
*widget
, GdkEventKey
*gdk_event
, wxWindowGTK
*win
)
1129 wxapp_install_idle_handler();
1131 if (!win
->m_hasVMT
) return FALSE
;
1132 if (g_blockEventsOnDrag
) return FALSE
;
1134 long key_code
= map_to_unmodified_wx_keysym( gdk_event
);
1136 #ifdef DEBUG_KEY_EVENTS
1137 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event
->keyval
, key_code
);
1138 #endif // DEBUG_KEY_EVENTS
1140 /* sending unknown key events doesn't really make sense */
1141 if (key_code
== 0) return FALSE
;
1145 GdkModifierType state
;
1146 if (gdk_event
->window
)
1147 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1149 wxKeyEvent
event( wxEVT_KEY_UP
);
1150 event
.SetTimestamp( gdk_event
->time
);
1151 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1152 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1153 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1154 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1155 event
.m_keyCode
= key_code
;
1156 event
.m_scanCode
= gdk_event
->keyval
;
1159 event
.SetEventObject( win
);
1161 if (win
->GetEventHandler()->ProcessEvent( event
))
1163 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1170 // ============================================================================
1172 // ============================================================================
1174 // init wxMouseEvent with the info from gdk_event
1175 #define InitMouseEvent(win, event, gdk_event) \
1177 event.SetTimestamp( gdk_event->time ); \
1178 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1179 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1180 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1181 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1182 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1183 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1184 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1186 wxPoint pt = win->GetClientAreaOrigin(); \
1187 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1188 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1191 // ----------------------------------------------------------------------------
1192 // mouse event processing helper
1193 // ----------------------------------------------------------------------------
1195 static void AdjustEventButtonState(wxMouseEvent
& event
)
1197 // GDK reports the old state of the button for a button press event, but
1198 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1199 // for a LEFT_DOWN event, not FALSE, so we will invert
1200 // left/right/middleDown for the corresponding click events
1202 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1203 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1204 (event
.GetEventType() == wxEVT_LEFT_UP
))
1206 event
.m_leftDown
= !event
.m_leftDown
;
1210 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1211 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1212 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1214 event
.m_middleDown
= !event
.m_middleDown
;
1218 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1219 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1220 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1222 event
.m_rightDown
= !event
.m_rightDown
;
1227 //-----------------------------------------------------------------------------
1228 // "button_press_event"
1229 //-----------------------------------------------------------------------------
1231 static gint
gtk_window_button_press_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1236 wxapp_install_idle_handler();
1239 wxPrintf( wxT("1) OnButtonPress from ") );
1240 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1241 wxPrintf( win->GetClassInfo()->GetClassName() );
1242 wxPrintf( wxT(".\n") );
1244 if (!win
->m_hasVMT
) return FALSE
;
1245 if (g_blockEventsOnDrag
) return TRUE
;
1246 if (g_blockEventsOnScroll
) return TRUE
;
1248 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1250 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1252 gtk_widget_grab_focus( win
->m_wxwindow
);
1254 wxPrintf( wxT("GrabFocus from ") );
1255 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1256 wxPrintf( win->GetClassInfo()->GetClassName() );
1257 wxPrintf( wxT(".\n") );
1261 wxEventType event_type
= wxEVT_NULL
;
1263 if (gdk_event
->button
== 1)
1265 switch (gdk_event
->type
)
1267 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1268 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1272 else if (gdk_event
->button
== 2)
1274 switch (gdk_event
->type
)
1276 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1277 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1281 else if (gdk_event
->button
== 3)
1283 switch (gdk_event
->type
)
1285 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1286 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1291 if ( event_type
== wxEVT_NULL
)
1293 // unknown mouse button or click type
1297 wxMouseEvent
event( event_type
);
1298 InitMouseEvent( win
, event
, gdk_event
);
1300 AdjustEventButtonState(event
);
1302 // wxListBox actually get mouse events from the item
1304 if (win
->m_isListBox
)
1306 event
.m_x
+= widget
->allocation
.x
;
1307 event
.m_y
+= widget
->allocation
.y
;
1310 // Some control don't have their own X window and thus cannot get
1313 if (!g_captureWindow
)
1315 wxCoord x
= event
.m_x
;
1316 wxCoord y
= event
.m_y
;
1317 if (win
->m_wxwindow
)
1319 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1320 x
+= pizza
->xoffset
;
1321 y
+= pizza
->yoffset
;
1324 wxNode
*node
= win
->GetChildren().First();
1327 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1329 node
= node
->Next();
1330 if (!child
->IsShown())
1333 if (child
->m_isStaticBox
)
1335 // wxStaticBox is transparent in the box itself
1336 int xx1
= child
->m_x
;
1337 int yy1
= child
->m_y
;
1338 int xx2
= child
->m_x
+ child
->m_width
;
1339 int yy2
= child
->m_x
+ child
->m_height
;
1342 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1344 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1346 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1348 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1351 event
.m_x
-= child
->m_x
;
1352 event
.m_y
-= child
->m_y
;
1359 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1360 (child
->m_x
<= x
) &&
1361 (child
->m_y
<= y
) &&
1362 (child
->m_x
+child
->m_width
>= x
) &&
1363 (child
->m_y
+child
->m_height
>= y
))
1366 event
.m_x
-= child
->m_x
;
1367 event
.m_y
-= child
->m_y
;
1374 event
.SetEventObject( win
);
1376 gs_timeLastClick
= gdk_event
->time
;
1379 wxPrintf( wxT("2) OnButtonPress from ") );
1380 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1381 wxPrintf( win->GetClassInfo()->GetClassName() );
1382 wxPrintf( wxT(".\n") );
1385 if (win
->GetEventHandler()->ProcessEvent( event
))
1387 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1394 //-----------------------------------------------------------------------------
1395 // "button_release_event"
1396 //-----------------------------------------------------------------------------
1398 static gint
gtk_window_button_release_callback( GtkWidget
*widget
, GdkEventButton
*gdk_event
, wxWindowGTK
*win
)
1403 wxapp_install_idle_handler();
1405 if (!win
->m_hasVMT
) return FALSE
;
1406 if (g_blockEventsOnDrag
) return FALSE
;
1407 if (g_blockEventsOnScroll
) return FALSE
;
1409 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1412 printf( "OnButtonRelease from " );
1413 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1414 printf( win->GetClassInfo()->GetClassName() );
1418 wxEventType event_type
= wxEVT_NULL
;
1420 switch (gdk_event
->button
)
1422 case 1: event_type
= wxEVT_LEFT_UP
; break;
1423 case 2: event_type
= wxEVT_MIDDLE_UP
; break;
1424 case 3: event_type
= wxEVT_RIGHT_UP
; break;
1425 default: return FALSE
;
1428 wxMouseEvent
event( event_type
);
1429 InitMouseEvent( win
, event
, gdk_event
);
1431 AdjustEventButtonState(event
);
1433 // wxListBox actually get mouse events from the item
1435 if (win
->m_isListBox
)
1437 event
.m_x
+= widget
->allocation
.x
;
1438 event
.m_y
+= widget
->allocation
.y
;
1441 // Some control don't have their own X window and thus cannot get
1444 if (!g_captureWindow
)
1446 wxCoord x
= event
.m_x
;
1447 wxCoord y
= event
.m_y
;
1448 if (win
->m_wxwindow
)
1450 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1451 x
+= pizza
->xoffset
;
1452 y
+= pizza
->yoffset
;
1455 wxNode
*node
= win
->GetChildren().First();
1458 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1460 node
= node
->Next();
1461 if (!child
->IsShown())
1464 if (child
->m_isStaticBox
)
1466 // wxStaticBox is transparent in the box itself
1467 int xx1
= child
->m_x
;
1468 int yy1
= child
->m_y
;
1469 int xx2
= child
->m_x
+ child
->m_width
;
1470 int yy2
= child
->m_x
+ child
->m_height
;
1473 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1475 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1477 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1479 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1482 event
.m_x
-= child
->m_x
;
1483 event
.m_y
-= child
->m_y
;
1490 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1491 (child
->m_x
<= x
) &&
1492 (child
->m_y
<= y
) &&
1493 (child
->m_x
+child
->m_width
>= x
) &&
1494 (child
->m_y
+child
->m_height
>= y
))
1497 event
.m_x
-= child
->m_x
;
1498 event
.m_y
-= child
->m_y
;
1505 event
.SetEventObject( win
);
1507 if (win
->GetEventHandler()->ProcessEvent( event
))
1509 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1516 //-----------------------------------------------------------------------------
1517 // "motion_notify_event"
1518 //-----------------------------------------------------------------------------
1520 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1521 GdkEventMotion
*gdk_event
,
1527 wxapp_install_idle_handler();
1529 if (!win
->m_hasVMT
) return FALSE
;
1530 if (g_blockEventsOnDrag
) return FALSE
;
1531 if (g_blockEventsOnScroll
) return FALSE
;
1533 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1535 if (gdk_event
->is_hint
)
1539 GdkModifierType state
;
1540 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1546 printf( "OnMotion from " );
1547 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1548 printf( win->GetClassInfo()->GetClassName() );
1552 wxMouseEvent
event( wxEVT_MOTION
);
1553 InitMouseEvent(win
, event
, gdk_event
);
1555 if ( g_captureWindow
)
1557 // synthetize a mouse enter or leave event if needed
1558 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1559 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1560 if ( hasMouse
!= g_captureWindowHasMouse
)
1562 // the mouse changed window
1563 g_captureWindowHasMouse
= hasMouse
;
1565 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1566 : wxEVT_LEAVE_WINDOW
);
1567 InitMouseEvent(win
, event
, gdk_event
);
1568 event
.SetEventObject(win
);
1569 win
->GetEventHandler()->ProcessEvent(event
);
1574 // Some control don't have their own X window and thus cannot get
1577 wxCoord x
= event
.m_x
;
1578 wxCoord y
= event
.m_y
;
1579 if (win
->m_wxwindow
)
1581 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1582 x
+= pizza
->xoffset
;
1583 y
+= pizza
->yoffset
;
1586 wxNode
*node
= win
->GetChildren().First();
1589 wxWindowGTK
*child
= (wxWindowGTK
*)node
->Data();
1591 node
= node
->Next();
1592 if (!child
->IsShown())
1595 if (child
->m_isStaticBox
)
1597 // wxStaticBox is transparent in the box itself
1598 int xx1
= child
->m_x
;
1599 int yy1
= child
->m_y
;
1600 int xx2
= child
->m_x
+ child
->m_width
;
1601 int yy2
= child
->m_x
+ child
->m_height
;
1604 if (((x
>= xx1
) && (x
<= xx1
+10) && (y
>= yy1
) && (y
<= yy2
)) ||
1606 ((x
>= xx2
-10) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy2
)) ||
1608 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy1
) && (y
<= yy1
+10)) ||
1610 ((x
>= xx1
) && (x
<= xx2
) && (y
>= yy2
-1) && (y
<= yy2
)))
1613 event
.m_x
-= child
->m_x
;
1614 event
.m_y
-= child
->m_y
;
1621 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1622 (child
->m_x
<= x
) &&
1623 (child
->m_y
<= y
) &&
1624 (child
->m_x
+child
->m_width
>= x
) &&
1625 (child
->m_y
+child
->m_height
>= y
))
1628 event
.m_x
-= child
->m_x
;
1629 event
.m_y
-= child
->m_y
;
1636 event
.SetEventObject( win
);
1638 if (win
->GetEventHandler()->ProcessEvent( event
))
1640 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1647 //-----------------------------------------------------------------------------
1649 //-----------------------------------------------------------------------------
1651 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1652 GdkEvent
*WXUNUSED(event
),
1658 wxapp_install_idle_handler();
1660 if (!win
->m_hasVMT
) return FALSE
;
1661 if (g_blockEventsOnDrag
) return FALSE
;
1663 switch ( g_sendActivateEvent
)
1666 // we've got focus from outside, synthetize wxActivateEvent
1667 g_sendActivateEvent
= 1;
1671 // another our window just lost focus, it was already ours before
1672 // - don't send any wxActivateEvent
1673 g_sendActivateEvent
= -1;
1678 g_focusWindow
= win
;
1681 wxLogDebug( wxT("OnSetFocus from %s\n"), win
->GetName().c_str() );
1684 // notify the parent keeping track of focus for the kbd navigation
1685 // purposes that we got it
1686 wxChildFocusEvent
eventFocus(win
);
1687 (void)win
->GetEventHandler()->ProcessEvent(eventFocus
);
1691 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1695 // caret needs to be informed about focus change
1696 wxCaret
*caret
= win
->GetCaret();
1699 caret
->OnSetFocus();
1701 #endif // wxUSE_CARET
1703 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1704 if ( active
!= g_activeFrame
)
1706 if ( g_activeFrame
)
1708 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1709 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1710 event
.SetEventObject(g_activeFrame
);
1711 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1714 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1715 g_activeFrame
= active
;
1716 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1717 event
.SetEventObject(g_activeFrame
);
1718 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1720 g_activeFrameLostFocus
= FALSE
;
1723 wxFocusEvent
event( wxEVT_SET_FOCUS
, win
->GetId() );
1724 event
.SetEventObject( win
);
1726 if (win
->GetEventHandler()->ProcessEvent( event
))
1728 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1736 //-----------------------------------------------------------------------------
1737 // "focus_out_event"
1738 //-----------------------------------------------------------------------------
1740 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1745 wxapp_install_idle_handler();
1747 if (!win
->m_hasVMT
) return FALSE
;
1748 if (g_blockEventsOnDrag
) return FALSE
;
1751 wxLogDebug( wxT("OnKillFocus from %s"), win
->GetName().c_str() );
1754 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1756 // VZ: commenting this out because it does happen (although not easy
1757 // to reproduce, I only see it when using wxMiniFrame and not
1758 // always) and makes using Mahogany quite annoying
1760 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1761 wxT("unfocusing window that hasn't gained focus properly") )
1764 g_activeFrameLostFocus
= TRUE
;
1767 // if the focus goes out of our app alltogether, OnIdle() will send
1768 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1769 // g_sendActivateEvent to -1
1770 g_sendActivateEvent
= 0;
1772 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1776 g_focusWindow
= (wxWindowGTK
*)NULL
;
1784 // caret needs to be informed about focus change
1785 wxCaret
*caret
= win
->GetCaret();
1788 caret
->OnKillFocus();
1790 #endif // wxUSE_CARET
1792 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1793 event
.SetEventObject( win
);
1795 if (win
->GetEventHandler()->ProcessEvent( event
))
1797 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1804 //-----------------------------------------------------------------------------
1805 // "enter_notify_event"
1806 //-----------------------------------------------------------------------------
1808 static gint
gtk_window_enter_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1813 wxapp_install_idle_handler();
1815 if (!win
->m_hasVMT
) return FALSE
;
1816 if (g_blockEventsOnDrag
) return FALSE
;
1818 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1820 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1821 event
.SetTimestamp( gdk_event
->time
);
1822 event
.SetEventObject( win
);
1826 GdkModifierType state
= (GdkModifierType
)0;
1828 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1830 InitMouseEvent(win
, event
, gdk_event
);
1831 wxPoint pt
= win
->GetClientAreaOrigin();
1832 event
.m_x
= x
+ pt
.x
;
1833 event
.m_y
= y
+ pt
.y
;
1835 if (win
->GetEventHandler()->ProcessEvent( event
))
1837 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1844 //-----------------------------------------------------------------------------
1845 // "leave_notify_event"
1846 //-----------------------------------------------------------------------------
1848 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1853 wxapp_install_idle_handler();
1855 if (!win
->m_hasVMT
) return FALSE
;
1856 if (g_blockEventsOnDrag
) return FALSE
;
1858 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1860 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
1861 event
.SetTimestamp( gdk_event
->time
);
1862 event
.SetEventObject( win
);
1866 GdkModifierType state
= (GdkModifierType
)0;
1868 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1870 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
);
1871 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
);
1872 event
.m_altDown
= (state
& GDK_MOD1_MASK
);
1873 event
.m_metaDown
= (state
& GDK_MOD2_MASK
);
1874 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
);
1875 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
);
1876 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
);
1878 wxPoint pt
= win
->GetClientAreaOrigin();
1879 event
.m_x
= x
+ pt
.x
;
1880 event
.m_y
= y
+ pt
.y
;
1882 if (win
->GetEventHandler()->ProcessEvent( event
))
1884 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
1891 //-----------------------------------------------------------------------------
1892 // "value_changed" from m_vAdjust
1893 //-----------------------------------------------------------------------------
1895 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
1902 wxapp_install_idle_handler();
1904 if (g_blockEventsOnDrag
) return;
1906 if (!win
->m_hasVMT
) return;
1908 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
1909 if (fabs(diff
) < 0.2) return;
1911 win
->m_oldVerticalPos
= adjust
->value
;
1913 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1915 int value
= (int)(adjust
->value
+0.5);
1917 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
1918 event
.SetEventObject( win
);
1919 win
->GetEventHandler()->ProcessEvent( event
);
1922 //-----------------------------------------------------------------------------
1923 // "value_changed" from m_hAdjust
1924 //-----------------------------------------------------------------------------
1926 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
1933 wxapp_install_idle_handler();
1935 if (g_blockEventsOnDrag
) return;
1936 if (!win
->m_hasVMT
) return;
1938 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
1939 if (fabs(diff
) < 0.2) return;
1941 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win
->m_widget
));
1943 win
->m_oldHorizontalPos
= adjust
->value
;
1945 int value
= (int)(adjust
->value
+0.5);
1947 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
1948 event
.SetEventObject( win
);
1949 win
->GetEventHandler()->ProcessEvent( event
);
1952 //-----------------------------------------------------------------------------
1953 // "button_press_event" from scrollbar
1954 //-----------------------------------------------------------------------------
1956 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
1957 GdkEventButton
*gdk_event
,
1963 wxapp_install_idle_handler();
1966 g_blockEventsOnScroll
= TRUE
;
1968 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
1970 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
1976 //-----------------------------------------------------------------------------
1977 // "button_release_event" from scrollbar
1978 //-----------------------------------------------------------------------------
1980 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
1981 GdkEventButton
*WXUNUSED(gdk_event
),
1986 // don't test here as we can release the mouse while being over
1987 // a different window than the slider
1989 // if (gdk_event->window != widget->slider) return FALSE;
1991 g_blockEventsOnScroll
= FALSE
;
1993 if (win
->m_isScrolling
)
1995 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
1999 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2000 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2002 value
= (int)(win
->m_hAdjust
->value
+0.5);
2005 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2007 value
= (int)(win
->m_vAdjust
->value
+0.5);
2011 wxScrollWinEvent
event( command
, value
, dir
);
2012 event
.SetEventObject( win
);
2013 win
->GetEventHandler()->ProcessEvent( event
);
2016 win
->m_isScrolling
= FALSE
;
2021 // ----------------------------------------------------------------------------
2022 // this wxWindowBase function is implemented here (in platform-specific file)
2023 // because it is static and so couldn't be made virtual
2024 // ----------------------------------------------------------------------------
2026 wxWindow
*wxWindowBase::FindFocus()
2028 // the cast is necessary when we compile in wxUniversal mode
2029 return (wxWindow
*)g_focusWindow
;
2032 //-----------------------------------------------------------------------------
2033 // "realize" from m_widget
2034 //-----------------------------------------------------------------------------
2036 /* We cannot set colours and fonts before the widget has
2037 been realized, so we do this directly after realization. */
2040 gtk_window_realized_callback( GtkWidget
*WXUNUSED(m_widget
), wxWindow
*win
)
2045 wxapp_install_idle_handler();
2047 if (win
->m_delayedBackgroundColour
)
2048 win
->SetBackgroundColour( win
->GetBackgroundColour() );
2050 if (win
->m_delayedForegroundColour
)
2051 win
->SetForegroundColour( win
->GetForegroundColour() );
2053 wxWindowCreateEvent
event( win
);
2054 event
.SetEventObject( win
);
2055 win
->GetEventHandler()->ProcessEvent( event
);
2060 //-----------------------------------------------------------------------------
2062 //-----------------------------------------------------------------------------
2065 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2066 GtkAllocation
*WXUNUSED(alloc
),
2070 wxapp_install_idle_handler();
2072 if (!win
->m_hasScrolling
) return;
2074 int client_width
= 0;
2075 int client_height
= 0;
2076 win
->GetClientSize( &client_width
, &client_height
);
2077 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2080 win
->m_oldClientWidth
= client_width
;
2081 win
->m_oldClientHeight
= client_height
;
2083 if (!win
->m_nativeSizeEvent
)
2085 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2086 event
.SetEventObject( win
);
2087 win
->GetEventHandler()->ProcessEvent( event
);
2093 #define WXUNUSED_UNLESS_XIM(param) param
2095 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2098 /* Resize XIM window */
2101 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2102 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2103 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2106 wxapp_install_idle_handler();
2112 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2116 gdk_window_get_size (widget
->window
, &width
, &height
);
2117 win
->m_icattr
->preedit_area
.width
= width
;
2118 win
->m_icattr
->preedit_area
.height
= height
;
2119 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2124 //-----------------------------------------------------------------------------
2125 // "realize" from m_wxwindow
2126 //-----------------------------------------------------------------------------
2128 /* Initialize XIM support */
2131 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2132 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2135 wxapp_install_idle_handler();
2138 if (win
->m_ic
) return FALSE
;
2139 if (!widget
) return FALSE
;
2140 if (!gdk_im_ready()) return FALSE
;
2142 win
->m_icattr
= gdk_ic_attr_new();
2143 if (!win
->m_icattr
) return FALSE
;
2147 GdkColormap
*colormap
;
2148 GdkICAttr
*attr
= win
->m_icattr
;
2149 unsigned attrmask
= GDK_IC_ALL_REQ
;
2151 GdkIMStyle supported_style
= (GdkIMStyle
)
2152 (GDK_IM_PREEDIT_NONE
|
2153 GDK_IM_PREEDIT_NOTHING
|
2154 GDK_IM_PREEDIT_POSITION
|
2155 GDK_IM_STATUS_NONE
|
2156 GDK_IM_STATUS_NOTHING
);
2158 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2159 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2161 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2162 attr
->client_window
= widget
->window
;
2164 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2165 gtk_widget_get_default_colormap ())
2167 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2168 attr
->preedit_colormap
= colormap
;
2171 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2172 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2173 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2174 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2176 switch (style
& GDK_IM_PREEDIT_MASK
)
2178 case GDK_IM_PREEDIT_POSITION
:
2179 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2181 g_warning ("over-the-spot style requires fontset");
2185 gdk_window_get_size (widget
->window
, &width
, &height
);
2187 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2188 attr
->spot_location
.x
= 0;
2189 attr
->spot_location
.y
= height
;
2190 attr
->preedit_area
.x
= 0;
2191 attr
->preedit_area
.y
= 0;
2192 attr
->preedit_area
.width
= width
;
2193 attr
->preedit_area
.height
= height
;
2194 attr
->preedit_fontset
= widget
->style
->font
;
2199 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2201 if (win
->m_ic
== NULL
)
2202 g_warning ("Can't create input context.");
2205 mask
= gdk_window_get_events (widget
->window
);
2206 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2207 gdk_window_set_events (widget
->window
, mask
);
2209 if (GTK_WIDGET_HAS_FOCUS(widget
))
2210 gdk_im_begin (win
->m_ic
, widget
->window
);
2217 //-----------------------------------------------------------------------------
2218 // InsertChild for wxWindowGTK.
2219 //-----------------------------------------------------------------------------
2221 /* Callback for wxWindowGTK. This very strange beast has to be used because
2222 * C++ has no virtual methods in a constructor. We have to emulate a
2223 * virtual function here as wxNotebook requires a different way to insert
2224 * a child in it. I had opted for creating a wxNotebookPage window class
2225 * which would have made this superfluous (such in the MDI window system),
2226 * but no-one was listening to me... */
2228 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2230 /* the window might have been scrolled already, do we
2231 have to adapt the position */
2232 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2233 child
->m_x
+= pizza
->xoffset
;
2234 child
->m_y
+= pizza
->yoffset
;
2236 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2237 GTK_WIDGET(child
->m_widget
),
2244 //-----------------------------------------------------------------------------
2246 //-----------------------------------------------------------------------------
2248 wxWindow
*wxGetActiveWindow()
2250 // the cast is necessary when we compile in wxUniversal mode
2251 return (wxWindow
*)g_focusWindow
;
2254 //-----------------------------------------------------------------------------
2256 //-----------------------------------------------------------------------------
2258 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2260 #ifdef __WXUNIVERSAL__
2261 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2263 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2264 #endif // __WXUNIVERSAL__/__WXGTK__
2266 void wxWindowGTK::Init()
2272 m_widget
= (GtkWidget
*) NULL
;
2273 m_wxwindow
= (GtkWidget
*) NULL
;
2274 m_focusWidget
= (GtkWidget
*) NULL
;
2284 m_needParent
= TRUE
;
2285 m_isBeingDeleted
= FALSE
;
2288 m_nativeSizeEvent
= FALSE
;
2290 m_hasScrolling
= FALSE
;
2291 m_isScrolling
= FALSE
;
2293 m_hAdjust
= (GtkAdjustment
*) NULL
;
2294 m_vAdjust
= (GtkAdjustment
*) NULL
;
2295 m_oldHorizontalPos
= 0.0;
2296 m_oldVerticalPos
= 0.0;
2299 m_widgetStyle
= (GtkStyle
*) NULL
;
2301 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2303 m_isStaticBox
= FALSE
;
2304 m_isRadioButton
= FALSE
;
2305 m_isListBox
= FALSE
;
2307 m_acceptsFocus
= FALSE
;
2309 m_clipPaintRegion
= FALSE
;
2311 m_cursor
= *wxSTANDARD_CURSOR
;
2313 m_delayedForegroundColour
= FALSE
;
2314 m_delayedBackgroundColour
= FALSE
;
2317 m_ic
= (GdkIC
*) NULL
;
2318 m_icattr
= (GdkICAttr
*) NULL
;
2322 wxWindowGTK::wxWindowGTK()
2327 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2332 const wxString
&name
)
2336 Create( parent
, id
, pos
, size
, style
, name
);
2339 bool wxWindowGTK::Create( wxWindow
*parent
,
2344 const wxString
&name
)
2346 if (!PreCreation( parent
, pos
, size
) ||
2347 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2349 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2353 m_insertCallback
= wxInsertChildInWindow
;
2355 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2356 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2358 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2360 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2361 scroll_class
->scrollbar_spacing
= 0;
2363 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2365 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2366 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2368 m_wxwindow
= gtk_pizza_new();
2370 #ifndef __WXUNIVERSAL__
2371 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2373 if (HasFlag(wxRAISED_BORDER
))
2375 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2377 else if (HasFlag(wxSUNKEN_BORDER
))
2379 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2381 else if (HasFlag(wxSIMPLE_BORDER
))
2383 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2387 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2389 #endif // __WXUNIVERSAL__
2391 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2393 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2394 m_acceptsFocus
= TRUE
;
2396 // I _really_ don't want scrollbars in the beginning
2397 m_vAdjust
->lower
= 0.0;
2398 m_vAdjust
->upper
= 1.0;
2399 m_vAdjust
->value
= 0.0;
2400 m_vAdjust
->step_increment
= 1.0;
2401 m_vAdjust
->page_increment
= 1.0;
2402 m_vAdjust
->page_size
= 5.0;
2403 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2404 m_hAdjust
->lower
= 0.0;
2405 m_hAdjust
->upper
= 1.0;
2406 m_hAdjust
->value
= 0.0;
2407 m_hAdjust
->step_increment
= 1.0;
2408 m_hAdjust
->page_increment
= 1.0;
2409 m_hAdjust
->page_size
= 5.0;
2410 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2412 // these handlers block mouse events to any window during scrolling such as
2413 // motion events and prevent GTK and wxWindows from fighting over where the
2416 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2417 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2419 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2420 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2422 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2423 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2425 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2426 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2428 // these handlers get notified when screen updates are required either when
2429 // scrolling or when the window size (and therefore scrollbar configuration)
2432 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2433 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2434 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2435 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2437 gtk_widget_show( m_wxwindow
);
2440 m_parent
->DoAddChild( this );
2442 m_focusWidget
= m_wxwindow
;
2451 wxWindowGTK::~wxWindowGTK()
2453 if (g_focusWindow
== this)
2454 g_focusWindow
= NULL
;
2456 if (g_activeFrame
== this)
2457 g_activeFrame
= NULL
;
2459 m_isBeingDeleted
= TRUE
;
2468 m_parent
->RemoveChild( this );
2472 gdk_ic_destroy (m_ic
);
2474 gdk_ic_attr_destroy (m_icattr
);
2479 #if DISABLE_STYLE_IF_BROKEN_THEME
2480 // don't delete if it's a pixmap theme style
2481 if (!m_widgetStyle
->engine_data
)
2482 gtk_style_unref( m_widgetStyle
);
2484 m_widgetStyle
= (GtkStyle
*) NULL
;
2489 gtk_widget_destroy( m_wxwindow
);
2490 m_wxwindow
= (GtkWidget
*) NULL
;
2495 gtk_widget_destroy( m_widget
);
2496 m_widget
= (GtkWidget
*) NULL
;
2500 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2502 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2504 /* this turns -1 into 20 so that a minimal window is
2505 visible even although -1,-1 has been given as the
2506 size of the window. the same trick is used in other
2507 ports and should make debugging easier */
2508 m_width
= WidthDefault(size
.x
);
2509 m_height
= HeightDefault(size
.y
);
2514 /* some reasonable defaults */
2519 m_x
= (gdk_screen_width () - m_width
) / 2;
2520 if (m_x
< 10) m_x
= 10;
2524 m_y
= (gdk_screen_height () - m_height
) / 2;
2525 if (m_y
< 10) m_y
= 10;
2532 void wxWindowGTK::PostCreation()
2534 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2540 // these get reported to wxWindows -> wxPaintEvent
2542 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2544 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2545 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2548 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2549 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2551 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2553 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2554 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2557 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow
), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE
) );
2561 // these are called when the "sunken" or "raised" borders are drawn
2562 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2563 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2566 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2567 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2573 if (m_focusWidget
== NULL
)
2574 m_focusWidget
= m_widget
;
2576 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2577 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2579 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2580 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2582 // connect to the various key and mouse handlers
2584 GtkWidget
*connect_widget
= GetConnectWidget();
2586 ConnectWidget( connect_widget
);
2588 /* We cannot set colours, fonts and cursors before the widget has
2589 been realized, so we do this directly after realization */
2590 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2591 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2595 // Catch native resize events
2596 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2597 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2599 // Initialize XIM support
2600 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2601 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2603 // And resize XIM window
2604 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2605 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2608 if (!GTK_IS_COMBO(m_widget
))
2610 // This is needed if we want to add our windows into native
2611 // GTK control, such as the toolbar. With this callback, the
2612 // toolbar gets to know the correct size (the one set by the
2613 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2614 // when moving to GTK 2.0.
2615 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2616 GTK_SIGNAL_FUNC(gtk_window_size_request_callback
), (gpointer
) this );
2622 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2624 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2625 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2627 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2628 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2630 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2631 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2633 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2634 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2636 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2637 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2639 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2640 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2642 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2643 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2646 bool wxWindowGTK::Destroy()
2648 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2652 return wxWindowBase::Destroy();
2655 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2657 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2660 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2662 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2663 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2666 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2669 if (m_resizing
) return; /* I don't like recursions */
2672 int currentX
, currentY
;
2673 GetPosition(¤tX
, ¤tY
);
2678 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2680 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2682 /* don't set the size for children of wxNotebook, just take the values. */
2690 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2691 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2693 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2694 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2695 if (width
!= -1) m_width
= width
;
2696 if (height
!= -1) m_height
= height
;
2700 m_x
= x
+ pizza
->xoffset
;
2701 m_y
= y
+ pizza
->yoffset
;
2706 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2708 if (width
== -1) m_width
= 80;
2711 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2713 if (height
== -1) m_height
= 26;
2716 int minWidth
= GetMinWidth(),
2717 minHeight
= GetMinHeight(),
2718 maxWidth
= GetMaxWidth(),
2719 maxHeight
= GetMaxHeight();
2721 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2722 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2723 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2724 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2727 int bottom_border
= 0;
2730 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2732 /* the default button has a border around it */
2738 DoMoveWindow( m_x
-border
,
2741 m_height
+border
+bottom_border
);
2746 /* Sometimes the client area changes size without the
2747 whole windows's size changing, but if the whole
2748 windows's size doesn't change, no wxSizeEvent will
2749 normally be sent. Here we add an extra test if
2750 the client test has been changed and this will
2752 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2756 wxPrintf( "OnSize sent from " );
2757 if (GetClassInfo() && GetClassInfo()->GetClassName())
2758 wxPrintf( GetClassInfo()->GetClassName() );
2759 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2762 if (!m_nativeSizeEvent
)
2764 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2765 event
.SetEventObject( this );
2766 GetEventHandler()->ProcessEvent( event
);
2772 void wxWindowGTK::OnInternalIdle()
2774 // Update invalidated regions.
2777 // Synthetize activate events.
2778 if ( g_sendActivateEvent
!= -1 )
2780 bool activate
= g_sendActivateEvent
!= 0;
2783 g_sendActivateEvent
= -1;
2785 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2788 if ( g_activeFrameLostFocus
)
2790 if ( g_activeFrame
)
2792 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2793 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2794 event
.SetEventObject(g_activeFrame
);
2795 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2796 g_activeFrame
= NULL
;
2798 g_activeFrameLostFocus
= FALSE
;
2801 wxCursor cursor
= m_cursor
;
2802 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2806 /* I now set the cursor anew in every OnInternalIdle call
2807 as setting the cursor in a parent window also effects the
2808 windows above so that checking for the current cursor is
2813 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
2815 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2817 if (!g_globalCursor
.Ok())
2818 cursor
= *wxSTANDARD_CURSOR
;
2820 window
= m_widget
->window
;
2821 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2822 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2828 GdkWindow
*window
= m_widget
->window
;
2829 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
2830 gdk_window_set_cursor( window
, cursor
.GetCursor() );
2838 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
2840 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2842 if (width
) (*width
) = m_width
;
2843 if (height
) (*height
) = m_height
;
2846 void wxWindowGTK::DoSetClientSize( int width
, int height
)
2848 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2852 SetSize( width
, height
);
2859 #ifndef __WXUNIVERSAL__
2860 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2862 /* when using GTK 1.2 we set the shadow border size to 2 */
2866 if (HasFlag(wxSIMPLE_BORDER
))
2868 /* when using GTK 1.2 we set the simple border size to 1 */
2872 #endif // __WXUNIVERSAL__
2876 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2878 GtkRequisition vscroll_req
;
2879 vscroll_req
.width
= 2;
2880 vscroll_req
.height
= 2;
2881 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2882 (scroll_window
->vscrollbar
, &vscroll_req
);
2884 GtkRequisition hscroll_req
;
2885 hscroll_req
.width
= 2;
2886 hscroll_req
.height
= 2;
2887 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2888 (scroll_window
->hscrollbar
, &hscroll_req
);
2890 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2892 if (scroll_window
->vscrollbar_visible
)
2894 dw
+= vscroll_req
.width
;
2895 dw
+= scroll_class
->scrollbar_spacing
;
2898 if (scroll_window
->hscrollbar_visible
)
2900 dh
+= hscroll_req
.height
;
2901 dh
+= scroll_class
->scrollbar_spacing
;
2905 SetSize( width
+dw
, height
+dh
);
2909 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
2911 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2915 if (width
) (*width
) = m_width
;
2916 if (height
) (*height
) = m_height
;
2923 #ifndef __WXUNIVERSAL__
2924 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
2926 /* when using GTK 1.2 we set the shadow border size to 2 */
2930 if (HasFlag(wxSIMPLE_BORDER
))
2932 /* when using GTK 1.2 we set the simple border size to 1 */
2936 #endif // __WXUNIVERSAL__
2940 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
2942 GtkRequisition vscroll_req
;
2943 vscroll_req
.width
= 2;
2944 vscroll_req
.height
= 2;
2945 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
2946 (scroll_window
->vscrollbar
, &vscroll_req
);
2948 GtkRequisition hscroll_req
;
2949 hscroll_req
.width
= 2;
2950 hscroll_req
.height
= 2;
2951 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
2952 (scroll_window
->hscrollbar
, &hscroll_req
);
2954 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2956 if (scroll_window
->vscrollbar_visible
)
2958 dw
+= vscroll_req
.width
;
2959 dw
+= scroll_class
->scrollbar_spacing
;
2962 if (scroll_window
->hscrollbar_visible
)
2964 dh
+= hscroll_req
.height
;
2965 dh
+= scroll_class
->scrollbar_spacing
;
2969 if (width
) (*width
) = m_width
- dw
;
2970 if (height
) (*height
) = m_height
- dh
;
2974 printf( "GetClientSize, name %s ", GetName().c_str() );
2975 if (width) printf( " width = %d", (*width) );
2976 if (height) printf( " height = %d", (*height) );
2981 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
2983 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
2987 if (m_parent
&& m_parent
->m_wxwindow
)
2989 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2990 dx
= pizza
->xoffset
;
2991 dy
= pizza
->yoffset
;
2994 if (x
) (*x
) = m_x
- dx
;
2995 if (y
) (*y
) = m_y
- dy
;
2998 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3000 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3002 if (!m_widget
->window
) return;
3004 GdkWindow
*source
= (GdkWindow
*) NULL
;
3006 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3008 source
= m_widget
->window
;
3012 gdk_window_get_origin( source
, &org_x
, &org_y
);
3016 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3018 org_x
+= m_widget
->allocation
.x
;
3019 org_y
+= m_widget
->allocation
.y
;
3027 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3029 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3031 if (!m_widget
->window
) return;
3033 GdkWindow
*source
= (GdkWindow
*) NULL
;
3035 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3037 source
= m_widget
->window
;
3041 gdk_window_get_origin( source
, &org_x
, &org_y
);
3045 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3047 org_x
+= m_widget
->allocation
.x
;
3048 org_y
+= m_widget
->allocation
.y
;
3056 bool wxWindowGTK::Show( bool show
)
3058 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3060 if (!wxWindowBase::Show(show
))
3067 gtk_widget_show( m_widget
);
3069 gtk_widget_hide( m_widget
);
3074 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3076 win
->OnParentEnable(enable
);
3078 // Recurse, so that children have the opportunity to Do The Right Thing
3079 // and reset colours that have been messed up by a parent's (really ancestor's)
3081 for ( wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
3083 node
= node
->GetNext() )
3085 wxWindow
*child
= node
->GetData();
3086 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3087 wxWindowNotifyEnable(child
, enable
);
3091 bool wxWindowGTK::Enable( bool enable
)
3093 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3095 if (!wxWindowBase::Enable(enable
))
3101 gtk_widget_set_sensitive( m_widget
, enable
);
3103 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3105 wxWindowNotifyEnable(this, enable
);
3110 int wxWindowGTK::GetCharHeight() const
3112 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3114 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3116 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3118 return font
->ascent
+ font
->descent
;
3121 int wxWindowGTK::GetCharWidth() const
3123 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3125 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3127 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3129 return gdk_string_width( font
, "H" );
3132 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3136 int *externalLeading
,
3137 const wxFont
*theFont
) const
3139 wxFont fontToUse
= m_font
;
3140 if (theFont
) fontToUse
= *theFont
;
3142 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3144 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3145 if (x
) (*x
) = gdk_string_width( font
, string
.mbc_str() );
3146 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3147 if (descent
) (*descent
) = font
->descent
;
3148 if (externalLeading
) (*externalLeading
) = 0; // ??
3151 void wxWindowGTK::SetFocus()
3153 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3156 wxPrintf( "SetFocus from " );
3157 if (GetClassInfo() && GetClassInfo()->GetClassName())
3158 wxPrintf( GetClassInfo()->GetClassName() );
3164 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3166 gtk_widget_grab_focus (m_wxwindow
);
3171 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3173 gtk_widget_grab_focus (m_widget
);
3175 else if (GTK_IS_CONTAINER(m_widget
))
3177 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3186 bool wxWindowGTK::AcceptsFocus() const
3188 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3191 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3193 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3195 wxWindowGTK
*oldParent
= m_parent
,
3196 *newParent
= (wxWindowGTK
*)newParentBase
;
3198 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3200 if ( !wxWindowBase::Reparent(newParent
) )
3203 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3205 /* prevent GTK from deleting the widget arbitrarily */
3206 gtk_widget_ref( m_widget
);
3210 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3213 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3217 /* insert GTK representation */
3218 (*(newParent
->m_insertCallback
))(newParent
, this);
3221 /* reverse: prevent GTK from deleting the widget arbitrarily */
3222 gtk_widget_unref( m_widget
);
3227 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3229 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3231 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3233 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3238 /* insert GTK representation */
3239 (*m_insertCallback
)(this, child
);
3242 void wxWindowGTK::Raise()
3244 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3246 if (!m_widget
->window
) return;
3248 gdk_window_raise( m_widget
->window
);
3251 void wxWindowGTK::Lower()
3253 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3255 if (!m_widget
->window
) return;
3257 gdk_window_lower( m_widget
->window
);
3260 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3262 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3264 if (cursor
== m_cursor
)
3268 wxapp_install_idle_handler();
3270 if (cursor
== wxNullCursor
)
3271 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3273 return wxWindowBase::SetCursor( cursor
);
3276 void wxWindowGTK::WarpPointer( int x
, int y
)
3278 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3280 // We provide this function ourselves as it is
3281 // missing in GDK (top of this file).
3283 GdkWindow
*window
= (GdkWindow
*) NULL
;
3285 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3287 window
= GetConnectWidget()->window
;
3290 gdk_window_warp_pointer( window
, x
, y
);
3293 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3295 if (!m_widget
) return;
3296 if (!m_widget
->window
) return;
3299 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3303 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3304 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3308 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3309 m_clearRegion
.Clear();
3310 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3318 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3319 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3323 GdkRectangle gdk_rect
;
3324 gdk_rect
.x
= rect
->x
;
3325 gdk_rect
.y
= rect
->y
;
3326 gdk_rect
.width
= rect
->width
;
3327 gdk_rect
.height
= rect
->height
;
3328 gtk_widget_draw( m_widget
, &gdk_rect
);
3335 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3336 m_updateRegion
.Clear();
3337 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3341 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3349 GdkRectangle gdk_rect
;
3350 gdk_rect
.x
= rect
->x
;
3351 gdk_rect
.y
= rect
->y
;
3352 gdk_rect
.width
= rect
->width
;
3353 gdk_rect
.height
= rect
->height
;
3354 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3358 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3364 void wxWindowGTK::Update()
3367 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3368 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3371 if (!m_updateRegion
.IsEmpty())
3372 GtkSendPaintEvents();
3375 void wxWindowGTK::GtkSendPaintEvents()
3379 m_clearRegion
.Clear();
3380 m_updateRegion
.Clear();
3384 m_clipPaintRegion
= TRUE
;
3386 // if (!m_clearRegion.IsEmpty()) // always send an erase event
3388 wxWindowDC
dc( (wxWindow
*)this );
3389 dc
.SetClippingRegion( m_clearRegion
);
3391 wxEraseEvent
erase_event( GetId(), &dc
);
3392 erase_event
.SetEventObject( this );
3394 if (!GetEventHandler()->ProcessEvent(erase_event
))
3396 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3398 wxRegionIterator
upd( m_clearRegion
);
3401 gdk_draw_rectangle( GTK_PIZZA(m_wxwindow
)->bin_window
, g_eraseGC
, 0,
3402 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3406 m_clearRegion
.Clear();
3409 wxNcPaintEvent
nc_paint_event( GetId() );
3410 nc_paint_event
.SetEventObject( this );
3411 GetEventHandler()->ProcessEvent( nc_paint_event
);
3413 wxPaintEvent
paint_event( GetId() );
3414 paint_event
.SetEventObject( this );
3415 GetEventHandler()->ProcessEvent( paint_event
);
3417 m_clipPaintRegion
= FALSE
;
3419 #ifndef __WXUNIVERSAL__
3421 // The following code will result in all window-less widgets
3422 // being redrawn because the wxWindows class is allowed to
3423 // paint over the window-less widgets.
3425 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
3427 GList
*children
= pizza
->children
;
3430 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3431 children
= children
->next
;
3433 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3434 GTK_WIDGET_DRAWABLE (child
->widget
))
3436 // Get intersection of widget area and update region
3437 wxRegion
region( m_updateRegion
);
3439 GdkEventExpose gdk_event
;
3440 gdk_event
.type
= GDK_EXPOSE
;
3441 gdk_event
.window
= pizza
->bin_window
;
3442 gdk_event
.count
= 0;
3444 wxRegionIterator
upd( m_updateRegion
);
3448 rect
.x
= upd
.GetX();
3449 rect
.y
= upd
.GetY();
3450 rect
.width
= upd
.GetWidth();
3451 rect
.height
= upd
.GetHeight();
3453 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3455 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3465 m_updateRegion
.Clear();
3468 void wxWindowGTK::Clear()
3470 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3472 if (!m_widget
->window
) return;
3474 if (m_wxwindow
&& m_wxwindow
->window
)
3476 // gdk_window_clear( m_wxwindow->window );
3481 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3483 wxWindowBase::DoSetToolTip(tip
);
3486 m_tooltip
->Apply( (wxWindow
*)this );
3489 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3491 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3493 #endif // wxUSE_TOOLTIPS
3495 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3497 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3499 if (!wxWindowBase::SetBackgroundColour(colour
))
3501 // don't leave if the GTK widget has just
3503 if (!m_delayedBackgroundColour
) return FALSE
;
3506 GdkWindow
*window
= (GdkWindow
*) NULL
;
3508 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3510 window
= GetConnectWidget()->window
;
3514 // indicate that a new style has been set
3515 // but it couldn't get applied as the
3516 // widget hasn't been realized yet.
3517 m_delayedBackgroundColour
= TRUE
;
3521 (m_wxwindow
->window
) &&
3522 (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
)))
3524 /* wxMSW doesn't clear the window here. I don't do that either to
3525 provide compatibility. call Clear() to do the job. */
3527 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3528 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3536 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3538 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3540 if (!wxWindowBase::SetForegroundColour(colour
))
3542 // don't leave if the GTK widget has just
3544 if (!m_delayedForegroundColour
) return FALSE
;
3547 GdkWindow
*window
= (GdkWindow
*) NULL
;
3549 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3551 window
= GetConnectWidget()->window
;
3555 // indicate that a new style has been set
3556 // but it couldn't get applied as the
3557 // widget hasn't been realized yet.
3558 m_delayedForegroundColour
= TRUE
;
3566 GtkStyle
*wxWindowGTK::GetWidgetStyle()
3570 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
3572 // FIXME: no more klass in 2.0
3574 remake
->klass
= m_widgetStyle
->klass
;
3577 gtk_style_unref( m_widgetStyle
);
3578 m_widgetStyle
= remake
;
3582 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3585 def
= gtk_widget_get_default_style();
3587 m_widgetStyle
= gtk_style_copy( def
);
3589 // FIXME: no more klass in 2.0
3591 m_widgetStyle
->klass
= def
->klass
;
3595 return m_widgetStyle
;
3598 void wxWindowGTK::SetWidgetStyle()
3600 #if DISABLE_STYLE_IF_BROKEN_THEME
3601 if (m_widget
->style
->engine_data
)
3603 static bool s_warningPrinted
= FALSE
;
3604 if (!s_warningPrinted
)
3606 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3607 s_warningPrinted
= TRUE
;
3609 m_widgetStyle
= m_widget
->style
;
3614 GtkStyle
*style
= GetWidgetStyle();
3616 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
3618 SET_STYLE_FONT(style
, m_font
.GetInternalFont( 1.0 ));
3621 if (m_foregroundColour
.Ok())
3623 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3624 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
3626 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
3627 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
3628 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
3632 // Try to restore the gtk default style. This is still a little
3633 // oversimplified for what is probably really needed here for controls
3634 // other than buttons, but is better than not being able to (re)set a
3635 // control's foreground colour to *wxBLACK -- RL
3636 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3639 def
= gtk_widget_get_default_style();
3641 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
3642 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
3643 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
3647 if (m_backgroundColour
.Ok())
3649 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
3650 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
3652 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3653 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
3654 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3655 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
3656 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3657 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
3658 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3659 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
3663 // Try to restore the gtk default style. This is still a little
3664 // oversimplified for what is probably really needed here for controls
3665 // other than buttons, but is better than not being able to (re)set a
3666 // control's background colour to default grey and means resetting a
3667 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3669 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
3672 def
= gtk_widget_get_default_style();
3674 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
3675 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
3676 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
3677 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
3678 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
3679 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
3680 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
3681 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
3686 void wxWindowGTK::ApplyWidgetStyle()
3690 //-----------------------------------------------------------------------------
3691 // Pop-up menu stuff
3692 //-----------------------------------------------------------------------------
3694 #if wxUSE_MENUS_NATIVE
3697 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
3699 *is_waiting
= FALSE
;
3702 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
3704 menu
->SetInvokingWindow( win
);
3705 wxMenuItemList::Node
*node
= menu
->GetMenuItems().GetFirst();
3708 wxMenuItem
*menuitem
= node
->GetData();
3709 if (menuitem
->IsSubMenu())
3711 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
3714 node
= node
->GetNext();
3718 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3719 // wxPopupMenuPositionCallback()
3721 // should be safe even in the MT case as the user can hardly popup 2 menus
3722 // simultaneously, can he?
3723 static gint gs_pop_x
= 0;
3724 static gint gs_pop_y
= 0;
3726 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
3729 gboolean
* WXUNUSED(whatever
),
3731 gpointer
WXUNUSED(user_data
) )
3733 // ensure that the menu appears entirely on screen
3735 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
3737 wxSize sizeScreen
= wxGetDisplaySize();
3739 gint xmax
= sizeScreen
.x
- req
.width
,
3740 ymax
= sizeScreen
.y
- req
.height
;
3742 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
3743 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
3746 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
3748 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3750 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
3752 SetInvokingWindow( menu
, this );
3758 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
3760 bool is_waiting
= TRUE
;
3762 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
3764 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
3765 (gpointer
)&is_waiting
);
3768 GTK_MENU(menu
->m_menu
),
3769 (GtkWidget
*) NULL
, // parent menu shell
3770 (GtkWidget
*) NULL
, // parent menu item
3771 wxPopupMenuPositionCallback
, // function to position it
3772 NULL
, // client data
3773 0, // button used to activate it
3774 gs_timeLastClick
// the time of activation
3779 while (gtk_events_pending())
3780 gtk_main_iteration();
3786 #endif // wxUSE_MENUS_NATIVE
3788 #if wxUSE_DRAG_AND_DROP
3790 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
3792 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3794 GtkWidget
*dnd_widget
= GetConnectWidget();
3796 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
3798 if (m_dropTarget
) delete m_dropTarget
;
3799 m_dropTarget
= dropTarget
;
3801 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
3804 #endif // wxUSE_DRAG_AND_DROP
3806 GtkWidget
* wxWindowGTK::GetConnectWidget()
3808 GtkWidget
*connect_widget
= m_widget
;
3809 if (m_wxwindow
) connect_widget
= m_wxwindow
;
3811 return connect_widget
;
3814 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
3817 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
3819 return (window
== m_widget
->window
);
3822 bool wxWindowGTK::SetFont( const wxFont
&font
)
3824 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3826 if (!wxWindowBase::SetFont(font
))
3831 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
3832 if ( sysbg
== m_backgroundColour
)
3834 m_backgroundColour
= wxNullColour
;
3836 m_backgroundColour
= sysbg
;
3846 void wxWindowGTK::DoCaptureMouse()
3848 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3850 GdkWindow
*window
= (GdkWindow
*) NULL
;
3852 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3854 window
= GetConnectWidget()->window
;
3856 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
3858 wxCursor
* cursor
= & m_cursor
;
3860 cursor
= wxSTANDARD_CURSOR
;
3862 gdk_pointer_grab( window
, FALSE
,
3864 (GDK_BUTTON_PRESS_MASK
|
3865 GDK_BUTTON_RELEASE_MASK
|
3866 GDK_POINTER_MOTION_HINT_MASK
|
3867 GDK_POINTER_MOTION_MASK
),
3869 cursor
->GetCursor(),
3870 (guint32
)GDK_CURRENT_TIME
);
3871 g_captureWindow
= this;
3872 g_captureWindowHasMouse
= TRUE
;
3875 void wxWindowGTK::DoReleaseMouse()
3877 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3879 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
3881 g_captureWindow
= (wxWindowGTK
*) NULL
;
3883 GdkWindow
*window
= (GdkWindow
*) NULL
;
3885 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3887 window
= GetConnectWidget()->window
;
3892 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
3896 wxWindow
*wxWindowBase::GetCapture()
3898 return (wxWindow
*)g_captureWindow
;
3901 bool wxWindowGTK::IsRetained() const
3906 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
3907 int range
, bool refresh
)
3909 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3911 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3913 m_hasScrolling
= TRUE
;
3915 if (orient
== wxHORIZONTAL
)
3917 float fpos
= (float)pos
;
3918 float frange
= (float)range
;
3919 float fthumb
= (float)thumbVisible
;
3920 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3921 if (fpos
< 0.0) fpos
= 0.0;
3923 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
3924 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
3926 SetScrollPos( orient
, pos
, refresh
);
3930 m_oldHorizontalPos
= fpos
;
3932 m_hAdjust
->lower
= 0.0;
3933 m_hAdjust
->upper
= frange
;
3934 m_hAdjust
->value
= fpos
;
3935 m_hAdjust
->step_increment
= 1.0;
3936 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3937 m_hAdjust
->page_size
= fthumb
;
3941 float fpos
= (float)pos
;
3942 float frange
= (float)range
;
3943 float fthumb
= (float)thumbVisible
;
3944 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
3945 if (fpos
< 0.0) fpos
= 0.0;
3947 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
3948 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
3950 SetScrollPos( orient
, pos
, refresh
);
3954 m_oldVerticalPos
= fpos
;
3956 m_vAdjust
->lower
= 0.0;
3957 m_vAdjust
->upper
= frange
;
3958 m_vAdjust
->value
= fpos
;
3959 m_vAdjust
->step_increment
= 1.0;
3960 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
3961 m_vAdjust
->page_size
= fthumb
;
3964 if (orient
== wxHORIZONTAL
)
3965 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
3967 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
3970 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
3972 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3974 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
3976 if (orient
== wxHORIZONTAL
)
3978 float fpos
= (float)pos
;
3979 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
3980 if (fpos
< 0.0) fpos
= 0.0;
3981 m_oldHorizontalPos
= fpos
;
3983 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
3984 m_hAdjust
->value
= fpos
;
3988 float fpos
= (float)pos
;
3989 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
3990 if (fpos
< 0.0) fpos
= 0.0;
3991 m_oldVerticalPos
= fpos
;
3993 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
3994 m_vAdjust
->value
= fpos
;
3997 if (m_wxwindow
->window
)
3999 if (orient
== wxHORIZONTAL
)
4001 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4002 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4004 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4006 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4007 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4011 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4012 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4014 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4016 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4017 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4022 int wxWindowGTK::GetScrollThumb( int orient
) const
4024 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4026 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4028 if (orient
== wxHORIZONTAL
)
4029 return (int)(m_hAdjust
->page_size
+0.5);
4031 return (int)(m_vAdjust
->page_size
+0.5);
4034 int wxWindowGTK::GetScrollPos( int orient
) const
4036 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4038 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4040 if (orient
== wxHORIZONTAL
)
4041 return (int)(m_hAdjust
->value
+0.5);
4043 return (int)(m_vAdjust
->value
+0.5);
4046 int wxWindowGTK::GetScrollRange( int orient
) const
4048 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4050 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4052 if (orient
== wxHORIZONTAL
)
4053 return (int)(m_hAdjust
->upper
+0.5);
4055 return (int)(m_vAdjust
->upper
+0.5);
4058 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4060 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4062 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4064 // No scrolling requested.
4065 if ((dx
== 0) && (dy
== 0)) return;
4068 if (!m_updateRegion
.IsEmpty())
4070 m_updateRegion
.Offset( dx
, dy
);
4074 GetClientSize( &cw
, &ch
);
4075 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4078 if (!m_clearRegion
.IsEmpty())
4080 m_clearRegion
.Offset( dx
, dy
);
4084 GetClientSize( &cw
, &ch
);
4085 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4088 m_clipPaintRegion
= TRUE
;
4090 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4092 m_clipPaintRegion
= FALSE
;
4095 gdk_window_scroll( GTK_PIZZA(m_wxwindow
)->bin_window
, dx
, dy
);
4097 GTK_PIZZA(m_wxwindow
)->xoffset
+= dx
;
4098 GTK_PIZZA(m_wxwindow
)->yoffset
+= dy
;
4105 // Find the wxWindow at the current mouse position, also returning the mouse
4107 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4109 pt
= wxGetMousePosition();
4110 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4114 // Get the current mouse position.
4115 wxPoint
wxGetMousePosition()
4117 /* This crashes when used within wxHelpContext,
4118 so we have to use the X-specific implementation below.
4120 GdkModifierType *mask;
4121 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4123 return wxPoint(x, y);
4127 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4129 return wxPoint(-999, -999);
4131 Display
*display
= GDK_WINDOW_XDISPLAY(windowAtPtr
);
4132 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4133 Window rootReturn
, childReturn
;
4134 int rootX
, rootY
, winX
, winY
;
4135 unsigned int maskReturn
;
4137 XQueryPointer (display
,
4141 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4142 return wxPoint(rootX
, rootY
);
4146 // ----------------------------------------------------------------------------
4148 // ----------------------------------------------------------------------------
4150 class wxWinModule
: public wxModule
4157 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4160 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4162 bool wxWinModule::OnInit()
4164 g_eraseGC
= gdk_gc_new( GDK_ROOT_PARENT() );
4165 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4170 void wxWinModule::OnExit()
4172 gdk_gc_unref( g_eraseGC
);